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