]> Pileus Git - ~andy/gtk/blob - gtk/gtkclipboard.c
declare parent_class static
[~andy/gtk] / gtk / gtkclipboard.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2000 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Global clipboard abstraction. 
20  */
21
22 #include <string.h>
23
24 #include "gtkclipboard.h"
25 #include "gtkinvisible.h"
26 #include "gtkmain.h"
27 #include "gtksignal.h"
28
29 #ifdef GDK_WINDOWING_X11
30 #include "x11/gdkx.h"
31 #endif
32
33 #ifdef GDK_WINDOWING_WIN32
34 #include "win32/gdkwin32.h"
35 #endif
36
37 typedef struct _GtkClipboardClass GtkClipboardClass;
38
39 typedef struct _RequestContentsInfo RequestContentsInfo;
40 typedef struct _RequestTextInfo RequestTextInfo;
41
42 struct _GtkClipboard 
43 {
44   GObject parent_instance;
45
46   GdkAtom selection;
47
48   GtkClipboardGetFunc get_func;
49   GtkClipboardClearFunc clear_func;
50   gpointer user_data;
51   gboolean have_owner;
52
53   guint32 timestamp;
54
55   gboolean have_selection;
56   GdkDisplay *display;
57 };
58
59 struct _GtkClipboardClass
60 {
61   GObjectClass parent_class;
62 };
63
64 struct _RequestContentsInfo
65 {
66   GtkClipboardReceivedFunc callback;
67   gpointer user_data;
68 };
69
70 struct _RequestTextInfo
71 {
72   GtkClipboardTextReceivedFunc callback;
73   gpointer user_data;
74 };
75
76 static void gtk_clipboard_class_init (GtkClipboardClass *class);
77 static void gtk_clipboard_finalize   (GObject           *object);
78
79 static void clipboard_unset    (GtkClipboard     *clipboard);
80 static void selection_received (GtkWidget        *widget,
81                                 GtkSelectionData *selection_data,
82                                 guint             time);
83
84 enum {
85   TARGET_STRING,
86   TARGET_TEXT,
87   TARGET_COMPOUND_TEXT,
88   TARGET_UTF8_STRING
89 };
90
91 static const gchar *request_contents_key = "gtk-request-contents";
92 static GQuark request_contents_key_id = 0;
93
94 static const gchar *clipboards_owned_key = "gtk-clipboards-owned";
95 static GQuark clipboards_owned_key_id = 0;
96
97 static GObjectClass *parent_class;
98
99 GType
100 gtk_clipboard_get_type (void)
101 {
102   static GType clipboard_type = 0;
103   
104   if (!clipboard_type)
105     {
106       static const GTypeInfo clipboard_info =
107       {
108         sizeof (GtkClipboardClass),
109         NULL,           /* base_init */
110         NULL,           /* base_finalize */
111         (GClassInitFunc) gtk_clipboard_class_init,
112         NULL,           /* class_finalize */
113         NULL,           /* class_data */
114         sizeof (GtkClipboard),
115         0,              /* n_preallocs */
116         (GInstanceInitFunc) NULL,
117       };
118       
119       clipboard_type = g_type_register_static (G_TYPE_OBJECT, "GtkClipboard", &clipboard_info, 0);
120     }
121   
122   return clipboard_type;
123 }
124
125 static void
126 gtk_clipboard_class_init (GtkClipboardClass *class)
127 {
128   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
129
130   parent_class = g_type_class_peek_parent (class);
131   
132   gobject_class->finalize = gtk_clipboard_finalize;
133 }
134
135 static void
136 gtk_clipboard_finalize   (GObject *object)
137 {
138   clipboard_unset (GTK_CLIPBOARD (object));
139 }
140
141 static void
142 clipboard_display_closed (GdkDisplay   *display,
143                           gboolean      is_error,
144                           GtkClipboard *clipboard)
145 {
146   GSList *clipboards;
147
148   clipboards = g_object_get_data (G_OBJECT (display), "gtk-clipboard-list");
149   g_object_run_dispose (G_OBJECT (clipboard));
150   g_object_unref (clipboard);
151   clipboards = g_slist_remove (clipboards, clipboard);
152   
153   g_object_set_data (G_OBJECT (display), "gtk-clipboard-list", clipboards);
154 }
155
156 /**
157  * gtk_clipboard_get_for_display:
158  * @display: the display for which the clipboard is to be retrieved or created
159  * @selection: a #GdkAtom which identifies the clipboard
160  *             to use.
161  * 
162  * Returns the clipboard object for the given selection.
163  * Cut/copy/paste menu items and keyboard shortcuts should use
164  * the default clipboard, returned by passing %GDK_SELECTION_CLIPBOARD for @selection.
165  * (%GDK_NONE is supported as a synonym for GDK_SELECTION_CLIPBOARD
166  * for backwards compatibility reasons.)
167  * The currently-selected object or text should be provided on the clipboard
168  * identified by #GDK_SELECTION_PRIMARY. Cut/copy/paste menu items
169  * conceptually copy the contents of the #GDK_SELECTION_PRIMARY clipboard
170  * to the default clipboard, i.e. they copy the selection to what the
171  * user sees as the clipboard.
172  *
173  * (Passing #GDK_NONE is the same as using <literal>gdk_atom_intern
174  * ("CLIPBOARD", FALSE)</literal>. See
175  * <ulink url="http://www.freedesktop.org/standards/clipboards.txt">
176  * http://www.freedesktop.org/standards/clipboards.txt</ulink>
177  * for a detailed discussion of the "CLIPBOARD" vs. "PRIMARY" selections
178  * under the X window system. On Win32 the #GDK_SELECTION_PRIMARY
179  * clipboard is essentially ignored.)
180  *
181  * It's possible to have arbitrary named clipboards; if you do invent
182  * new clipboards, you should prefix the selection name with an
183  * underscore (because the ICCCM requires that nonstandard atoms are
184  * underscore-prefixed), and namespace it as well. For example,
185  * if your application called "Foo" has a special-purpose
186  * clipboard, you might call it "_FOO_SPECIAL_CLIPBOARD".
187  * 
188  * Return value: the appropriate clipboard object. If no
189  *             clipboard already exists, a new one will
190  *             be created. Once a clipboard object has
191  *             been created, it is persistent for all time and
192  *             cannot be freed.
193  **/
194 GtkClipboard *
195 gtk_clipboard_get_for_display (GdkDisplay *display, GdkAtom selection)
196 {
197   GtkClipboard *clipboard = NULL;
198   GSList *clipboards;
199   GSList *tmp_list;
200
201   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
202   g_return_val_if_fail (!display->closed, NULL);
203
204   if (selection == GDK_NONE)
205     selection = GDK_SELECTION_CLIPBOARD;
206
207   clipboards = g_object_get_data (G_OBJECT (display), "gtk-clipboard-list");
208
209   tmp_list = clipboards;
210   while (tmp_list)
211     {
212       clipboard = tmp_list->data;
213       if (clipboard->selection == selection)
214         break;
215
216       tmp_list = tmp_list->next;
217     }
218
219   if (!tmp_list)
220     {
221       clipboard = g_object_new (GTK_TYPE_CLIPBOARD, NULL);
222       clipboard->selection = selection;
223       clipboard->display = display;
224       clipboards = g_slist_prepend (clipboards, clipboard);
225       g_object_set_data (G_OBJECT (display), "gtk-clipboard-list", clipboards);
226       g_signal_connect (display, "closed",
227                         G_CALLBACK (clipboard_display_closed), clipboard);
228     }
229   
230   return clipboard;
231 }
232
233 /**
234  * gtk_clipboard_get():
235  * @selection: a #GdkAtom which identifies the clipboard
236  *             to use.
237  * 
238  * Returns the clipboard object for the given selection.
239  * See gtk_clipboard_get_for_display() for complete details.
240  * 
241  * Return value: the appropriate clipboard object. If no
242  *             clipboard already exists, a new one will
243  *             be created. Once a clipboard object has
244  *             been created, it is persistent for all time and
245  *             cannot be freed.
246  **/
247 GtkClipboard *
248 gtk_clipboard_get (GdkAtom selection)
249 {
250   return gtk_clipboard_get_for_display (gdk_display_get_default (), selection);
251 }
252
253 static void 
254 selection_get_cb (GtkWidget          *widget,
255                   GtkSelectionData   *selection_data,
256                   guint               info,
257                   guint               time)
258 {
259   GtkClipboard *clipboard = gtk_widget_get_clipboard (widget, selection_data->selection);
260
261   if (clipboard && clipboard->get_func)
262     clipboard->get_func (clipboard, selection_data, info, clipboard->user_data);
263 }
264
265 static gboolean
266 selection_clear_event_cb (GtkWidget         *widget,
267                           GdkEventSelection *event)
268 {
269   GtkClipboard *clipboard = gtk_widget_get_clipboard (widget, event->selection);
270
271   if (clipboard)
272     {
273       clipboard_unset (clipboard);
274       return TRUE;
275     }
276
277   return FALSE;
278 }
279
280 static GtkWidget *
281 make_clipboard_widget (GdkDisplay *display, 
282                        gboolean    provider)
283 {
284   GtkWidget *widget = gtk_invisible_new_for_screen (gdk_display_get_default_screen (display));
285
286   gtk_signal_connect (GTK_OBJECT (widget), "selection_received",
287                       GTK_SIGNAL_FUNC (selection_received), NULL);
288
289   if (provider)
290     {
291       /* We need this for gdk_x11_get_server_time() */
292       gtk_widget_add_events (widget, GDK_PROPERTY_CHANGE_MASK);
293       
294       gtk_signal_connect (GTK_OBJECT (widget), "selection_get",
295                           GTK_SIGNAL_FUNC (selection_get_cb), NULL);
296       gtk_signal_connect (GTK_OBJECT (widget), "selection_clear_event",
297                           GTK_SIGNAL_FUNC (selection_clear_event_cb), NULL);
298     }
299
300   return widget;
301 }
302
303 static GtkWidget *
304 get_clipboard_widget (GdkDisplay *display)
305 {
306   GtkWidget *clip_widget = g_object_get_data (G_OBJECT (display), "gtk-clipboard-widget");
307   if (!clip_widget)
308     {
309       clip_widget = make_clipboard_widget (display, TRUE);
310       g_object_set_data (G_OBJECT (display), "gtk-clipboard-widget", clip_widget);
311     }
312
313   return clip_widget;
314 }
315
316 /* This function makes a very good guess at what the correct
317  * timestamp for a selection request should be. If there is
318  * a currently processed event, it uses the timestamp for that
319  * event, otherwise it uses the current server time. However,
320  * if the time resulting from that is older than the time used
321  * last time, it uses the time used last time instead.
322  *
323  * In order implement this correctly, we never use CurrentTime,
324  * but actually retrieve the actual timestamp from the server.
325  * This is a little slower but allows us to make the guarantee
326  * that the times used by this application will always ascend
327  * and we won't get selections being rejected just because
328  * we are using a correct timestamp from an event, but used
329  * CurrentTime previously.
330  */
331 static guint32
332 clipboard_get_timestamp (GtkClipboard *clipboard)
333 {
334   GtkWidget *clipboard_widget = get_clipboard_widget (clipboard->display);
335   guint32 timestamp = gtk_get_current_event_time ();
336
337   if (timestamp == GDK_CURRENT_TIME)
338     {
339 #ifdef GDK_WINDOWING_X11
340       timestamp = gdk_x11_get_server_time (clipboard_widget->window);
341 #elif defined GDK_WINDOWING_WIN32
342       timestamp = GetMessageTime ();
343 #endif
344     }
345   else
346     {
347       if (clipboard->timestamp != GDK_CURRENT_TIME)
348         {
349           /* Check to see if clipboard->timestamp is newer than
350            * timestamp, accounting for wraparound.
351            */
352
353           guint32 max = timestamp + 0x80000000;
354
355           if ((max > timestamp &&
356                (clipboard->timestamp > timestamp &&
357                 clipboard->timestamp <= max)) ||
358               (max <= timestamp &&
359                (clipboard->timestamp > timestamp ||
360                 clipboard->timestamp <= max)))
361             {
362               timestamp = clipboard->timestamp;
363             }
364         }
365     }
366
367   clipboard->timestamp = timestamp;
368
369   return timestamp;
370 }
371
372 static void
373 clipboard_owner_destroyed (gpointer data)
374 {
375   GSList *clipboards = data;
376   GSList *tmp_list;
377
378   tmp_list = clipboards;
379   while (tmp_list)
380     {
381       GtkClipboard *clipboard = tmp_list->data;
382
383       clipboard->get_func = NULL;
384       clipboard->clear_func = NULL;
385       clipboard->user_data = NULL;
386       clipboard->have_owner = FALSE;
387
388       gtk_clipboard_clear (clipboard);
389
390       tmp_list = tmp_list->next;
391     }
392   
393   g_slist_free (clipboards);
394 }
395
396 static void
397 clipboard_add_owner_notify (GtkClipboard *clipboard)
398 {
399   if (!clipboards_owned_key_id)
400     clipboards_owned_key_id = g_quark_from_static_string (clipboards_owned_key);
401   
402   if (clipboard->have_owner)
403     g_object_set_qdata_full (clipboard->user_data, clipboards_owned_key_id,
404                              g_slist_prepend (g_object_steal_qdata (clipboard->user_data,
405                                                                     clipboards_owned_key_id),
406                                               clipboard),
407                              clipboard_owner_destroyed);
408 }
409
410 static void
411 clipboard_remove_owner_notify (GtkClipboard *clipboard)
412 {
413   if (clipboard->have_owner)
414      g_object_set_qdata_full (clipboard->user_data, clipboards_owned_key_id,
415                               g_slist_remove (g_object_steal_qdata (clipboard->user_data,
416                                                                     clipboards_owned_key_id),
417                                               clipboard),
418                               clipboard_owner_destroyed);
419 }
420           
421 static gboolean
422 gtk_clipboard_set_contents (GtkClipboard         *clipboard,
423                             const GtkTargetEntry *targets,
424                             guint                 n_targets,
425                             GtkClipboardGetFunc   get_func,
426                             GtkClipboardClearFunc clear_func,
427                             gpointer              user_data,
428                             gboolean              have_owner)
429 {
430   GtkWidget *clipboard_widget = get_clipboard_widget (clipboard->display);
431
432   if (gtk_selection_owner_set_for_display (clipboard->display,
433                                            clipboard_widget,
434                                            clipboard->selection,
435                                            clipboard_get_timestamp (clipboard)))
436     {
437       clipboard->have_selection = TRUE;
438
439       if (!(clipboard->have_owner && have_owner) ||
440           clipboard->user_data != user_data)
441         {
442           clipboard_unset (clipboard);
443
444           if (clipboard->get_func)
445             {
446               /* Calling unset() caused the clipboard contents to be reset!
447                * Avoid leaking and return 
448                */
449               if (!(clipboard->have_owner && have_owner) ||
450                   clipboard->user_data != user_data)
451                 {
452                   (*clear_func) (clipboard, user_data);
453                   return FALSE;
454                 }
455               else
456                 return TRUE;
457             }
458           else
459             {
460               clipboard->user_data = user_data;
461               clipboard->have_owner = have_owner;
462               if (have_owner)
463                 clipboard_add_owner_notify (clipboard);
464             }
465           
466         }
467
468       clipboard->get_func = get_func;
469       clipboard->clear_func = clear_func;
470
471       gtk_selection_clear_targets (clipboard_widget, clipboard->selection);
472       gtk_selection_add_targets (clipboard_widget, clipboard->selection,
473                                  targets, n_targets);
474
475       return TRUE;
476     }
477   else
478     return FALSE;
479 }
480
481 /**
482  * gtk_clipboard_set_with_data:
483  * @clipboard:  a #GtkClipboard
484  * @targets:    array containing information about the available forms for the
485  *              clipboard data
486  * @n_targets:  number of elements in @targets
487  * @get_func:   function to call to get the actual clipboard data
488  * @clear_func: when the clipboard contents are set again, this function will
489  *              be called, and @get_func will not be subsequently called.
490  * @user_data:  user data to pass to @get_func and @clear_func.
491  * 
492  * Virtually sets the contents of the specified clipboard by providing
493  * a list of supported formats for the clipboard data and a function
494  * to call to get the actual data when it is requested.
495  * 
496  * Return value: %TRUE if setting the clipboard data succeeded. If setting
497  *               the clipboard data failed the provided callback functions
498  *               will be ignored.
499  **/
500 gboolean
501 gtk_clipboard_set_with_data (GtkClipboard          *clipboard,
502                              const GtkTargetEntry  *targets,
503                              guint                  n_targets,
504                              GtkClipboardGetFunc    get_func,
505                              GtkClipboardClearFunc  clear_func,
506                              gpointer               user_data)
507 {
508   g_return_val_if_fail (clipboard != NULL, FALSE);
509   g_return_val_if_fail (targets != NULL, FALSE);
510   g_return_val_if_fail (get_func != NULL, FALSE);
511
512   return gtk_clipboard_set_contents (clipboard, targets, n_targets,
513                                      get_func, clear_func, user_data,
514                                      FALSE);
515 }
516
517 /**
518  * gtk_clipboard_set_with_owner:
519  * @clipboard:  a #GtkClipboard
520  * @targets:    array containing information about the available forms for the
521  *              clipboard data
522  * @n_targets:  number of elements in @targets
523  * @get_func:   function to call to get the actual clipboard data
524  * @clear_func: when the clipboard contents are set again, this function will
525  *              be called, and @get_func will not be subsequently called.
526  * @owner:      an object that "owns" the data. This object will be passed
527  *              to the callbacks when called. 
528  * 
529  * Virtually sets the contents of the specified clipboard by providing
530  * a list of supported formats for the clipboard data and a function
531  * to call to get the actual data when it is requested.
532  *
533  * The difference between this function and gtk_clipboard_set_with_data()
534  * is that instead of an generic @user_data pointer, a #GObject is passed
535  * in. 
536  * 
537  * Return value: %TRUE if setting the clipboard data succeeded. If setting
538  *               the clipboard data failed the provided callback functions
539  *               will be ignored.
540  **/
541 gboolean
542 gtk_clipboard_set_with_owner (GtkClipboard          *clipboard,
543                               const GtkTargetEntry  *targets,
544                               guint                  n_targets,
545                               GtkClipboardGetFunc    get_func,
546                               GtkClipboardClearFunc  clear_func,
547                               GObject               *owner)
548 {
549   g_return_val_if_fail (clipboard != NULL, FALSE);
550   g_return_val_if_fail (targets != NULL, FALSE);
551   g_return_val_if_fail (get_func != NULL, FALSE);
552   g_return_val_if_fail (G_IS_OBJECT (owner), FALSE);
553
554   return gtk_clipboard_set_contents (clipboard, targets, n_targets,
555                                      get_func, clear_func, owner,
556                                      TRUE);
557 }
558
559 /**
560  * gtk_clipboard_get_owner:
561  * @clipboard: a #GtkClipboard
562  * 
563  * If the clipboard contents callbacks were set with 
564  * gtk_clipboard_set_with_owner(), and the gtk_clipboard_set_with_data() or 
565  * gtk_clipboard_clear() has not subsequently called, returns the owner set 
566  * by gtk_clipboard_set_with_owner().
567  * 
568  * Return value: the owner of the clipboard, if any; otherwise %NULL.
569  **/
570 GObject *
571 gtk_clipboard_get_owner (GtkClipboard *clipboard)
572 {
573   g_return_val_if_fail (clipboard != NULL, NULL);
574
575   if (clipboard->have_owner)
576     return clipboard->user_data;
577   else
578     return NULL;
579 }
580
581 static void
582 clipboard_unset (GtkClipboard *clipboard)
583 {
584   GtkClipboardClearFunc old_clear_func;
585   gpointer old_data;
586   
587   old_clear_func = clipboard->clear_func;
588   old_data = clipboard->user_data;
589           
590   if (clipboard->have_owner)
591     {
592       clipboard_remove_owner_notify (clipboard);
593       clipboard->have_owner = FALSE;
594     }
595   
596   clipboard->get_func = NULL;
597   clipboard->clear_func = NULL;
598   clipboard->user_data = NULL;
599   
600   if (old_clear_func)
601     old_clear_func (clipboard, old_data);
602 }
603
604 /**
605  * gtk_clipboard_clear:
606  * @clipboard:  a #GtkClipboard
607  * 
608  * Clears the contents of the clipboard. Generally this should only
609  * be called between the time you call gtk_clipboard_set_with_owner()
610  * or gtk_clipboard_set_with_data(),
611  * and when the @clear_func you supplied is called. Otherwise, the
612  * clipboard may be owned by someone else.
613  **/
614 void
615 gtk_clipboard_clear (GtkClipboard *clipboard)
616 {
617   g_return_if_fail (clipboard != NULL);
618
619   if (clipboard->have_selection)
620     gtk_selection_owner_set_for_display (clipboard->display, 
621                                          NULL,
622                                          clipboard->selection,
623                                          clipboard_get_timestamp (clipboard));
624 }
625
626 static void 
627 text_get_func (GtkClipboard     *clipboard,
628                GtkSelectionData *selection_data,
629                guint             info,
630                gpointer          data)
631 {
632   gtk_selection_data_set_text (selection_data, data, -1);
633 }
634
635 static void 
636 text_clear_func (GtkClipboard *clipboard,
637                  gpointer      data)
638 {
639   g_free (data);
640 }
641
642 /**
643  * gtk_clipboard_set_text:
644  * @clipboard: a #GtkClipboard object
645  * @text:      a UTF-8 string.
646  * @len:       length of @text, in bytes, or -1, in which case
647  *             the length will be determined with <function>strlen()</function>.
648  * 
649  * Sets the contents of the clipboard to the given UTF-8 string. GTK+ will
650  * make a copy of the text and take responsibility for responding
651  * for requests for the text, and for converting the text into
652  * the requested format.
653  **/
654 void 
655 gtk_clipboard_set_text (GtkClipboard *clipboard,
656                         const gchar  *text,
657                         gint          len)
658 {
659   static const GtkTargetEntry targets[] = {
660     { "STRING", 0, TARGET_STRING },
661     { "TEXT",   0, TARGET_TEXT }, 
662     { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
663     { "UTF8_STRING", 0, TARGET_UTF8_STRING }
664   };
665
666   g_return_if_fail (clipboard != NULL);
667   g_return_if_fail (text != NULL);
668   
669   if (len < 0)
670     len = strlen (text);
671   
672   gtk_clipboard_set_with_data (clipboard, 
673                                targets, G_N_ELEMENTS (targets),
674                                text_get_func, text_clear_func,
675                                g_strndup (text, len));
676 }
677
678 static void
679 set_request_contents_info (GtkWidget           *widget,
680                            RequestContentsInfo *info)
681 {
682   if (!request_contents_key_id)
683     request_contents_key_id = g_quark_from_static_string (request_contents_key);
684
685   gtk_object_set_data_by_id (GTK_OBJECT (widget),
686                              request_contents_key_id,
687                              info);
688 }
689
690 static RequestContentsInfo *
691 get_request_contents_info (GtkWidget *widget)
692 {
693   if (!request_contents_key_id)
694     return NULL;
695   else
696     return gtk_object_get_data_by_id (GTK_OBJECT (widget),
697                                       request_contents_key_id);
698 }
699
700 static void 
701 selection_received (GtkWidget            *widget,
702                     GtkSelectionData     *selection_data,
703                     guint                 time)
704 {
705   RequestContentsInfo *request_info = get_request_contents_info (widget);
706   set_request_contents_info (widget, NULL);
707   
708   request_info->callback (gtk_widget_get_clipboard (widget, selection_data->selection), 
709                           selection_data,
710                           request_info->user_data);
711
712   g_free (request_info);
713
714   if (widget != get_clipboard_widget (gtk_widget_get_display (widget)))
715     gtk_widget_destroy (widget);
716 }
717
718 /**
719  * gtk_clipboard_request_contents:
720  * @clipboard: a #GtkClipboard
721  * @target:    an atom representing the form into which the clipboard
722  *             owner should convert the selection.
723  * @callback:  A function to call when the results are received
724  *             (or the retrieval fails). If the retrieval fails
725  *             the length field of @selection_data will be
726  *             negative.
727  * @user_data: user data to pass to @callback
728  * 
729  * Requests the contents of clipboard as the given target.
730  * When the results of the result are later received the supplied callback
731  * will be called.
732  **/
733 void 
734 gtk_clipboard_request_contents (GtkClipboard            *clipboard,
735                                 GdkAtom                  target,
736                                 GtkClipboardReceivedFunc callback,
737                                 gpointer                 user_data)
738 {
739   RequestContentsInfo *info;
740   GtkWidget *widget;
741   GtkWidget *clipboard_widget;
742
743   g_return_if_fail (clipboard != NULL);
744   g_return_if_fail (target != GDK_NONE);
745   g_return_if_fail (callback != NULL);
746   
747   clipboard_widget = get_clipboard_widget (clipboard->display);
748
749   if (get_request_contents_info (clipboard_widget))
750     widget = make_clipboard_widget (clipboard->display, FALSE);
751   else
752     widget = clipboard_widget;
753
754   info = g_new (RequestContentsInfo, 1);
755   info->callback = callback;
756   info->user_data = user_data;
757
758   set_request_contents_info (widget, info);
759
760   gtk_selection_convert (widget, clipboard->selection, target,
761                          clipboard_get_timestamp (clipboard));
762 }
763
764 static void 
765 request_text_received_func (GtkClipboard     *clipboard,
766                             GtkSelectionData *selection_data,
767                             gpointer          data)
768 {
769   RequestTextInfo *info = data;
770   gchar *result = NULL;
771
772   result = gtk_selection_data_get_text (selection_data);
773
774   if (!result)
775     {
776       /* If we asked for UTF8 and didn't get it, try compound_text;
777        * if we asked for compound_text and didn't get it, try string;
778        * If we asked for anything else and didn't get it, give up.
779        */
780       if (selection_data->target == gdk_atom_intern ("UTF8_STRING", FALSE))
781         {
782           gtk_clipboard_request_contents (clipboard,
783                                           gdk_atom_intern ("COMPOUND_TEXT", FALSE), 
784                                           request_text_received_func, info);
785           return;
786         }
787       else if (selection_data->target == gdk_atom_intern ("COMPOUND_TEXT", FALSE))
788         {
789           gtk_clipboard_request_contents (clipboard,
790                                           GDK_TARGET_STRING, 
791                                           request_text_received_func, info);
792           return;
793         }
794     }
795
796   info->callback (clipboard, result, info->user_data);
797   g_free (info);
798   g_free (result);
799 }
800
801 /**
802  * gtk_clipboard_request_text:
803  * @clipboard: a #GtkClipboard
804  * @callback:  a function to call when the text is received,
805  *             or the retrieval fails. (It will always be called
806  *             one way or the other.)
807  * @user_data: user data to pass to @callback.
808  * 
809  * Requests the contents of the clipboard as text. When the text is
810  * later received, it will be converted to UTF-8 if necessary, and
811  * @callback will be called. 
812  *
813  * The @text parameter to @callback will contain the resulting text if
814  * the request succeeded, or %NULL if it failed. This could happen for
815  * various reasons, in particular if the clipboard was empty or if the
816  * contents of the clipboard could not be converted into text form.
817  **/
818 void 
819 gtk_clipboard_request_text (GtkClipboard                *clipboard,
820                             GtkClipboardTextReceivedFunc callback,
821                             gpointer                     user_data)
822 {
823   RequestTextInfo *info;
824   
825   g_return_if_fail (clipboard != NULL);
826   g_return_if_fail (callback != NULL);
827   
828   info = g_new (RequestTextInfo, 1);
829   info->callback = callback;
830   info->user_data = user_data;
831
832   gtk_clipboard_request_contents (clipboard, gdk_atom_intern ("UTF8_STRING", FALSE),
833                                   request_text_received_func,
834                                   info);
835 }
836
837
838 typedef struct
839 {
840   GMainLoop *loop;
841   gpointer data;
842 } WaitResults;
843
844 static void 
845 clipboard_received_func (GtkClipboard     *clipboard,
846                          GtkSelectionData *selection_data,
847                          gpointer          data)
848 {
849   WaitResults *results = data;
850
851   if (selection_data->length >= 0)
852     results->data = gtk_selection_data_copy (selection_data);
853   
854   g_main_quit (results->loop);
855 }
856
857 /**
858  * gtk_clipboard_wait_for_contents:
859  * @clipboard: a #GtkClipboard
860  * @target: an atom representing the form into which the clipboard
861  *          owner should convert the selection.
862  * 
863  * Requests the contents of the clipboard using the given target.
864  * This function waits for the data to be received using the main 
865  * loop, so events, timeouts, etc, may be dispatched during the wait.
866  * 
867  * Return value: a newly-allocated #GtkSelectionData object or %NULL
868  *               if retrieving the given target failed. If non-%NULL,
869  *               this value must be freed with gtk_selection_data_free() 
870  *               when you are finished with it.
871  **/
872 GtkSelectionData *
873 gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
874                                  GdkAtom       target)
875 {
876   WaitResults results;
877
878   g_return_val_if_fail (clipboard != NULL, NULL);
879   g_return_val_if_fail (target != GDK_NONE, NULL);
880   
881   results.data = NULL;
882   results.loop = g_main_new (TRUE);
883
884   gtk_clipboard_request_contents (clipboard, target, 
885                                   clipboard_received_func,
886                                   &results);
887
888   if (g_main_is_running (results.loop))
889     {
890       GDK_THREADS_LEAVE ();
891       g_main_run (results.loop);
892       GDK_THREADS_ENTER ();
893     }
894
895   g_main_destroy (results.loop);
896
897   return results.data;
898 }
899
900 static void 
901 clipboard_text_received_func (GtkClipboard *clipboard,
902                               const gchar  *text,
903                               gpointer      data)
904 {
905   WaitResults *results = data;
906
907   results->data = g_strdup (text);
908   g_main_quit (results->loop);
909 }
910
911
912 /**
913  * gtk_clipboard_wait_for_text:
914  * @clipboard: a #GtkClipboard
915  * 
916  * Requests the contents of the clipboard as text and converts
917  * the result to UTF-8 if necessary. This function waits for
918  * the data to be received using the main loop, so events,
919  * timeouts, etc, may be dispatched during the wait.
920  * 
921  * Return value: a newly-allocated UTF-8 string which must
922  *               be freed with g_free(), or %NULL if retrieving
923  *               the selection data failed. (This could happen
924  *               for various reasons, in particular if the
925  *               clipboard was empty or if the contents of the
926  *               clipboard could not be converted into text form.)
927  **/
928 gchar *
929 gtk_clipboard_wait_for_text (GtkClipboard *clipboard)
930 {
931   WaitResults results;
932
933   g_return_val_if_fail (clipboard != NULL, NULL);
934   g_return_val_if_fail (clipboard != NULL, NULL);
935   
936   results.data = NULL;
937   results.loop = g_main_new (TRUE);
938
939   gtk_clipboard_request_text (clipboard,
940                               clipboard_text_received_func,
941                               &results);
942
943   if (g_main_is_running (results.loop))
944     {
945       GDK_THREADS_LEAVE ();
946       g_main_run (results.loop);
947       GDK_THREADS_ENTER ();
948     }
949
950   g_main_destroy (results.loop);
951
952   return results.data;
953 }
954 /**
955  * gtk_clipboard_get_display:
956  * @clipboard: a #GtkClipboard
957  *
958  * Gets the #GdkDisplay associated with @clipboard
959  *
960  * Return value: the #GdkDisplay associated with @clipboard
961  **/
962 GdkDisplay *
963 gtk_clipboard_get_display (GtkClipboard *clipboard)
964 {
965   g_return_val_if_fail (clipboard != NULL, NULL);
966
967   return clipboard->display;
968 }
969
970 /**
971  * gtk_clipboard_wait_is_text_available:
972  * @clipboard: a #GtkClipboard
973  * 
974  * Test to see if there is text available to be pasted
975  * This is done by requesting the TARGETS atom and checking
976  * if it contains any of the names: STRING, TEXT, COMPOUND_TEXT,
977  * UTF8_STRING. This function waits for the data to be received
978  * using the main loop, so events, timeouts, etc, may be dispatched
979  * during the wait.
980  *
981  * This function is a little faster than calling
982  * gtk_clipboard_wait_for_text() since it doesn't need to retrieve
983  * the actual text.
984  * 
985  * Return value: %TRUE is there is text available, %FALSE otherwise.
986  **/
987 gboolean
988 gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard)
989 {
990   GtkSelectionData *data;
991   gboolean result = FALSE;
992
993   data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern ("TARGETS", FALSE));
994   if (data)
995     {
996       result = gtk_selection_data_targets_include_text (data);
997       gtk_selection_data_free (data);
998     }
999
1000   return result;
1001 }