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