]> Pileus Git - ~andy/gtk/blob - gtk/gtkselection.c
Shrink the private structs of these a bit.
[~andy/gtk] / gtk / gtkselection.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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
20 /* This file implements most of the work of the ICCCM selection protocol.
21  * The code was written after an intensive study of the equivalent part
22  * of John Ousterhout's Tk toolkit, and does many things in much the 
23  * same way.
24  *
25  * The one thing in the ICCCM that isn't fully supported here (or in Tk)
26  * is side effects targets. For these to be handled properly, MULTIPLE
27  * targets need to be done in the order specified. This cannot be
28  * guaranteed with the way we do things, since if we are doing INCR
29  * transfers, the order will depend on the timing of the requestor.
30  *
31  * By Owen Taylor <owt1@cornell.edu>          8/16/97
32  */
33
34 /* Terminology note: when not otherwise specified, the term "incr" below
35  * refers to the _sending_ part of the INCR protocol. The receiving
36  * portion is referred to just as "retrieval". (Terminology borrowed
37  * from Tk, because there is no good opposite to "retrieval" in English.
38  * "send" can't be made into a noun gracefully and we're already using
39  * "emission" for something else ....)
40  */
41
42 /* The MOTIF entry widget seems to ask for the TARGETS target, then
43    (regardless of the reply) ask for the TEXT target. It's slightly
44    possible though that it somehow thinks we are responding negatively
45    to the TARGETS request, though I don't really think so ... */
46
47 /*
48  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
49  * file for a list of people on the GTK+ Team.  See the ChangeLog
50  * files for a list of changes.  These files are distributed with
51  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
52  */
53
54 #include <config.h>
55 #include <stdarg.h>
56 #include <string.h>
57 #include "gdk.h"
58
59 #include "gtkmain.h"
60 #include "gtkselection.h"
61 #include "gtkintl.h"
62 #include "gdk-pixbuf/gdk-pixbuf.h"
63
64 #ifdef GDK_WINDOWING_X11
65 #include "x11/gdkx.h"
66 #endif
67
68 #ifdef GDK_WINDOWING_WIN32
69 #include "win32/gdkwin32.h"
70 #endif
71
72 #include "gtkalias.h"
73
74 #undef DEBUG_SELECTION
75
76 /* Maximum size of a sent chunk, in bytes. Also the default size of
77    our buffers */
78 #ifdef GDK_WINDOWING_X11
79 #define GTK_SELECTION_MAX_SIZE(display)                                 \
80   MIN(262144,                                                           \
81       XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0     \
82        ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100         \
83        : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
84 #else
85 /* No chunks on Win32 */
86 #define GTK_SELECTION_MAX_SIZE(display) G_MAXINT
87 #endif
88
89 #define IDLE_ABORT_TIME 30
90
91 enum {
92   INCR,
93   MULTIPLE,
94   TARGETS,
95   TIMESTAMP,
96   LAST_ATOM
97 };
98
99 typedef struct _GtkSelectionInfo GtkSelectionInfo;
100 typedef struct _GtkIncrConversion GtkIncrConversion;
101 typedef struct _GtkIncrInfo GtkIncrInfo;
102 typedef struct _GtkRetrievalInfo GtkRetrievalInfo;
103
104 struct _GtkSelectionInfo
105 {
106   GdkAtom        selection;
107   GtkWidget     *widget;        /* widget that owns selection */
108   guint32        time;          /* time used to acquire selection */
109   GdkDisplay    *display;       /* needed in gtk_selection_remove_all */    
110 };
111
112 struct _GtkIncrConversion 
113 {
114   GdkAtom           target;     /* Requested target */
115   GdkAtom           property;   /* Property to store in */
116   GtkSelectionData  data;       /* The data being supplied */
117   gint              offset;     /* Current offset in sent selection.
118                                  *  -1 => All done
119                                  *  -2 => Only the final (empty) portion
120                                  *        left to send */
121 };
122
123 struct _GtkIncrInfo
124 {
125   GdkWindow *requestor;         /* Requestor window - we create a GdkWindow
126                                    so we can receive events */
127   GdkAtom    selection;         /* Selection we're sending */
128   
129   GtkIncrConversion *conversions; /* Information about requested conversions -
130                                    * With MULTIPLE requests (benighted 1980's
131                                    * hardware idea), there can be more than
132                                    * one */
133   gint num_conversions;
134   gint num_incrs;               /* number of remaining INCR style transactions */
135   guint32 idle_time;
136 };
137
138
139 struct _GtkRetrievalInfo
140 {
141   GtkWidget *widget;
142   GdkAtom selection;            /* Selection being retrieved. */
143   GdkAtom target;               /* Form of selection that we requested */
144   guint32 idle_time;            /* Number of seconds since we last heard
145                                    from selection owner */
146   guchar   *buffer;             /* Buffer in which to accumulate results */
147   gint     offset;              /* Current offset in buffer, -1 indicates
148                                    not yet started */
149   guint32 notify_time;          /* Timestamp from SelectionNotify */
150 };
151
152 /* Local Functions */
153 static void gtk_selection_init              (void);
154 static gint gtk_selection_incr_timeout      (GtkIncrInfo      *info);
155 static gint gtk_selection_retrieval_timeout (GtkRetrievalInfo *info);
156 static void gtk_selection_retrieval_report  (GtkRetrievalInfo *info,
157                                              GdkAtom           type,
158                                              gint              format,
159                                              guchar           *buffer,
160                                              gint              length,
161                                              guint32           time);
162 static void gtk_selection_invoke_handler    (GtkWidget        *widget,
163                                              GtkSelectionData *data,
164                                              guint             time);
165 static void gtk_selection_default_handler   (GtkWidget        *widget,
166                                              GtkSelectionData *data);
167 static int  gtk_selection_bytes_per_item    (gint              format);
168
169 /* Local Data */
170 static gint initialize = TRUE;
171 static GList *current_retrievals = NULL;
172 static GList *current_incrs = NULL;
173 static GList *current_selections = NULL;
174
175 static GdkAtom gtk_selection_atoms[LAST_ATOM];
176 static const char gtk_selection_handler_key[] = "gtk-selection-handlers";
177
178 /****************
179  * Target Lists *
180  ****************/
181
182 /*
183  * Target lists
184  */
185
186
187 /**
188  * gtk_target_list_new:
189  * @targets: Pointer to an array of #GtkTargetEntry
190  * @ntargets:  number of entries in @targets.
191  * 
192  * Creates a new #GtkTargetList from an array of #GtkTargetEntry.
193  * 
194  * Return value: the new #GtkTargetList.
195  **/
196 GtkTargetList *
197 gtk_target_list_new (const GtkTargetEntry *targets,
198                      guint                 ntargets)
199 {
200   GtkTargetList *result = g_new (GtkTargetList, 1);
201   result->list = NULL;
202   result->ref_count = 1;
203
204   if (targets)
205     gtk_target_list_add_table (result, targets, ntargets);
206   
207   return result;
208 }
209
210 /**
211  * gtk_target_list_ref:
212  * @list:  a #GtkTargetList
213  * 
214  * Increases the reference count of a #GtkTargetList by one.
215  *
216  **/
217 void               
218 gtk_target_list_ref (GtkTargetList *list)
219 {
220   g_return_if_fail (list != NULL);
221
222   list->ref_count++;
223 }
224
225 /**
226  * gtk_target_list_unref:
227  * @list: a #GtkTargetList
228  * 
229  * Decreases the reference count of a #GtkTargetList by one.
230  * If the resulting reference count is zero, frees the list.
231  **/
232 void               
233 gtk_target_list_unref (GtkTargetList *list)
234 {
235   g_return_if_fail (list != NULL);
236   g_return_if_fail (list->ref_count > 0);
237
238   list->ref_count--;
239   if (list->ref_count == 0)
240     {
241       GList *tmp_list = list->list;
242       while (tmp_list)
243         {
244           GtkTargetPair *pair = tmp_list->data;
245           g_free (pair);
246
247           tmp_list = tmp_list->next;
248         }
249       
250       g_list_free (list->list);
251       g_free (list);
252     }
253 }
254
255 /**
256  * gtk_target_list_add:
257  * @list:  a #GtkTargetList
258  * @target: the interned atom representing the target
259  * @flags: the flags for this target
260  * @info: an ID that will be passed back to the application
261  * 
262  * Appends another target to a #GtkTargetList.
263  **/
264 void 
265 gtk_target_list_add (GtkTargetList *list,
266                      GdkAtom        target,
267                      guint          flags,
268                      guint          info)
269 {
270   GtkTargetPair *pair;
271
272   g_return_if_fail (list != NULL);
273   
274   pair = g_new (GtkTargetPair, 1);
275   pair->target = target;
276   pair->flags = flags;
277   pair->info = info;
278
279   list->list = g_list_append (list->list, pair);
280 }
281
282 static GdkAtom utf8_atom;
283 static GdkAtom text_atom;
284 static GdkAtom ctext_atom;
285 static GdkAtom text_plain_atom;
286 static GdkAtom text_plain_utf8_atom;
287 static GdkAtom text_plain_locale_atom;
288 static GdkAtom text_uri_list_atom;
289
290 static void 
291 init_atoms (void)
292 {
293   gchar *tmp;
294   const gchar *charset;
295
296   if (!utf8_atom)
297     {
298       utf8_atom = gdk_atom_intern_static_string ("UTF8_STRING");
299       text_atom = gdk_atom_intern_static_string ("TEXT");
300       ctext_atom = gdk_atom_intern_static_string ("COMPOUND_TEXT");
301       text_plain_atom = gdk_atom_intern_static_string ("text/plain");
302       text_plain_utf8_atom = gdk_atom_intern_static_string ("text/plain;charset=utf-8");
303       g_get_charset (&charset);
304       tmp = g_strdup_printf ("text/plain;charset=%s", charset);
305       text_plain_locale_atom = gdk_atom_intern (tmp, FALSE);
306       g_free (tmp);
307
308       text_uri_list_atom = gdk_atom_intern_static_string ("text/uri-list");
309     }
310 }
311
312 /**
313  * gtk_target_list_add_text_targets:
314  * @list: a #GtkTargetList
315  * @info: an ID that will be passed back to the application
316  * 
317  * Appends the text targets supported by #GtkSelection to
318  * the target list. All targets are added with the same @info.
319  * 
320  * Since: 2.6
321  **/
322 void 
323 gtk_target_list_add_text_targets (GtkTargetList *list,
324                                   guint          info)
325 {
326   g_return_if_fail (list != NULL);
327   
328   init_atoms ();
329
330   /* Keep in sync with gtk_selection_data_targets_include_text()
331    */
332   gtk_target_list_add (list, utf8_atom, 0, info);  
333   gtk_target_list_add (list, ctext_atom, 0, info);  
334   gtk_target_list_add (list, text_atom, 0, info);  
335   gtk_target_list_add (list, GDK_TARGET_STRING, 0, info);  
336   gtk_target_list_add (list, text_plain_utf8_atom, 0, info);  
337   gtk_target_list_add (list, text_plain_locale_atom, 0, info);  
338   gtk_target_list_add (list, text_plain_atom, 0, info);  
339 }
340
341 /**
342  * gtk_target_list_add_image_targets:
343  * @list: a #GtkTargetList
344  * @info: an ID that will be passed back to the application
345  * @writable: whether to add only targets for which GTK+ knows
346  *   how to convert a pixbuf into the format
347  * 
348  * Appends the image targets supported by #GtkSelection to
349  * the target list. All targets are added with the same @info.
350  * 
351  * Since: 2.6
352  **/
353 void 
354 gtk_target_list_add_image_targets (GtkTargetList *list,
355                                    guint          info,
356                                    gboolean       writable)
357 {
358   GSList *formats, *f;
359   gchar **mimes, **m;
360   GdkAtom atom;
361
362   g_return_if_fail (list != NULL);
363
364   formats = gdk_pixbuf_get_formats ();
365
366   /* Make sure png comes first */
367   for (f = formats; f; f = f->next)
368     {
369       GdkPixbufFormat *fmt = f->data;
370       gchar *name; 
371  
372       name = gdk_pixbuf_format_get_name (fmt);
373       if (strcmp (name, "png") == 0)
374         {
375           formats = g_slist_delete_link (formats, f);
376           formats = g_slist_prepend (formats, fmt);
377
378           g_free (name);
379
380           break;
381         }
382
383       g_free (name);
384     }  
385
386   for (f = formats; f; f = f->next)
387     {
388       GdkPixbufFormat *fmt = f->data;
389
390       if (writable && !gdk_pixbuf_format_is_writable (fmt))
391         continue;
392       
393       mimes = gdk_pixbuf_format_get_mime_types (fmt);
394       for (m = mimes; *m; m++)
395         {
396           atom = gdk_atom_intern (*m, FALSE);
397           gtk_target_list_add (list, atom, 0, info);  
398         }
399       g_strfreev (mimes);
400     }
401
402   g_slist_free (formats);
403 }
404
405 /**
406  * gtk_target_list_add_uri_targets:
407  * @list: a #GtkTargetList
408  * @info: an ID that will be passed back to the application
409  * 
410  * Appends the URI targets supported by #GtkSelection to
411  * the target list. All targets are added with the same @info.
412  * 
413  * Since: 2.6
414  **/
415 void 
416 gtk_target_list_add_uri_targets (GtkTargetList *list,
417                                  guint          info)
418 {
419   g_return_if_fail (list != NULL);
420   
421   init_atoms ();
422
423   gtk_target_list_add (list, text_uri_list_atom, 0, info);  
424 }
425
426 /**
427  * gtk_target_list_add_table:
428  * @list: a #GtkTargetList
429  * @targets: the table of #GtkTargetEntry
430  * @ntargets: number of targets in the table
431  * 
432  * Prepends a table of #GtkTargetEntry to a target list.
433  **/
434 void               
435 gtk_target_list_add_table (GtkTargetList        *list,
436                            const GtkTargetEntry *targets,
437                            guint                 ntargets)
438 {
439   gint i;
440
441   for (i=ntargets-1; i >= 0; i--)
442     {
443       GtkTargetPair *pair = g_new (GtkTargetPair, 1);
444       pair->target = gdk_atom_intern (targets[i].target, FALSE);
445       pair->flags = targets[i].flags;
446       pair->info = targets[i].info;
447       
448       list->list = g_list_prepend (list->list, pair);
449     }
450 }
451
452 /**
453  * gtk_target_list_remove:
454  * @list: a #GtkTargetList
455  * @target: the interned atom representing the target
456  * 
457  * Removes a target from a target list.
458  **/
459 void 
460 gtk_target_list_remove (GtkTargetList *list,
461                         GdkAtom            target)
462 {
463   GList *tmp_list;
464
465   g_return_if_fail (list != NULL);
466
467   tmp_list = list->list;
468   while (tmp_list)
469     {
470       GtkTargetPair *pair = tmp_list->data;
471       
472       if (pair->target == target)
473         {
474           g_free (pair);
475
476           list->list = g_list_remove_link (list->list, tmp_list);
477           g_list_free_1 (tmp_list);
478
479           return;
480         }
481       
482       tmp_list = tmp_list->next;
483     }
484 }
485
486 /**
487  * gtk_target_list_find:
488  * @list: a #GtkTargetList
489  * @target: an interned atom representing the target to search for
490  * @info: a pointer to the location to store application info for target
491  * 
492  * Looks up a given target in a #GtkTargetList.
493  * 
494  * Return value: %TRUE if the target was found, otherwise %FALSE
495  **/
496 gboolean
497 gtk_target_list_find (GtkTargetList *list,
498                       GdkAtom        target,
499                       guint         *info)
500 {
501   GList *tmp_list = list->list;
502   while (tmp_list)
503     {
504       GtkTargetPair *pair = tmp_list->data;
505
506       if (pair->target == target)
507         {
508           *info = pair->info;
509           return TRUE;
510         }
511       tmp_list = tmp_list->next;
512     }
513
514   return FALSE;
515 }
516
517 /**
518  * gtk_selection_owner_set_for_display:
519  * @display: the #Gdkdisplay where the selection is set 
520  * @widget: new selection owner (a #GdkWidget), or %NULL.
521  * @selection: an interned atom representing the selection to claim.
522  * @time_: timestamp with which to claim the selection
523  *
524  * Claim ownership of a given selection for a particular widget, or,
525  * if @widget is %NULL, release ownership of the selection.
526  *
527  * Return value: TRUE if the operation succeeded 
528  * 
529  * Since: 2.2
530  */
531 gboolean
532 gtk_selection_owner_set_for_display (GdkDisplay   *display,
533                                      GtkWidget    *widget,
534                                      GdkAtom       selection,
535                                      guint32       time)
536 {
537   GList *tmp_list;
538   GtkWidget *old_owner;
539   GtkSelectionInfo *selection_info = NULL;
540   GdkWindow *window;
541
542   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
543   g_return_val_if_fail (selection != GDK_NONE, FALSE);
544   g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
545   g_return_val_if_fail (widget == NULL || gtk_widget_get_display (widget) == display, FALSE);
546   
547   if (widget == NULL)
548     window = NULL;
549   else
550     window = widget->window;
551
552   tmp_list = current_selections;
553   while (tmp_list)
554     {
555       if (((GtkSelectionInfo *)tmp_list->data)->selection == selection)
556         {
557           selection_info = tmp_list->data;
558           break;
559         }
560       
561       tmp_list = tmp_list->next;
562     }
563   
564   if (gdk_selection_owner_set_for_display (display, window, selection, time, TRUE))
565     {
566       old_owner = NULL;
567       
568       if (widget == NULL)
569         {
570           if (selection_info)
571             {
572               old_owner = selection_info->widget;
573               current_selections = g_list_remove_link (current_selections,
574                                                        tmp_list);
575               g_list_free (tmp_list);
576               g_free (selection_info);
577             }
578         }
579       else
580         {
581           if (selection_info == NULL)
582             {
583               selection_info = g_new (GtkSelectionInfo, 1);
584               selection_info->selection = selection;
585               selection_info->widget = widget;
586               selection_info->time = time;
587               selection_info->display = display;
588               current_selections = g_list_prepend (current_selections,
589                                                    selection_info);
590             }
591           else
592             {
593               old_owner = selection_info->widget;
594               selection_info->widget = widget;
595               selection_info->time = time;
596               selection_info->display = display;
597             }
598         }
599       /* If another widget in the application lost the selection,
600        *  send it a GDK_SELECTION_CLEAR event.
601        */
602       if (old_owner && old_owner != widget)
603         {
604           GdkEvent *event = gdk_event_new (GDK_SELECTION_CLEAR);
605           
606           event->selection.window = g_object_ref (old_owner->window);
607           event->selection.selection = selection;
608           event->selection.time = time;
609           
610           gtk_widget_event (old_owner, event);
611
612           gdk_event_free (event);
613         }
614       return TRUE;
615     }
616   else
617     return FALSE;
618 }
619
620 /**
621  * gtk_selection_owner_set:
622  * @widget:  a #GtkWidget, or %NULL.
623  * @selection:  an interned atom representing the selection to claim
624  * @time_: timestamp with which to claim the selection
625  * 
626  * Claims ownership of a given selection for a particular widget,
627  * or, if @widget is %NULL, release ownership of the selection.
628  * 
629  * Return value: %TRUE if the operation succeeded
630  **/
631 gboolean
632 gtk_selection_owner_set (GtkWidget *widget,
633                          GdkAtom    selection,
634                          guint32    time)
635 {
636   GdkDisplay *display;
637   
638   g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
639   g_return_val_if_fail (selection != GDK_NONE, FALSE);
640
641   if (widget)
642     display = gtk_widget_get_display (widget);
643   else
644     {
645       GTK_NOTE (MULTIHEAD,
646                 g_warning ("gtk_selection_owner_set (NULL,...) is not multihead safe"));
647                  
648       display = gdk_display_get_default ();
649     }
650   
651   return gtk_selection_owner_set_for_display (display, widget,
652                                               selection, time);
653 }
654
655 typedef struct _GtkSelectionTargetList GtkSelectionTargetList;
656
657 struct _GtkSelectionTargetList {
658   GdkAtom selection;
659   GtkTargetList *list;
660 };
661
662 static GtkTargetList *
663 gtk_selection_target_list_get (GtkWidget    *widget,
664                                GdkAtom       selection)
665 {
666   GtkSelectionTargetList *sellist;
667   GList *tmp_list;
668   GList *lists;
669
670   lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
671   
672   tmp_list = lists;
673   while (tmp_list)
674     {
675       sellist = tmp_list->data;
676       if (sellist->selection == selection)
677         return sellist->list;
678       tmp_list = tmp_list->next;
679     }
680
681   sellist = g_new (GtkSelectionTargetList, 1);
682   sellist->selection = selection;
683   sellist->list = gtk_target_list_new (NULL, 0);
684
685   lists = g_list_prepend (lists, sellist);
686   g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), lists);
687
688   return sellist->list;
689 }
690
691 static void
692 gtk_selection_target_list_remove (GtkWidget    *widget)
693 {
694   GtkSelectionTargetList *sellist;
695   GList *tmp_list;
696   GList *lists;
697
698   lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
699   
700   tmp_list = lists;
701   while (tmp_list)
702     {
703       sellist = tmp_list->data;
704
705       gtk_target_list_unref (sellist->list);
706
707       g_free (sellist);
708       tmp_list = tmp_list->next;
709     }
710
711   g_list_free (lists);
712   g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), NULL);
713 }
714
715 /**
716  * gtk_selection_clear_targets:
717  * @widget:    a #GtkWidget
718  * @selection: an atom representing a selection
719  *
720  * Remove all targets registered for the given selection for the
721  * widget.
722  **/
723 void 
724 gtk_selection_clear_targets (GtkWidget *widget,
725                              GdkAtom    selection)
726 {
727   GtkSelectionTargetList *sellist;
728   GList *tmp_list;
729   GList *lists;
730
731   g_return_if_fail (GTK_IS_WIDGET (widget));
732   g_return_if_fail (selection != GDK_NONE);
733
734   lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
735   
736   tmp_list = lists;
737   while (tmp_list)
738     {
739       sellist = tmp_list->data;
740       if (sellist->selection == selection)
741         {
742           lists = g_list_delete_link (lists, tmp_list);
743           gtk_target_list_unref (sellist->list);
744           g_free (sellist);
745
746           break;
747         }
748       
749       tmp_list = tmp_list->next;
750     }
751   
752   g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), lists);
753 }
754
755 /**
756  * gtk_selection_add_target:
757  * @widget:  a #GtkTarget
758  * @selection: the selection
759  * @target: target to add.
760  * @info: A unsigned integer which will be passed back to the application.
761  * 
762  * Appends a specified target to the list of supported targets for a 
763  * given widget and selection.
764  **/
765 void 
766 gtk_selection_add_target (GtkWidget         *widget, 
767                           GdkAtom            selection,
768                           GdkAtom            target,
769                           guint              info)
770 {
771   GtkTargetList *list;
772
773   g_return_if_fail (GTK_IS_WIDGET (widget));
774   g_return_if_fail (selection != GDK_NONE);
775
776   list = gtk_selection_target_list_get (widget, selection);
777   gtk_target_list_add (list, target, 0, info);
778 #ifdef GDK_WINDOWING_WIN32
779   gdk_win32_selection_add_targets (widget->window, selection, 1, &target);
780 #endif
781 }
782
783 /**
784  * gtk_selection_add_targets:
785  * @widget: a #GtkWidget
786  * @selection: the selection
787  * @targets: a table of targets to add
788  * @ntargets:  number of entries in @targets
789  * 
790  * Prepends a table of targets to the list of supported targets
791  * for a given widget and selection.
792  **/
793 void 
794 gtk_selection_add_targets (GtkWidget            *widget, 
795                            GdkAtom               selection,
796                            const GtkTargetEntry *targets,
797                            guint                 ntargets)
798 {
799   GtkTargetList *list;
800
801   g_return_if_fail (GTK_IS_WIDGET (widget));
802   g_return_if_fail (selection != GDK_NONE);
803   g_return_if_fail (targets != NULL);
804   
805   list = gtk_selection_target_list_get (widget, selection);
806   gtk_target_list_add_table (list, targets, ntargets);
807
808 #ifdef GDK_WINDOWING_WIN32
809   {
810     int i;
811     GdkAtom *atoms = g_new (GdkAtom, ntargets);
812
813     for (i = 0; i < ntargets; ++i)
814       atoms[i] = gdk_atom_intern (targets[i].target, FALSE);
815     gdk_win32_selection_add_targets (widget->window, selection, ntargets, atoms);
816     g_free (atoms);
817   }
818 #endif
819 }
820
821
822 /**
823  * gtk_selection_remove_all:
824  * @widget: a #GtkWidget 
825  * 
826  * Removes all handlers and unsets ownership of all 
827  * selections for a widget. Called when widget is being
828  * destroyed. This function will not generally be
829  * called by applications.
830  **/
831 void
832 gtk_selection_remove_all (GtkWidget *widget)
833 {
834   GList *tmp_list;
835   GList *next;
836   GtkSelectionInfo *selection_info;
837   
838   /* Remove pending requests/incrs for this widget */
839   
840   tmp_list = current_retrievals;
841   while (tmp_list)
842     {
843       next = tmp_list->next;
844       if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget)
845         {
846           current_retrievals = g_list_remove_link (current_retrievals, 
847                                                    tmp_list);
848           /* structure will be freed in timeout */
849           g_list_free (tmp_list);
850         }
851       tmp_list = next;
852     }
853   
854   /* Disclaim ownership of any selections */
855   
856   tmp_list = current_selections;
857   while (tmp_list)
858     {
859       next = tmp_list->next;
860       selection_info = (GtkSelectionInfo *)tmp_list->data;
861       
862       if (selection_info->widget == widget)
863         {       
864           gdk_selection_owner_set_for_display (selection_info->display,
865                                                NULL, 
866                                                selection_info->selection,
867                                                GDK_CURRENT_TIME, FALSE);
868           current_selections = g_list_remove_link (current_selections,
869                                                    tmp_list);
870           g_list_free (tmp_list);
871           g_free (selection_info);
872         }
873       
874       tmp_list = next;
875     }
876
877   /* Remove all selection lists */
878   gtk_selection_target_list_remove (widget);
879 }
880
881
882 /**
883  * gtk_selection_convert:
884  * @widget: The widget which acts as requestor
885  * @selection: Which selection to get
886  * @target: Form of information desired (e.g., STRING)
887  * @time_: Time of request (usually of triggering event)
888        In emergency, you could use #GDK_CURRENT_TIME
889  * 
890  * Requests the contents of a selection. When received, 
891  * a "selection_received" signal will be generated.
892  * 
893  * Return value: %TRUE if requested succeeded. %FALSE if we could not process
894  *          request. (e.g., there was already a request in process for
895  *          this widget).
896  **/
897 gboolean
898 gtk_selection_convert (GtkWidget *widget, 
899                        GdkAtom    selection, 
900                        GdkAtom    target,
901                        guint32    time_)
902 {
903   GtkRetrievalInfo *info;
904   GList *tmp_list;
905   GdkWindow *owner_window;
906   GdkDisplay *display;
907   
908   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
909   g_return_val_if_fail (selection != GDK_NONE, FALSE);
910   
911   if (initialize)
912     gtk_selection_init ();
913   
914   if (!GTK_WIDGET_REALIZED (widget))
915     gtk_widget_realize (widget);
916   
917   /* Check to see if there are already any retrievals in progress for
918      this widget. If we changed GDK to use the selection for the 
919      window property in which to store the retrieved information, then
920      we could support multiple retrievals for different selections.
921      This might be useful for DND. */
922   
923   tmp_list = current_retrievals;
924   while (tmp_list)
925     {
926       info = (GtkRetrievalInfo *)tmp_list->data;
927       if (info->widget == widget)
928         return FALSE;
929       tmp_list = tmp_list->next;
930     }
931   
932   info = g_new (GtkRetrievalInfo, 1);
933   
934   info->widget = widget;
935   info->selection = selection;
936   info->target = target;
937   info->idle_time = 0;
938   info->buffer = NULL;
939   info->offset = -1;
940   
941   /* Check if this process has current owner. If so, call handler
942      procedure directly to avoid deadlocks with INCR. */
943
944   display = gtk_widget_get_display (widget);
945   owner_window = gdk_selection_owner_get_for_display (display, selection);
946   
947   if (owner_window != NULL)
948     {
949       GtkWidget *owner_widget;
950       GtkSelectionData selection_data;
951       
952       selection_data.selection = selection;
953       selection_data.target = target;
954       selection_data.data = NULL;
955       selection_data.length = -1;
956       selection_data.display = display;
957       
958       gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget);
959       
960       if (owner_widget != NULL)
961         {
962           gtk_selection_invoke_handler (owner_widget, 
963                                         &selection_data,
964                                         time_);
965           
966           gtk_selection_retrieval_report (info,
967                                           selection_data.type, 
968                                           selection_data.format,
969                                           selection_data.data,
970                                           selection_data.length,
971                                           time_);
972           
973           g_free (selection_data.data);
974           
975           g_free (info);
976           return TRUE;
977         }
978     }
979   
980   /* Otherwise, we need to go through X */
981   
982   current_retrievals = g_list_append (current_retrievals, info);
983   gdk_selection_convert (widget->window, selection, target, time_);
984   g_timeout_add (1000, (GSourceFunc) gtk_selection_retrieval_timeout, info);
985   
986   return TRUE;
987 }
988
989
990 /**
991  * gtk_selection_data_set:
992  * @selection_data: a pointer to a #GtkSelectionData structure.
993  * @type: the type of selection data
994  * @format: format (number of bits in a unit)
995  * @data: pointer to the data (will be copied)
996  * @length: length of the data
997  * 
998  * Stores new data into a #GtkSelectionData object. Should
999  * <emphasis>only</emphasis> be called from a selection handler callback.
1000  * Zero-terminates the stored data.
1001  **/
1002 void 
1003 gtk_selection_data_set (GtkSelectionData *selection_data,
1004                         GdkAtom           type,
1005                         gint              format,
1006                         const guchar     *data,
1007                         gint              length)
1008 {
1009   if (selection_data->data)
1010     g_free (selection_data->data);
1011   
1012   selection_data->type = type;
1013   selection_data->format = format;
1014   
1015   if (data)
1016     {
1017       selection_data->data = g_new (guchar, length+1);
1018       memcpy (selection_data->data, data, length);
1019       selection_data->data[length] = 0;
1020     }
1021   else
1022     {
1023       g_return_if_fail (length <= 0);
1024       
1025       if (length < 0)
1026         selection_data->data = NULL;
1027       else
1028         selection_data->data = g_strdup("");
1029     }
1030   
1031   selection_data->length = length;
1032 }
1033
1034 static gboolean
1035 selection_set_string (GtkSelectionData *selection_data,
1036                       const gchar      *str,
1037                       gint              len)
1038 {
1039   gchar *tmp = g_strndup (str, len);
1040   gchar *latin1 = gdk_utf8_to_string_target (tmp);
1041   g_free (tmp);
1042   
1043   if (latin1)
1044     {
1045       gtk_selection_data_set (selection_data,
1046                               GDK_SELECTION_TYPE_STRING,
1047                               8, latin1, strlen (latin1));
1048       g_free (latin1);
1049       
1050       return TRUE;
1051     }
1052   else
1053     return FALSE;
1054 }
1055
1056 static gboolean
1057 selection_set_compound_text (GtkSelectionData *selection_data,
1058                              const gchar      *str,
1059                              gint              len)
1060 {
1061   gchar *tmp;
1062   guchar *text;
1063   GdkAtom encoding;
1064   gint format;
1065   gint new_length;
1066   gboolean result = FALSE;
1067   
1068   tmp = g_strndup (str, len);
1069   if (gdk_utf8_to_compound_text_for_display (selection_data->display, tmp,
1070                                              &encoding, &format, &text, &new_length))
1071     {
1072       gtk_selection_data_set (selection_data, encoding, format, text, new_length);
1073       gdk_free_compound_text (text);
1074       
1075       result = TRUE;
1076     }
1077
1078   g_free (tmp);
1079
1080   return result;
1081 }
1082
1083 /* Normalize \r and \n into \r\n
1084  */
1085 static gchar *
1086 normalize_to_crlf (const gchar *str, 
1087                    gint         len)
1088 {
1089   GString *result = g_string_sized_new (len);
1090   const gchar *p = str;
1091
1092   while (1)
1093     {
1094       if (*p == '\n')
1095         g_string_append_c (result, '\r');
1096
1097       if (*p == '\r')
1098         {
1099           g_string_append_c (result, *p);
1100           p++;
1101           if (*p != '\n')
1102             g_string_append_c (result, '\n');
1103         }
1104
1105       if (*p == '\0')
1106         break;
1107
1108       g_string_append_c (result, *p);
1109       p++;
1110     }
1111
1112   return g_string_free (result, FALSE);  
1113 }
1114
1115 /* Normalize \r and \r\n into \n
1116  */
1117 static gchar *
1118 normalize_to_lf (gchar *str, 
1119                  gint   len)
1120 {
1121   GString *result = g_string_sized_new (len);
1122   const gchar *p = str;
1123
1124   while (1)
1125     {
1126       if (*p == '\r')
1127         {
1128           p++;
1129           if (*p != '\n')
1130             g_string_append_c (result, '\n');
1131         }
1132
1133       if (*p == '\0')
1134         break;
1135
1136       g_string_append_c (result, *p);
1137       p++;
1138     }
1139
1140   return g_string_free (result, FALSE);  
1141 }
1142
1143 static gboolean
1144 selection_set_text_plain (GtkSelectionData *selection_data,
1145                           const gchar      *str,
1146                           gint              len)
1147 {
1148   const gchar *charset = NULL;
1149   gchar *result;
1150   GError *error = NULL;
1151
1152   result = normalize_to_crlf (str, len);
1153   if (selection_data->target == text_plain_atom)
1154     charset = "ASCII";
1155   else if (selection_data->target == text_plain_locale_atom)
1156     g_get_charset (&charset);
1157
1158   if (charset)
1159     {
1160       gchar *tmp = result;
1161       result = g_convert_with_fallback (tmp, -1, 
1162                                         charset, "UTF-8", 
1163                                         NULL, NULL, NULL, &error);
1164       g_free (tmp);
1165     }
1166
1167   if (!result)
1168     {
1169       g_warning ("Error converting from UTF-8 to %s: %s",
1170                  charset, error->message);
1171       g_error_free (error);
1172       
1173       return FALSE;
1174     }
1175   
1176   gtk_selection_data_set (selection_data,
1177                           selection_data->target, 
1178                           8, result, strlen (result));
1179   g_free (result);
1180   
1181   return TRUE;
1182 }
1183
1184 static gchar *
1185 selection_get_text_plain (GtkSelectionData *selection_data)
1186 {
1187   const gchar *charset = NULL;
1188   gchar *str, *result;
1189   gsize len;
1190   GError *error = NULL;
1191
1192   str = g_strdup (selection_data->data);
1193   len = selection_data->length;
1194   
1195   if (selection_data->type == text_plain_atom)
1196     charset = "ISO-8859-1";
1197   else if (selection_data->type == text_plain_locale_atom)
1198     g_get_charset (&charset);
1199
1200   if (charset)
1201     {
1202       gchar *tmp = str;
1203       str = g_convert_with_fallback (tmp, len, 
1204                                      charset, "UTF-8", 
1205                                      NULL, NULL, &len, &error);
1206       g_free (tmp);
1207
1208       if (!str)
1209         {
1210           g_warning ("Error converting from %s to UTF-8: %s",
1211                       charset, error->message);
1212           g_error_free (error);
1213
1214           return NULL;
1215         }
1216     }
1217   else if (!g_utf8_validate (str, -1, NULL))
1218     {
1219       g_warning ("Error converting from text/plain;charset=utf-8 to UTF-8");
1220       g_free (str);
1221
1222       return NULL;
1223     }
1224
1225   result = normalize_to_lf (str, len);
1226   g_free (str);
1227
1228   return result;
1229 }
1230
1231 /**
1232  * gtk_selection_data_set_text:
1233  * @selection_data: a #GtkSelectionData
1234  * @str: a UTF-8 string
1235  * @len: the length of @str, or -1 if @str is nul-terminated.
1236  * 
1237  * Sets the contents of the selection from a UTF-8 encoded string.
1238  * The string is converted to the form determined by
1239  * @selection_data->target.
1240  * 
1241  * Return value: %TRUE if the selection was successfully set,
1242  *   otherwise %FALSE.
1243  **/
1244 gboolean
1245 gtk_selection_data_set_text (GtkSelectionData     *selection_data,
1246                              const gchar          *str,
1247                              gint                  len)
1248 {
1249   if (len < 0)
1250     len = strlen (str);
1251   
1252   init_atoms ();
1253
1254   if (selection_data->target == utf8_atom)
1255     {
1256       gtk_selection_data_set (selection_data,
1257                               utf8_atom,
1258                               8, (guchar *)str, len);
1259       return TRUE;
1260     }
1261   else if (selection_data->target == GDK_TARGET_STRING)
1262     {
1263       return selection_set_string (selection_data, str, len);
1264     }
1265   else if (selection_data->target == ctext_atom ||
1266            selection_data->target == text_atom)
1267     {
1268       if (selection_set_compound_text (selection_data, str, len))
1269         return TRUE;
1270       else if (selection_data->target == text_atom)
1271         return selection_set_string (selection_data, str, len);
1272     }
1273   else if (selection_data->target == text_plain_atom ||
1274            selection_data->target == text_plain_utf8_atom ||
1275            selection_data->target == text_plain_locale_atom)
1276     {
1277       return selection_set_text_plain (selection_data, str, len);
1278     }
1279
1280   return FALSE;
1281 }
1282
1283 /**
1284  * gtk_selection_data_get_text:
1285  * @selection_data: a #GtkSelectionData
1286  * 
1287  * Gets the contents of the selection data as a UTF-8 string.
1288  * 
1289  * Return value: if the selection data contained a recognized
1290  *   text type and it could be converted to UTF-8, a newly allocated
1291  *   string containing the converted text, otherwise %NULL.
1292  *   If the result is non-%NULL it must be freed with g_free().
1293  **/
1294 guchar *
1295 gtk_selection_data_get_text (GtkSelectionData *selection_data)
1296 {
1297   guchar *result = NULL;
1298
1299   init_atoms ();
1300   
1301   if (selection_data->length >= 0 &&
1302       (selection_data->type == GDK_TARGET_STRING ||
1303        selection_data->type == ctext_atom ||
1304        selection_data->type == utf8_atom))
1305     {
1306       gchar **list;
1307       gint i;
1308       gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1309                                                                selection_data->type,
1310                                                                selection_data->format, 
1311                                                                selection_data->data,
1312                                                                selection_data->length,
1313                                                                &list);
1314       if (count > 0)
1315         result = list[0];
1316
1317       for (i = 1; i < count; i++)
1318         g_free (list[i]);
1319       g_free (list);
1320     }
1321   else if (selection_data->length >= 0 &&
1322            (selection_data->type == text_plain_atom ||
1323             selection_data->type == text_plain_utf8_atom ||
1324             selection_data->type == text_plain_locale_atom))
1325     {
1326       result = selection_get_text_plain (selection_data);
1327     }
1328
1329   return result;
1330 }
1331
1332 /**
1333  * gtk_selection_data_set_pixbuf:
1334  * @selection_data: a #GtkSelectionData
1335  * @pixbuf: a #GdkPixbuf
1336  * 
1337  * Sets the contents of the selection from a #GdkPixbuf
1338  * The pixbuf is converted to the form determined by
1339  * @selection_data->target.
1340  * 
1341  * Return value: %TRUE if the selection was successfully set,
1342  *   otherwise %FALSE.
1343  *
1344  * Since: 2.6
1345  **/
1346 gboolean
1347 gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data,
1348                                GdkPixbuf        *pixbuf)
1349 {
1350   GSList *formats, *f;
1351   gchar **mimes, **m;
1352   GdkAtom atom;
1353   gboolean result;
1354   gchar *str, *type;
1355   gsize len;
1356
1357   formats = gdk_pixbuf_get_formats ();
1358
1359   for (f = formats; f; f = f->next)
1360     {
1361       GdkPixbufFormat *fmt = f->data;
1362
1363       mimes = gdk_pixbuf_format_get_mime_types (fmt);
1364       for (m = mimes; *m; m++)
1365         {
1366           atom = gdk_atom_intern (*m, FALSE);
1367           if (selection_data->target == atom)
1368             {
1369               str = NULL;
1370               type = gdk_pixbuf_format_get_name (fmt);
1371               result = gdk_pixbuf_save_to_buffer (pixbuf, &str, &len,
1372                                                   type, NULL,
1373                                                   ((strcmp (type, "png") == 0) ?
1374                                                    "compression" : NULL), "2",
1375                                                   NULL);
1376               if (result)
1377                 gtk_selection_data_set (selection_data,
1378                                         atom, 8, (guchar *)str, len);
1379               g_free (type);
1380               g_free (str);
1381               g_strfreev (mimes);
1382               g_slist_free (formats);
1383
1384               return result;
1385             }
1386         }
1387
1388       g_strfreev (mimes);
1389     }
1390
1391   g_slist_free (formats);
1392  
1393   return FALSE;
1394 }
1395
1396 /**
1397  * gtk_selection_data_get_pixbuf:
1398  * @selection_data: a #GtkSelectionData
1399  * 
1400  * Gets the contents of the selection data as a #GdkPixbuf.
1401  * 
1402  * Return value: if the selection data contained a recognized
1403  *   image type and it could be converted to a #GdkPixbuf, a 
1404  *   newly allocated pixbuf is returned, otherwise %NULL.
1405  *   If the result is non-%NULL it must be freed with g_object_unref().
1406  *
1407  * Since: 2.6
1408  **/
1409 GdkPixbuf *
1410 gtk_selection_data_get_pixbuf (GtkSelectionData *selection_data)
1411 {
1412   GdkPixbufLoader *loader;
1413   GdkPixbuf *result = NULL;
1414
1415   if (selection_data->length > 0)
1416     {
1417       loader = gdk_pixbuf_loader_new ();
1418       
1419       gdk_pixbuf_loader_write (loader, 
1420                                selection_data->data,
1421                                selection_data->length,
1422                                NULL);
1423       gdk_pixbuf_loader_close (loader, NULL);
1424       result = gdk_pixbuf_loader_get_pixbuf (loader);
1425       
1426       if (result)
1427         g_object_ref (result);
1428       
1429       g_object_unref (loader);
1430     }
1431
1432   return result;
1433 }
1434
1435 /**
1436  * gtk_selection_data_set_uris:
1437  * @selection_data: a #GtkSelectionData
1438  * @uris: a %NULL-terminated array of strings hilding URIs
1439  * 
1440  * Sets the contents of the selection from a list of URIs.
1441  * The string is converted to the form determined by
1442  * @selection_data->target.
1443  * 
1444  * Return value: %TRUE if the selection was successfully set,
1445  *   otherwise %FALSE.
1446  *
1447  * Since: 2.6
1448  **/
1449 gboolean
1450 gtk_selection_data_set_uris (GtkSelectionData  *selection_data,
1451                              gchar            **uris)
1452 {
1453   init_atoms ();
1454
1455   if (selection_data->target == text_uri_list_atom)
1456     {
1457       GString *list;
1458       gint i;
1459       gchar *result;
1460       gsize length;
1461       
1462       list = g_string_new (NULL);
1463       for (i = 0; uris[i]; i++)
1464         {
1465           g_string_append (list, uris[i]);
1466           g_string_append (list, "\r\n");
1467         }
1468
1469       result = g_convert (list->str, list->len,
1470                           "ASCII", "UTF-8", 
1471                           NULL, &length, NULL);
1472       g_string_free (list, TRUE);
1473       
1474       if (result)
1475         {
1476           gtk_selection_data_set (selection_data,
1477                                   text_uri_list_atom,
1478                                   8, (guchar *)result, length);
1479           
1480           g_free (result);
1481
1482           return TRUE;
1483         }
1484     }
1485
1486   return FALSE;
1487 }
1488
1489 /**
1490  * gtk_selection_data_get_uris:
1491  * @selection_data: a #GtkSelectionData
1492  * 
1493  * Gets the contents of the selection data as array of URIs.
1494  * 
1495  * Return value: if the selection data contains a list of
1496  *   URIs, a newly allocated %NULL-terminated string array
1497  *   containing the URIs, otherwise %NULL. If the result is 
1498  *   non-%NULL it must be freed with g_strfreev().
1499  *
1500  * Since: 2.6
1501  **/
1502 gchar **
1503 gtk_selection_data_get_uris (GtkSelectionData *selection_data)
1504 {
1505   gchar **result = NULL;
1506
1507   init_atoms ();
1508   
1509   if (selection_data->length >= 0 &&
1510       selection_data->type == text_uri_list_atom)
1511     {
1512       gchar **list;
1513       gint i;
1514       gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1515                                                                utf8_atom,
1516                                                                selection_data->format, 
1517                                                                selection_data->data,
1518                                                                selection_data->length,
1519                                                                &list);
1520       if (count > 0)
1521         result = g_uri_list_extract_uris (list[0]);
1522       
1523       g_strfreev (list);
1524     }
1525
1526   return result;
1527 }
1528
1529
1530 /**
1531  * gtk_selection_data_get_targets:
1532  * @selection_data: a #GtkSelectionData object
1533  * @targets: location to store an array of targets. The result
1534  *           stored here must be freed with g_free().
1535  * @n_atoms: location to store number of items in @targets.
1536  * 
1537  * Gets the contents of @selection_data as an array of targets.
1538  * This can be used to interpret the results of getting
1539  * the standard TARGETS target that is always supplied for
1540  * any selection.
1541  * 
1542  * Return value: %TRUE if @selection_data contains a valid
1543  *    array of targets, otherwise %FALSE.
1544  **/
1545 gboolean
1546 gtk_selection_data_get_targets (GtkSelectionData  *selection_data,
1547                                 GdkAtom          **targets,
1548                                 gint              *n_atoms)
1549 {
1550   if (selection_data->length >= 0 &&
1551       selection_data->format == 32 &&
1552       selection_data->type == GDK_SELECTION_TYPE_ATOM)
1553     {
1554       if (targets)
1555         *targets = g_memdup (selection_data->data, selection_data->length);
1556       if (n_atoms)
1557         *n_atoms = selection_data->length / sizeof (GdkAtom);
1558
1559       return TRUE;
1560     }
1561   else
1562     {
1563       if (targets)
1564         *targets = NULL;
1565       if (n_atoms)
1566         *n_atoms = -1;
1567
1568       return FALSE;
1569     }
1570 }
1571
1572 /**
1573  * gtk_targets_include_text:
1574  * @targets: an array of #GdkAtom<!-- -->s
1575  * @n_targets: the length of @targets
1576  * 
1577  * Determines if any of the targets in @targets can be used to
1578  * provide text.
1579  * 
1580  * Return value: %TRUE if @targets include a suitable target for text,
1581  *   otherwise %FALSE.
1582  *
1583  * Since: 2.10
1584  **/
1585 gboolean 
1586 gtk_targets_include_text (GdkAtom *targets,
1587                            gint     n_targets)
1588 {
1589   gint i;
1590   gboolean result = FALSE;
1591
1592   /* Keep in sync with gtk_target_list_add_text_targets()
1593    */
1594   for (i = 0; i < n_targets; i++)
1595     {
1596       if (targets[i] == utf8_atom ||
1597           targets[i] == text_atom ||
1598           targets[i] == GDK_TARGET_STRING ||
1599           targets[i] == ctext_atom ||
1600           targets[i] == text_plain_atom ||
1601           targets[i] == text_plain_utf8_atom ||
1602           targets[i] == text_plain_locale_atom)
1603         {
1604           result = TRUE;
1605           break;
1606         }
1607     }
1608   
1609   return result;
1610 }
1611                                     
1612 /**
1613  * gtk_selection_data_targets_include_text:
1614  * @selection_data: a #GtkSelectionData object
1615  * 
1616  * Given a #GtkSelectionData object holding a list of targets,
1617  * determines if any of the targets in @targets can be used to
1618  * provide text.
1619  * 
1620  * Return value: %TRUE if @selection_data holds a list of targets,
1621  *   and a suitable target for text is included, otherwise %FALSE.
1622  **/
1623 gboolean
1624 gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
1625 {
1626   GdkAtom *targets;
1627   gint n_targets;
1628   gboolean result = FALSE;
1629
1630   init_atoms ();
1631
1632   if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1633     {
1634       result = gtk_targets_include_text (targets, n_targets);
1635       g_free (targets);
1636     }
1637
1638   return result;
1639 }
1640
1641 /**
1642  * gtk_targets_include_image:
1643  * @targets: an array of #GdkAtom<!-- -->s
1644  * @n_targets: the length of @targets
1645  * @writable: whether to accept only targets for which GTK+ knows
1646  *   how to convert a pixbuf into the format
1647  * 
1648  * Determines if any of the targets in @targets can be used to
1649  * provide a #GdkPixbuf.
1650  * 
1651  * Return value: %TRUE if @targets include a suitable target for images,
1652  *   otherwise %FALSE.
1653  *
1654  * Since: 2.10
1655  **/
1656 gboolean 
1657 gtk_targets_include_image (GdkAtom *targets,
1658                            gint     n_targets,
1659                            gboolean writable)
1660 {
1661   GtkTargetList *list;
1662   GList *l;
1663   gint i;
1664   gboolean result = FALSE;
1665
1666   list = gtk_target_list_new (NULL, 0);
1667   gtk_target_list_add_image_targets (list, 0, writable);
1668   for (i = 0; i < n_targets && !result; i++)
1669     {
1670       for (l = list->list; l; l = l->next)
1671         {
1672           GtkTargetPair *pair = (GtkTargetPair *)l->data;
1673           if (pair->target == targets[i])
1674             {
1675               result = TRUE;
1676               break;
1677             }
1678         }
1679     }
1680   gtk_target_list_unref (list);
1681
1682   return result;
1683 }
1684                                     
1685 /**
1686  * gtk_selection_data_targets_include_image:
1687  * @selection_data: a #GtkSelectionData object
1688  * @writable: whether to accept only targets for which GTK+ knows
1689  *   how to convert a pixbuf into the format
1690  * 
1691  * Given a #GtkSelectionData object holding a list of targets,
1692  * determines if any of the targets in @targets can be used to
1693  * provide a #GdkPixbuf.
1694  * 
1695  * Return value: %TRUE if @selection_data holds a list of targets,
1696  *   and a suitable target for images is included, otherwise %FALSE.
1697  *
1698  * Since: 2.6
1699  **/
1700 gboolean 
1701 gtk_selection_data_targets_include_image (GtkSelectionData *selection_data,
1702                                           gboolean          writable)
1703 {
1704   GdkAtom *targets;
1705   gint n_targets;
1706   gboolean result = FALSE;
1707
1708   init_atoms ();
1709
1710   if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1711     {
1712       result = gtk_targets_include_image (targets, n_targets, writable);
1713       g_free (targets);
1714     }
1715
1716   return result;
1717 }
1718
1719 /**
1720  * gtk_targets_include_uri:
1721  * @targets: an array of #GdkAtom<!-- -->s
1722  * @n_targets: the length of @targets
1723  * 
1724  * Determines if any of the targets in @targets can be used to
1725  * provide an uri list.
1726  * 
1727  * Return value: %TRUE if @targets include a suitable target for uri lists,
1728  *   otherwise %FALSE.
1729  *
1730  * Since: 2.10
1731  **/
1732 gboolean 
1733 gtk_targets_include_uri (GdkAtom *targets,
1734                          gint     n_targets)
1735 {
1736   gint i;
1737   gboolean result = FALSE;
1738
1739   /* Keep in sync with gtk_target_list_add_uri_targets()
1740    */
1741   for (i = 0; i < n_targets; i++)
1742     {
1743       if (targets[i] == text_uri_list_atom)
1744         {
1745           result = TRUE;
1746           break;
1747         }
1748     }
1749   
1750   return result;
1751 }
1752
1753 /**
1754  * gtk_selection_data_targets_include_uri:
1755  * @selection_data: a #GtkSelectionData object
1756  * 
1757  * Given a #GtkSelectionData object holding a list of targets,
1758  * determines if any of the targets in @targets can be used to
1759  * provide a list or URIs.
1760  * 
1761  * Return value: %TRUE if @selection_data holds a list of targets,
1762  *   and a suitable target for text is included, otherwise %FALSE.
1763  *
1764  * Since: 2.10
1765  **/
1766 gboolean
1767 gtk_selection_data_targets_include_uri (GtkSelectionData *selection_data)
1768 {
1769   GdkAtom *targets;
1770   gint n_targets;
1771   gboolean result = FALSE;
1772
1773   init_atoms ();
1774
1775   if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1776     {
1777       result = gtk_targets_include_uri (targets, n_targets);
1778       g_free (targets);
1779     }
1780
1781   return result;
1782 }
1783
1784           
1785 /*************************************************************
1786  * gtk_selection_init:
1787  *     Initialize local variables
1788  *   arguments:
1789  *     
1790  *   results:
1791  *************************************************************/
1792
1793 static void
1794 gtk_selection_init (void)
1795 {
1796   gtk_selection_atoms[INCR] = gdk_atom_intern_static_string ("INCR");
1797   gtk_selection_atoms[MULTIPLE] = gdk_atom_intern_static_string ("MULTIPLE");
1798   gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern_static_string ("TIMESTAMP");
1799   gtk_selection_atoms[TARGETS] = gdk_atom_intern_static_string ("TARGETS");
1800
1801   initialize = FALSE;
1802 }
1803
1804 /**
1805  * gtk_selection_clear:
1806  * @widget: a #GtkWidget
1807  * @event: the event
1808  * 
1809  * The default handler for the GtkWidget::selection_clear_event
1810  * signal. 
1811  * 
1812  * Return value: %TRUE if the event was handled, otherwise false
1813  * 
1814  * Since: 2.2
1815  *
1816  * Deprecated: 2.4: Instead of calling this function, chain up from
1817  * your selection_clear_event handler. Calling this function
1818  * from any other context is illegal. 
1819  **/
1820 gboolean
1821 gtk_selection_clear (GtkWidget         *widget,
1822                      GdkEventSelection *event)
1823 {
1824   /* Note that we filter clear events in gdkselection-x11.c, so
1825    * that we only will get here if the clear event actually
1826    * represents a change that we didn't do ourself.
1827    */
1828   GList *tmp_list;
1829   GtkSelectionInfo *selection_info = NULL;
1830   
1831   tmp_list = current_selections;
1832   while (tmp_list)
1833     {
1834       selection_info = (GtkSelectionInfo *)tmp_list->data;
1835       
1836       if ((selection_info->selection == event->selection) &&
1837           (selection_info->widget == widget))
1838         break;
1839       
1840       tmp_list = tmp_list->next;
1841     }
1842   
1843   if (tmp_list)
1844     {
1845       current_selections = g_list_remove_link (current_selections, tmp_list);
1846       g_list_free (tmp_list);
1847       g_free (selection_info);
1848     }
1849   
1850   return TRUE;
1851 }
1852
1853
1854 /*************************************************************
1855  * _gtk_selection_request:
1856  *     Handler for "selection_request_event" 
1857  *   arguments:
1858  *     widget:
1859  *     event:
1860  *   results:
1861  *************************************************************/
1862
1863 gboolean
1864 _gtk_selection_request (GtkWidget *widget,
1865                         GdkEventSelection *event)
1866 {
1867   GdkDisplay *display = gtk_widget_get_display (widget);
1868   GtkIncrInfo *info;
1869   GList *tmp_list;
1870   int i;
1871   gulong selection_max_size;
1872
1873   if (initialize)
1874     gtk_selection_init ();
1875   
1876   selection_max_size = GTK_SELECTION_MAX_SIZE (display);
1877
1878   /* Check if we own selection */
1879   
1880   tmp_list = current_selections;
1881   while (tmp_list)
1882     {
1883       GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data;
1884       
1885       if ((selection_info->selection == event->selection) &&
1886           (selection_info->widget == widget))
1887         break;
1888       
1889       tmp_list = tmp_list->next;
1890     }
1891   
1892   if (tmp_list == NULL)
1893     return FALSE;
1894   
1895   info = g_new (GtkIncrInfo, 1);
1896
1897   g_object_ref (widget);
1898   
1899   info->selection = event->selection;
1900   info->num_incrs = 0;
1901   
1902   /* Create GdkWindow structure for the requestor */
1903   
1904   info->requestor = gdk_window_lookup_for_display (display,
1905                                                    event->requestor);
1906   if (!info->requestor)
1907     info->requestor = gdk_window_foreign_new_for_display (display,
1908                                                           event->requestor);
1909   
1910   /* Determine conversions we need to perform */
1911   
1912   if (event->target == gtk_selection_atoms[MULTIPLE])
1913     {
1914       GdkAtom  type;
1915       guchar  *mult_atoms;
1916       gint     format;
1917       gint     length;
1918       
1919       mult_atoms = NULL;
1920       
1921       gdk_error_trap_push ();
1922       if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */
1923                              0, selection_max_size, FALSE,
1924                              &type, &format, &length, &mult_atoms))
1925         {
1926           gdk_selection_send_notify_for_display (display,
1927                                                  event->requestor, 
1928                                                  event->selection,
1929                                                  event->target, 
1930                                                  GDK_NONE, 
1931                                                  event->time);
1932           g_free (mult_atoms);
1933           g_free (info);
1934           return TRUE;
1935         }
1936       gdk_error_trap_pop ();
1937
1938       /* This is annoying; the ICCCM doesn't specify the property type
1939        * used for the property contents, so the autoconversion for
1940        * ATOM / ATOM_PAIR in GDK doesn't work properly.
1941        */
1942 #ifdef GDK_WINDOWING_X11
1943       if (type != GDK_SELECTION_TYPE_ATOM &&
1944           type != gdk_atom_intern_static_string ("ATOM_PAIR"))
1945         {
1946           info->num_conversions = length / (2*sizeof (glong));
1947           info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1948           
1949           for (i=0; i<info->num_conversions; i++)
1950             {
1951               info->conversions[i].target = gdk_x11_xatom_to_atom_for_display (display,
1952                                                                                ((glong *)mult_atoms)[2*i]);
1953               info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display,
1954                                                                                  ((glong *)mult_atoms)[2*i + 1]);
1955             }
1956
1957           g_free (mult_atoms);
1958         }
1959       else
1960 #endif
1961         {
1962           info->num_conversions = length / (2*sizeof (GdkAtom));
1963           info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1964           
1965           for (i=0; i<info->num_conversions; i++)
1966             {
1967               info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
1968               info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
1969             }
1970         }
1971     }
1972   else                          /* only a single conversion */
1973     {
1974       info->conversions = g_new (GtkIncrConversion, 1);
1975       info->num_conversions = 1;
1976       info->conversions[0].target = event->target;
1977       info->conversions[0].property = event->property;
1978     }
1979   
1980   /* Loop through conversions and determine which of these are big
1981      enough to require doing them via INCR */
1982   for (i=0; i<info->num_conversions; i++)
1983     {
1984       GtkSelectionData data;
1985       glong items;
1986       
1987       data.selection = event->selection;
1988       data.target = info->conversions[i].target;
1989       data.data = NULL;
1990       data.length = -1;
1991       data.display = gtk_widget_get_display (widget);
1992       
1993 #ifdef DEBUG_SELECTION
1994       g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
1995                  event->selection, 
1996                  info->conversions[i].target,
1997                  gdk_atom_name (info->conversions[i].target),
1998                  event->requestor, info->conversions[i].property);
1999 #endif
2000       
2001       gtk_selection_invoke_handler (widget, &data, event->time);
2002       
2003       if (data.length < 0)
2004         {
2005           info->conversions[i].property = GDK_NONE;
2006           continue;
2007         }
2008       
2009       g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
2010       
2011       items = data.length / gtk_selection_bytes_per_item (data.format);
2012       
2013       if (data.length > selection_max_size)
2014         {
2015           /* Sending via INCR */
2016 #ifdef DEBUG_SELECTION
2017           g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n",
2018                      data.length, selection_max_size);
2019 #endif
2020           
2021           info->conversions[i].offset = 0;
2022           info->conversions[i].data = data;
2023           info->num_incrs++;
2024           
2025           gdk_property_change (info->requestor, 
2026                                info->conversions[i].property,
2027                                gtk_selection_atoms[INCR],
2028                                32,
2029                                GDK_PROP_MODE_REPLACE,
2030                                (guchar *)&items, 1);
2031         }
2032       else
2033         {
2034           info->conversions[i].offset = -1;
2035           
2036           gdk_property_change (info->requestor, 
2037                                info->conversions[i].property,
2038                                data.type,
2039                                data.format,
2040                                GDK_PROP_MODE_REPLACE,
2041                                data.data, items);
2042           
2043           g_free (data.data);
2044         }
2045     }
2046   
2047   /* If we have some INCR's, we need to send the rest of the data in
2048      a callback */
2049   
2050   if (info->num_incrs > 0)
2051     {
2052       /* FIXME: this could be dangerous if window doesn't still
2053          exist */
2054       
2055 #ifdef DEBUG_SELECTION
2056       g_message ("Starting INCR...");
2057 #endif
2058       
2059       gdk_window_set_events (info->requestor,
2060                              gdk_window_get_events (info->requestor) |
2061                              GDK_PROPERTY_CHANGE_MASK);
2062       current_incrs = g_list_append (current_incrs, info);
2063       g_timeout_add (1000, (GSourceFunc) gtk_selection_incr_timeout, info);
2064     }
2065   
2066   /* If it was a MULTIPLE request, set the property to indicate which
2067      conversions succeeded */
2068   if (event->target == gtk_selection_atoms[MULTIPLE])
2069     {
2070       GdkAtom *mult_atoms = g_new (GdkAtom, 2 * info->num_conversions);
2071       for (i = 0; i < info->num_conversions; i++)
2072         {
2073           mult_atoms[2*i] = info->conversions[i].target;
2074           mult_atoms[2*i+1] = info->conversions[i].property;
2075         }
2076       
2077       gdk_property_change (info->requestor, event->property,
2078                            gdk_atom_intern_static_string ("ATOM_PAIR"), 32, 
2079                            GDK_PROP_MODE_REPLACE,
2080                            (guchar *)mult_atoms, 2*info->num_conversions);
2081       g_free (mult_atoms);
2082     }
2083
2084   if (info->num_conversions == 1 &&
2085       info->conversions[0].property == GDK_NONE)
2086     {
2087       /* Reject the entire conversion */
2088       gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
2089                                              event->requestor, 
2090                                              event->selection, 
2091                                              event->target, 
2092                                              GDK_NONE, 
2093                                              event->time);
2094     }
2095   else
2096     {
2097       gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
2098                                              event->requestor, 
2099                                              event->selection,
2100                                              event->target,
2101                                              event->property, 
2102                                              event->time);
2103     }
2104
2105   if (info->num_incrs == 0)
2106     {
2107       g_free (info->conversions);
2108       g_free (info);
2109     }
2110
2111   g_object_unref (widget);
2112   
2113   return TRUE;
2114 }
2115
2116 /*************************************************************
2117  * _gtk_selection_incr_event:
2118  *     Called whenever an PropertyNotify event occurs for an 
2119  *     GdkWindow with user_data == NULL. These will be notifications
2120  *     that a window we are sending the selection to via the
2121  *     INCR protocol has deleted a property and is ready for
2122  *     more data.
2123  *
2124  *   arguments:
2125  *     window:  the requestor window
2126  *     event:   the property event structure
2127  *
2128  *   results:
2129  *************************************************************/
2130
2131 gboolean
2132 _gtk_selection_incr_event (GdkWindow       *window,
2133                            GdkEventProperty *event)
2134 {
2135   GList *tmp_list;
2136   GtkIncrInfo *info = NULL;
2137   gint num_bytes;
2138   guchar *buffer;
2139   gulong selection_max_size;
2140   
2141   int i;
2142   
2143   if (event->state != GDK_PROPERTY_DELETE)
2144     return FALSE;
2145   
2146 #ifdef DEBUG_SELECTION
2147   g_message ("PropertyDelete, property %ld", event->atom);
2148 #endif
2149
2150   selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window));  
2151
2152   /* Now find the appropriate ongoing INCR */
2153   tmp_list = current_incrs;
2154   while (tmp_list)
2155     {
2156       info = (GtkIncrInfo *)tmp_list->data;
2157       if (info->requestor == event->window)
2158         break;
2159       
2160       tmp_list = tmp_list->next;
2161     }
2162   
2163   if (tmp_list == NULL)
2164     return FALSE;
2165   
2166   /* Find out which target this is for */
2167   for (i=0; i<info->num_conversions; i++)
2168     {
2169       if (info->conversions[i].property == event->atom &&
2170           info->conversions[i].offset != -1)
2171         {
2172           int bytes_per_item;
2173           
2174           info->idle_time = 0;
2175           
2176           if (info->conversions[i].offset == -2) /* only the last 0-length
2177                                                     piece*/
2178             {
2179               num_bytes = 0;
2180               buffer = NULL;
2181             }
2182           else
2183             {
2184               num_bytes = info->conversions[i].data.length -
2185                 info->conversions[i].offset;
2186               buffer = info->conversions[i].data.data + 
2187                 info->conversions[i].offset;
2188               
2189               if (num_bytes > selection_max_size)
2190                 {
2191                   num_bytes = selection_max_size;
2192                   info->conversions[i].offset += selection_max_size;
2193                 }
2194               else
2195                 info->conversions[i].offset = -2;
2196             }
2197 #ifdef DEBUG_SELECTION
2198           g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
2199                      num_bytes, info->conversions[i].offset, 
2200                      GDK_WINDOW_XWINDOW(info->requestor), event->atom);
2201 #endif
2202
2203           bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
2204           gdk_property_change (info->requestor, event->atom,
2205                                info->conversions[i].data.type,
2206                                info->conversions[i].data.format,
2207                                GDK_PROP_MODE_REPLACE,
2208                                buffer,
2209                                num_bytes / bytes_per_item);
2210           
2211           if (info->conversions[i].offset == -2)
2212             {
2213               g_free (info->conversions[i].data.data);
2214               info->conversions[i].data.data = NULL;
2215             }
2216           
2217           if (num_bytes == 0)
2218             {
2219               info->num_incrs--;
2220               info->conversions[i].offset = -1;
2221             }
2222         }
2223     }
2224   
2225   /* Check if we're finished with all the targets */
2226   
2227   if (info->num_incrs == 0)
2228     {
2229       current_incrs = g_list_remove_link (current_incrs, tmp_list);
2230       g_list_free (tmp_list);
2231       /* Let the timeout free it */
2232     }
2233   
2234   return TRUE;
2235 }
2236
2237 /*************************************************************
2238  * gtk_selection_incr_timeout:
2239  *     Timeout callback for the sending portion of the INCR
2240  *     protocol
2241  *   arguments:
2242  *     info:    Information about this incr
2243  *   results:
2244  *************************************************************/
2245
2246 static gint
2247 gtk_selection_incr_timeout (GtkIncrInfo *info)
2248 {
2249   GList *tmp_list;
2250   gboolean retval;
2251
2252   GDK_THREADS_ENTER ();
2253   
2254   /* Determine if retrieval has finished by checking if it still in
2255      list of pending retrievals */
2256   
2257   tmp_list = current_incrs;
2258   while (tmp_list)
2259     {
2260       if (info == (GtkIncrInfo *)tmp_list->data)
2261         break;
2262       tmp_list = tmp_list->next;
2263     }
2264   
2265   /* If retrieval is finished */
2266   if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2267     {
2268       if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2269         {
2270           current_incrs = g_list_remove_link (current_incrs, tmp_list);
2271           g_list_free (tmp_list);
2272         }
2273       
2274       g_free (info->conversions);
2275       /* FIXME: we should check if requestor window is still in use,
2276          and if not, remove it? */
2277       
2278       g_free (info);
2279       
2280       retval =  FALSE;          /* remove timeout */
2281     }
2282   else
2283     {
2284       info->idle_time++;
2285       
2286       retval = TRUE;            /* timeout will happen again */
2287     }
2288   
2289   GDK_THREADS_LEAVE ();
2290
2291   return retval;
2292 }
2293
2294 /*************************************************************
2295  * _gtk_selection_notify:
2296  *     Handler for "selection_notify_event" signals on windows
2297  *     where a retrieval is currently in process. The selection
2298  *     owner has responded to our conversion request.
2299  *   arguments:
2300  *     widget:          Widget getting signal
2301  *     event:           Selection event structure
2302  *     info:            Information about this retrieval
2303  *   results:
2304  *     was event handled?
2305  *************************************************************/
2306
2307 gboolean
2308 _gtk_selection_notify (GtkWidget               *widget,
2309                        GdkEventSelection *event)
2310 {
2311   GList *tmp_list;
2312   GtkRetrievalInfo *info = NULL;
2313   guchar  *buffer = NULL;
2314   gint length;
2315   GdkAtom type;
2316   gint    format;
2317   
2318 #ifdef DEBUG_SELECTION
2319   g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
2320              event->selection, event->target, event->property);
2321 #endif
2322   
2323   tmp_list = current_retrievals;
2324   while (tmp_list)
2325     {
2326       info = (GtkRetrievalInfo *)tmp_list->data;
2327       if (info->widget == widget && info->selection == event->selection)
2328         break;
2329       tmp_list = tmp_list->next;
2330     }
2331   
2332   if (!tmp_list)                /* no retrieval in progress */
2333     return FALSE;
2334
2335   if (event->property != GDK_NONE)
2336     length = gdk_selection_property_get (widget->window, &buffer, 
2337                                          &type, &format);
2338   else
2339     length = 0; /* silence gcc */
2340   
2341   if (event->property == GDK_NONE || buffer == NULL)
2342     {
2343       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2344       g_list_free (tmp_list);
2345       /* structure will be freed in timeout */
2346       gtk_selection_retrieval_report (info,
2347                                       GDK_NONE, 0, NULL, -1, event->time);
2348       
2349       return TRUE;
2350     }
2351   
2352   if (type == gtk_selection_atoms[INCR])
2353     {
2354       /* The remainder of the selection will come through PropertyNotify
2355          events */
2356
2357       info->notify_time = event->time;
2358       info->idle_time = 0;
2359       info->offset = 0;         /* Mark as OK to proceed */
2360       gdk_window_set_events (widget->window,
2361                              gdk_window_get_events (widget->window)
2362                              | GDK_PROPERTY_CHANGE_MASK);
2363     }
2364   else
2365     {
2366       /* We don't delete the info structure - that will happen in timeout */
2367       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2368       g_list_free (tmp_list);
2369       
2370       info->offset = length;
2371       gtk_selection_retrieval_report (info,
2372                                       type, format, 
2373                                       buffer, length, event->time);
2374     }
2375   
2376   gdk_property_delete (widget->window, event->property);
2377   
2378   g_free (buffer);
2379   
2380   return TRUE;
2381 }
2382
2383 /*************************************************************
2384  * _gtk_selection_property_notify:
2385  *     Handler for "property_notify_event" signals on windows
2386  *     where a retrieval is currently in process. The selection
2387  *     owner has added more data.
2388  *   arguments:
2389  *     widget:          Widget getting signal
2390  *     event:           Property event structure
2391  *     info:            Information about this retrieval
2392  *   results:
2393  *     was event handled?
2394  *************************************************************/
2395
2396 gboolean
2397 _gtk_selection_property_notify (GtkWidget       *widget,
2398                                 GdkEventProperty *event)
2399 {
2400   GList *tmp_list;
2401   GtkRetrievalInfo *info = NULL;
2402   guchar *new_buffer;
2403   int length;
2404   GdkAtom type;
2405   gint    format;
2406   
2407   g_return_val_if_fail (widget != NULL, FALSE);
2408   g_return_val_if_fail (event != NULL, FALSE);
2409
2410 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
2411   if ((event->state != GDK_PROPERTY_NEW_VALUE) ||  /* property was deleted */
2412       (event->atom != gdk_atom_intern_static_string ("GDK_SELECTION"))) /* not the right property */
2413 #endif
2414     return FALSE;
2415   
2416 #ifdef DEBUG_SELECTION
2417   g_message ("PropertyNewValue, property %ld",
2418              event->atom);
2419 #endif
2420   
2421   tmp_list = current_retrievals;
2422   while (tmp_list)
2423     {
2424       info = (GtkRetrievalInfo *)tmp_list->data;
2425       if (info->widget == widget)
2426         break;
2427       tmp_list = tmp_list->next;
2428     }
2429   
2430   if (!tmp_list)                /* No retrieval in progress */
2431     return FALSE;
2432   
2433   if (info->offset < 0)         /* We haven't got the SelectionNotify
2434                                    for this retrieval yet */
2435     return FALSE;
2436   
2437   info->idle_time = 0;
2438   
2439   length = gdk_selection_property_get (widget->window, &new_buffer, 
2440                                        &type, &format);
2441   gdk_property_delete (widget->window, event->atom);
2442   
2443   /* We could do a lot better efficiency-wise by paying attention to
2444      what length was sent in the initial INCR transaction, instead of
2445      doing memory allocation at every step. But its only guaranteed to
2446      be a _lower bound_ (pretty useless!) */
2447   
2448   if (length == 0 || type == GDK_NONE)          /* final zero length portion */
2449     {
2450       /* Info structure will be freed in timeout */
2451       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2452       g_list_free (tmp_list);
2453       gtk_selection_retrieval_report (info,
2454                                       type, format, 
2455                                       (type == GDK_NONE) ?  NULL : info->buffer,
2456                                       (type == GDK_NONE) ?  -1 : info->offset,
2457                                       info->notify_time);
2458     }
2459   else                          /* append on newly arrived data */
2460     {
2461       if (!info->buffer)
2462         {
2463 #ifdef DEBUG_SELECTION
2464           g_message ("Start - Adding %d bytes at offset 0",
2465                      length);
2466 #endif
2467           info->buffer = new_buffer;
2468           info->offset = length;
2469         }
2470       else
2471         {
2472           
2473 #ifdef DEBUG_SELECTION
2474           g_message ("Appending %d bytes at offset %d",
2475                      length,info->offset);
2476 #endif
2477           /* We copy length+1 bytes to preserve guaranteed null termination */
2478           info->buffer = g_realloc (info->buffer, info->offset+length+1);
2479           memcpy (info->buffer + info->offset, new_buffer, length+1);
2480           info->offset += length;
2481           g_free (new_buffer);
2482         }
2483     }
2484   
2485   return TRUE;
2486 }
2487
2488 /*************************************************************
2489  * gtk_selection_retrieval_timeout:
2490  *     Timeout callback while receiving a selection.
2491  *   arguments:
2492  *     info:    Information about this retrieval
2493  *   results:
2494  *************************************************************/
2495
2496 static gint
2497 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
2498 {
2499   GList *tmp_list;
2500   gboolean retval;
2501
2502   GDK_THREADS_ENTER ();
2503   
2504   /* Determine if retrieval has finished by checking if it still in
2505      list of pending retrievals */
2506   
2507   tmp_list = current_retrievals;
2508   while (tmp_list)
2509     {
2510       if (info == (GtkRetrievalInfo *)tmp_list->data)
2511         break;
2512       tmp_list = tmp_list->next;
2513     }
2514   
2515   /* If retrieval is finished */
2516   if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2517     {
2518       if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2519         {
2520           current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2521           g_list_free (tmp_list);
2522           gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
2523         }
2524       
2525       g_free (info->buffer);
2526       g_free (info);
2527       
2528       retval =  FALSE;          /* remove timeout */
2529     }
2530   else
2531     {
2532       info->idle_time++;
2533       
2534       retval =  TRUE;           /* timeout will happen again */
2535     }
2536
2537   GDK_THREADS_LEAVE ();
2538
2539   return retval;
2540 }
2541
2542 /*************************************************************
2543  * gtk_selection_retrieval_report:
2544  *     Emits a "selection_received" signal.
2545  *   arguments:
2546  *     info:      information about the retrieval that completed
2547  *     buffer:    buffer containing data (NULL => errror)
2548  *     time:      timestamp for data in buffer
2549  *   results:
2550  *************************************************************/
2551
2552 static void
2553 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
2554                                 GdkAtom type, gint format, 
2555                                 guchar *buffer, gint length,
2556                                 guint32 time)
2557 {
2558   GtkSelectionData data;
2559   
2560   data.selection = info->selection;
2561   data.target = info->target;
2562   data.type = type;
2563   data.format = format;
2564   
2565   data.length = length;
2566   data.data = buffer;
2567   data.display = gtk_widget_get_display (info->widget);
2568   
2569   g_signal_emit_by_name (info->widget,
2570                          "selection_received", 
2571                          &data, time);
2572 }
2573
2574 /*************************************************************
2575  * gtk_selection_invoke_handler:
2576  *     Finds and invokes handler for specified
2577  *     widget/selection/target combination, calls 
2578  *     gtk_selection_default_handler if none exists.
2579  *
2580  *   arguments:
2581  *     widget:      selection owner
2582  *     data:        selection data [INOUT]
2583  *     time:        time from requeset
2584  *     
2585  *   results:
2586  *     Number of bytes written to buffer, -1 if error
2587  *************************************************************/
2588
2589 static void
2590 gtk_selection_invoke_handler (GtkWidget        *widget,
2591                               GtkSelectionData *data,
2592                               guint             time)
2593 {
2594   GtkTargetList *target_list;
2595   guint info;
2596   
2597
2598   g_return_if_fail (widget != NULL);
2599
2600   target_list = gtk_selection_target_list_get (widget, data->selection);
2601   if (target_list && 
2602       gtk_target_list_find (target_list, data->target, &info))
2603     {
2604       g_signal_emit_by_name (widget,
2605                              "selection_get",
2606                              data,
2607                              info, time);
2608     }
2609   else
2610     gtk_selection_default_handler (widget, data);
2611 }
2612
2613 /*************************************************************
2614  * gtk_selection_default_handler:
2615  *     Handles some default targets that exist for any widget
2616  *     If it can't fit results into buffer, returns -1. This
2617  *     won't happen in any conceivable case, since it would
2618  *     require 1000 selection targets!
2619  *
2620  *   arguments:
2621  *     widget:      selection owner
2622  *     data:        selection data [INOUT]
2623  *
2624  *************************************************************/
2625
2626 static void
2627 gtk_selection_default_handler (GtkWidget        *widget,
2628                                GtkSelectionData *data)
2629 {
2630   if (data->target == gtk_selection_atoms[TIMESTAMP])
2631     {
2632       /* Time which was used to obtain selection */
2633       GList *tmp_list;
2634       GtkSelectionInfo *selection_info;
2635       
2636       tmp_list = current_selections;
2637       while (tmp_list)
2638         {
2639           selection_info = (GtkSelectionInfo *)tmp_list->data;
2640           if ((selection_info->widget == widget) &&
2641               (selection_info->selection == data->selection))
2642             {
2643               gulong time = selection_info->time;
2644
2645               gtk_selection_data_set (data,
2646                                       GDK_SELECTION_TYPE_INTEGER,
2647                                       32,
2648                                       (guchar *)&time,
2649                                       sizeof (time));
2650               return;
2651             }
2652           
2653           tmp_list = tmp_list->next;
2654         }
2655       
2656       data->length = -1;
2657     }
2658   else if (data->target == gtk_selection_atoms[TARGETS])
2659     {
2660       /* List of all targets supported for this widget/selection pair */
2661       GdkAtom *p;
2662       guint count;
2663       GList *tmp_list;
2664       GtkTargetList *target_list;
2665       GtkTargetPair *pair;
2666       
2667       target_list = gtk_selection_target_list_get (widget,
2668                                                    data->selection);
2669       count = g_list_length (target_list->list) + 3;
2670       
2671       data->type = GDK_SELECTION_TYPE_ATOM;
2672       data->format = 32;
2673       data->length = count * sizeof (GdkAtom);
2674
2675       /* selection data is always terminated by a trailing \0
2676        */
2677       p = g_malloc (data->length + 1);
2678       data->data = (guchar *)p;
2679       data->data[data->length] = '\0';
2680       
2681       *p++ = gtk_selection_atoms[TIMESTAMP];
2682       *p++ = gtk_selection_atoms[TARGETS];
2683       *p++ = gtk_selection_atoms[MULTIPLE];
2684       
2685       tmp_list = target_list->list;
2686       while (tmp_list)
2687         {
2688           pair = (GtkTargetPair *)tmp_list->data;
2689           *p++ = pair->target;
2690           
2691           tmp_list = tmp_list->next;
2692         }
2693     }
2694   else
2695     {
2696       data->length = -1;
2697     }
2698 }
2699
2700
2701 /**
2702  * gtk_selection_data_copy:
2703  * @data: a pointer to a #GtkSelectionData structure.
2704  * 
2705  * Makes a copy of a #GtkSelectionData structure and its data.
2706  * 
2707  * Return value: a pointer to a copy of @data.
2708  **/
2709 GtkSelectionData*
2710 gtk_selection_data_copy (GtkSelectionData *data)
2711 {
2712   GtkSelectionData *new_data;
2713   
2714   g_return_val_if_fail (data != NULL, NULL);
2715   
2716   new_data = g_new (GtkSelectionData, 1);
2717   *new_data = *data;
2718
2719   if (data->data)
2720     {
2721       new_data->data = g_malloc (data->length + 1);
2722       memcpy (new_data->data, data->data, data->length + 1);
2723     }
2724   
2725   return new_data;
2726 }
2727
2728 /**
2729  * gtk_selection_data_free:
2730  * @data: a pointer to a #GtkSelectionData structure.
2731  * 
2732  * Frees a #GtkSelectionData structure returned from
2733  * gtk_selection_data_copy().
2734  **/
2735 void
2736 gtk_selection_data_free (GtkSelectionData *data)
2737 {
2738   g_return_if_fail (data != NULL);
2739   
2740   if (data->data)
2741     g_free (data->data);
2742   
2743   g_free (data);
2744 }
2745
2746 GType
2747 gtk_selection_data_get_type (void)
2748 {
2749   static GType our_type = 0;
2750   
2751   if (our_type == 0)
2752     our_type = g_boxed_type_register_static (I_("GtkSelectionData"),
2753                                              (GBoxedCopyFunc) gtk_selection_data_copy,
2754                                              (GBoxedFreeFunc) gtk_selection_data_free);
2755
2756   return our_type;
2757 }
2758
2759 static int 
2760 gtk_selection_bytes_per_item (gint format)
2761 {
2762   switch (format)
2763     {
2764     case 8:
2765       return sizeof (char);
2766       break;
2767     case 16:
2768       return sizeof (short);
2769       break;
2770     case 32:
2771       return sizeof (long);
2772       break;
2773     default:
2774       g_assert_not_reached();
2775     }
2776   return 0;
2777 }
2778
2779 #define __GTK_SELECTION_C__
2780 #include "gtkaliasdef.c"