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