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