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