]> Pileus Git - ~andy/gtk/blob - gtk/gtkselection.c
b3013aa0c6a237b5f64975167a125135bcd2d0b4
[~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       gpointer owner_widget_ptr;
1071       GtkSelectionData selection_data;
1072       
1073       selection_data.selection = selection;
1074       selection_data.target = target;
1075       selection_data.data = NULL;
1076       selection_data.length = -1;
1077       selection_data.display = display;
1078       
1079       gdk_window_get_user_data (owner_window, &owner_widget_ptr);
1080       owner_widget = owner_widget_ptr;
1081       
1082       if (owner_widget != NULL)
1083         {
1084           gtk_selection_invoke_handler (owner_widget, 
1085                                         &selection_data,
1086                                         time_);
1087           
1088           gtk_selection_retrieval_report (info,
1089                                           selection_data.type, 
1090                                           selection_data.format,
1091                                           selection_data.data,
1092                                           selection_data.length,
1093                                           time_);
1094           
1095           g_free (selection_data.data);
1096           selection_data.data = NULL;
1097           selection_data.length = -1;
1098           
1099           g_slice_free (GtkRetrievalInfo, info);
1100           return TRUE;
1101         }
1102     }
1103   
1104   /* Otherwise, we need to go through X */
1105   
1106   current_retrievals = g_list_append (current_retrievals, info);
1107   gdk_selection_convert (widget->window, selection, target, time_);
1108   gdk_threads_add_timeout (1000,
1109       (GSourceFunc) gtk_selection_retrieval_timeout, info);
1110   
1111   return TRUE;
1112 }
1113
1114 /**
1115  * gtk_selection_data_get_target:
1116  * @selection_data: a pointer to a #GtkSelectionData structure.
1117  *
1118  * Retrieves the target of the selection.
1119  *
1120  * Returns:  the target of the selection.
1121  *
1122  * Since: 2.14
1123  **/
1124 GdkAtom
1125 gtk_selection_data_get_target (GtkSelectionData *selection_data)
1126 {
1127   g_return_val_if_fail (selection_data != NULL, 0);
1128
1129   return selection_data->target;
1130 }
1131
1132 /**
1133  * gtk_selection_data_get_data_type:
1134  * @selection_data: a pointer to a #GtkSelectionData structure.
1135  *
1136  * Retrieves the data type of the selection.
1137  *
1138  * Returns:  the data type of the selection.
1139  *
1140  * Since: 2.14
1141  **/
1142 GdkAtom
1143 gtk_selection_data_get_data_type (GtkSelectionData *selection_data)
1144 {
1145   g_return_val_if_fail (selection_data != NULL, 0);
1146
1147   return selection_data->type;
1148 }
1149
1150 /**
1151  * gtk_selection_data_get_format:
1152  * @selection_data: a pointer to a #GtkSelectionData structure.
1153  *
1154  * Retrieves the format of the selection.
1155  *
1156  * Returns: the format of the selection.
1157  *
1158  * Since: 2.14
1159  **/
1160 gint
1161 gtk_selection_data_get_format (GtkSelectionData *selection_data)
1162 {
1163   g_return_val_if_fail (selection_data != NULL, 0);
1164
1165   return selection_data->format;
1166 }
1167
1168 /**
1169  * gtk_selection_data_get_data:
1170  * @selection_data: a pointer to a #GtkSelectionData structure.
1171  *
1172  * Retrieves the raw data of the selection.
1173  *
1174  * Returns: the raw data of the selection.
1175  *
1176  * Since: 2.14
1177  **/
1178 const guchar*
1179 gtk_selection_data_get_data (GtkSelectionData *selection_data)
1180 {
1181   g_return_val_if_fail (selection_data != NULL, NULL);
1182
1183   return selection_data->data;
1184 }
1185
1186 /**
1187  * gtk_selection_data_get_length:
1188  * @selection_data: a pointer to a #GtkSelectionData structure.
1189  *
1190  * Retrieves the length of the raw data of the selection.
1191  *
1192  * Returns: the length of the data of the selection.
1193  *
1194  * Since: 2.14
1195  */
1196 gint
1197 gtk_selection_data_get_length (GtkSelectionData *selection_data)
1198 {
1199   g_return_val_if_fail (selection_data != NULL, -1);
1200
1201   return selection_data->length;
1202 }
1203
1204 /**
1205  * gtk_selection_data_get_display:
1206  * @selection_data: a pointer to a #GtkSelectionData structure.
1207  *
1208  * Retrieves the display of the selection.
1209  *
1210  * Returns: the display of the selection.
1211  *
1212  * Since: 2.14
1213  **/
1214 GdkDisplay *
1215 gtk_selection_data_get_display (GtkSelectionData *selection_data)
1216 {
1217   g_return_val_if_fail (selection_data != NULL, NULL);
1218
1219   return selection_data->display;
1220 }
1221
1222 /**
1223  * gtk_selection_data_set:
1224  * @selection_data: a pointer to a #GtkSelectionData structure.
1225  * @type: the type of selection data
1226  * @format: format (number of bits in a unit)
1227  * @data: pointer to the data (will be copied)
1228  * @length: length of the data
1229  * 
1230  * Stores new data into a #GtkSelectionData object. Should
1231  * <emphasis>only</emphasis> be called from a selection handler callback.
1232  * Zero-terminates the stored data.
1233  **/
1234 void 
1235 gtk_selection_data_set (GtkSelectionData *selection_data,
1236                         GdkAtom           type,
1237                         gint              format,
1238                         const guchar     *data,
1239                         gint              length)
1240 {
1241   g_return_if_fail (selection_data != NULL);
1242
1243   g_free (selection_data->data);
1244   
1245   selection_data->type = type;
1246   selection_data->format = format;
1247   
1248   if (data)
1249     {
1250       selection_data->data = g_new (guchar, length+1);
1251       memcpy (selection_data->data, data, length);
1252       selection_data->data[length] = 0;
1253     }
1254   else
1255     {
1256       g_return_if_fail (length <= 0);
1257       
1258       if (length < 0)
1259         selection_data->data = NULL;
1260       else
1261         selection_data->data = (guchar *) g_strdup ("");
1262     }
1263   
1264   selection_data->length = length;
1265 }
1266
1267 static gboolean
1268 selection_set_string (GtkSelectionData *selection_data,
1269                       const gchar      *str,
1270                       gint              len)
1271 {
1272   gchar *tmp = g_strndup (str, len);
1273   gchar *latin1 = gdk_utf8_to_string_target (tmp);
1274   g_free (tmp);
1275   
1276   if (latin1)
1277     {
1278       gtk_selection_data_set (selection_data,
1279                               GDK_SELECTION_TYPE_STRING,
1280                               8, (guchar *) latin1, strlen (latin1));
1281       g_free (latin1);
1282       
1283       return TRUE;
1284     }
1285   else
1286     return FALSE;
1287 }
1288
1289 static gboolean
1290 selection_set_compound_text (GtkSelectionData *selection_data,
1291                              const gchar      *str,
1292                              gint              len)
1293 {
1294   gchar *tmp;
1295   guchar *text;
1296   GdkAtom encoding;
1297   gint format;
1298   gint new_length;
1299   gboolean result = FALSE;
1300   
1301   tmp = g_strndup (str, len);
1302   if (gdk_utf8_to_compound_text_for_display (selection_data->display, tmp,
1303                                              &encoding, &format, &text, &new_length))
1304     {
1305       gtk_selection_data_set (selection_data, encoding, format, text, new_length);
1306       gdk_free_compound_text (text);
1307       
1308       result = TRUE;
1309     }
1310
1311   g_free (tmp);
1312
1313   return result;
1314 }
1315
1316 /* Normalize \r and \n into \r\n
1317  */
1318 static gchar *
1319 normalize_to_crlf (const gchar *str, 
1320                    gint         len)
1321 {
1322   GString *result = g_string_sized_new (len);
1323   const gchar *p = str;
1324   const gchar *end = str + len;
1325
1326   while (p < end)
1327     {
1328       if (*p == '\n')
1329         g_string_append_c (result, '\r');
1330
1331       if (*p == '\r')
1332         {
1333           g_string_append_c (result, *p);
1334           p++;
1335           if (p == end || *p != '\n')
1336             g_string_append_c (result, '\n');
1337           if (p == end)
1338             break;
1339         }
1340
1341       g_string_append_c (result, *p);
1342       p++;
1343     }
1344
1345   return g_string_free (result, FALSE);  
1346 }
1347
1348 /* Normalize \r and \r\n into \n
1349  */
1350 static gchar *
1351 normalize_to_lf (gchar *str, 
1352                  gint   len)
1353 {
1354   GString *result = g_string_sized_new (len);
1355   const gchar *p = str;
1356
1357   while (1)
1358     {
1359       if (*p == '\r')
1360         {
1361           p++;
1362           if (*p != '\n')
1363             g_string_append_c (result, '\n');
1364         }
1365
1366       if (*p == '\0')
1367         break;
1368
1369       g_string_append_c (result, *p);
1370       p++;
1371     }
1372
1373   return g_string_free (result, FALSE);  
1374 }
1375
1376 static gboolean
1377 selection_set_text_plain (GtkSelectionData *selection_data,
1378                           const gchar      *str,
1379                           gint              len)
1380 {
1381   const gchar *charset = NULL;
1382   gchar *result;
1383   GError *error = NULL;
1384
1385   result = normalize_to_crlf (str, len);
1386   if (selection_data->target == text_plain_atom)
1387     charset = "ASCII";
1388   else if (selection_data->target == text_plain_locale_atom)
1389     g_get_charset (&charset);
1390
1391   if (charset)
1392     {
1393       gchar *tmp = result;
1394       result = g_convert_with_fallback (tmp, -1, 
1395                                         charset, "UTF-8", 
1396                                         NULL, NULL, NULL, &error);
1397       g_free (tmp);
1398     }
1399
1400   if (!result)
1401     {
1402       g_warning ("Error converting from %s to %s: %s",
1403                  "UTF-8", charset, error->message);
1404       g_error_free (error);
1405       
1406       return FALSE;
1407     }
1408   
1409   gtk_selection_data_set (selection_data,
1410                           selection_data->target, 
1411                           8, (guchar *) result, strlen (result));
1412   g_free (result);
1413   
1414   return TRUE;
1415 }
1416
1417 static guchar *
1418 selection_get_text_plain (GtkSelectionData *selection_data)
1419 {
1420   const gchar *charset = NULL;
1421   gchar *str, *result;
1422   gsize len;
1423   GError *error = NULL;
1424
1425   str = g_strdup ((const gchar *) selection_data->data);
1426   len = selection_data->length;
1427   
1428   if (selection_data->type == text_plain_atom)
1429     charset = "ISO-8859-1";
1430   else if (selection_data->type == text_plain_locale_atom)
1431     g_get_charset (&charset);
1432
1433   if (charset)
1434     {
1435       gchar *tmp = str;
1436       str = g_convert_with_fallback (tmp, len, 
1437                                      "UTF-8", charset,
1438                                      NULL, NULL, &len, &error);
1439       g_free (tmp);
1440
1441       if (!str)
1442         {
1443           g_warning ("Error converting from %s to %s: %s",
1444                      charset, "UTF-8", error->message);
1445           g_error_free (error);
1446
1447           return NULL;
1448         }
1449     }
1450   else if (!g_utf8_validate (str, -1, NULL))
1451     {
1452       g_warning ("Error converting from %s to %s: %s",
1453                  "text/plain;charset=utf-8", "UTF-8", "invalid UTF-8");
1454       g_free (str);
1455
1456       return NULL;
1457     }
1458
1459   result = normalize_to_lf (str, len);
1460   g_free (str);
1461
1462   return (guchar *) result;
1463 }
1464
1465 /**
1466  * gtk_selection_data_set_text:
1467  * @selection_data: a #GtkSelectionData
1468  * @str: a UTF-8 string
1469  * @len: the length of @str, or -1 if @str is nul-terminated.
1470  * 
1471  * Sets the contents of the selection from a UTF-8 encoded string.
1472  * The string is converted to the form determined by
1473  * @selection_data->target.
1474  * 
1475  * Return value: %TRUE if the selection was successfully set,
1476  *   otherwise %FALSE.
1477  **/
1478 gboolean
1479 gtk_selection_data_set_text (GtkSelectionData     *selection_data,
1480                              const gchar          *str,
1481                              gint                  len)
1482 {
1483   g_return_val_if_fail (selection_data != NULL, FALSE);
1484
1485   if (len < 0)
1486     len = strlen (str);
1487   
1488   init_atoms ();
1489
1490   if (selection_data->target == utf8_atom)
1491     {
1492       gtk_selection_data_set (selection_data,
1493                               utf8_atom,
1494                               8, (guchar *)str, len);
1495       return TRUE;
1496     }
1497   else if (selection_data->target == GDK_TARGET_STRING)
1498     {
1499       return selection_set_string (selection_data, str, len);
1500     }
1501   else if (selection_data->target == ctext_atom ||
1502            selection_data->target == text_atom)
1503     {
1504       if (selection_set_compound_text (selection_data, str, len))
1505         return TRUE;
1506       else if (selection_data->target == text_atom)
1507         return selection_set_string (selection_data, str, len);
1508     }
1509   else if (selection_data->target == text_plain_atom ||
1510            selection_data->target == text_plain_utf8_atom ||
1511            selection_data->target == text_plain_locale_atom)
1512     {
1513       return selection_set_text_plain (selection_data, str, len);
1514     }
1515
1516   return FALSE;
1517 }
1518
1519 /**
1520  * gtk_selection_data_get_text:
1521  * @selection_data: a #GtkSelectionData
1522  * 
1523  * Gets the contents of the selection data as a UTF-8 string.
1524  * 
1525  * Return value: if the selection data contained a recognized
1526  *   text type and it could be converted to UTF-8, a newly allocated
1527  *   string containing the converted text, otherwise %NULL.
1528  *   If the result is non-%NULL it must be freed with g_free().
1529  **/
1530 guchar *
1531 gtk_selection_data_get_text (GtkSelectionData *selection_data)
1532 {
1533   guchar *result = NULL;
1534
1535   g_return_val_if_fail (selection_data != NULL, NULL);
1536
1537   init_atoms ();
1538   
1539   if (selection_data->length >= 0 &&
1540       (selection_data->type == GDK_TARGET_STRING ||
1541        selection_data->type == ctext_atom ||
1542        selection_data->type == utf8_atom))
1543     {
1544       gchar **list;
1545       gint i;
1546       gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1547                                                                selection_data->type,
1548                                                                selection_data->format, 
1549                                                                selection_data->data,
1550                                                                selection_data->length,
1551                                                                &list);
1552       if (count > 0)
1553         result = (guchar *) list[0];
1554
1555       for (i = 1; i < count; i++)
1556         g_free (list[i]);
1557       g_free (list);
1558     }
1559   else if (selection_data->length >= 0 &&
1560            (selection_data->type == text_plain_atom ||
1561             selection_data->type == text_plain_utf8_atom ||
1562             selection_data->type == text_plain_locale_atom))
1563     {
1564       result = selection_get_text_plain (selection_data);
1565     }
1566
1567   return result;
1568 }
1569
1570 /**
1571  * gtk_selection_data_set_pixbuf:
1572  * @selection_data: a #GtkSelectionData
1573  * @pixbuf: a #GdkPixbuf
1574  * 
1575  * Sets the contents of the selection from a #GdkPixbuf
1576  * The pixbuf is converted to the form determined by
1577  * @selection_data->target.
1578  * 
1579  * Return value: %TRUE if the selection was successfully set,
1580  *   otherwise %FALSE.
1581  *
1582  * Since: 2.6
1583  **/
1584 gboolean
1585 gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data,
1586                                GdkPixbuf        *pixbuf)
1587 {
1588   GSList *formats, *f;
1589   gchar **mimes, **m;
1590   GdkAtom atom;
1591   gboolean result;
1592   gchar *str, *type;
1593   gsize len;
1594
1595   g_return_val_if_fail (selection_data != NULL, FALSE);
1596   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
1597
1598   formats = gdk_pixbuf_get_formats ();
1599
1600   for (f = formats; f; f = f->next)
1601     {
1602       GdkPixbufFormat *fmt = f->data;
1603
1604       mimes = gdk_pixbuf_format_get_mime_types (fmt);
1605       for (m = mimes; *m; m++)
1606         {
1607           atom = gdk_atom_intern (*m, FALSE);
1608           if (selection_data->target == atom)
1609             {
1610               str = NULL;
1611               type = gdk_pixbuf_format_get_name (fmt);
1612               result = gdk_pixbuf_save_to_buffer (pixbuf, &str, &len,
1613                                                   type, NULL,
1614                                                   ((strcmp (type, "png") == 0) ?
1615                                                    "compression" : NULL), "2",
1616                                                   NULL);
1617               if (result)
1618                 gtk_selection_data_set (selection_data,
1619                                         atom, 8, (guchar *)str, len);
1620               g_free (type);
1621               g_free (str);
1622               g_strfreev (mimes);
1623               g_slist_free (formats);
1624
1625               return result;
1626             }
1627         }
1628
1629       g_strfreev (mimes);
1630     }
1631
1632   g_slist_free (formats);
1633  
1634   return FALSE;
1635 }
1636
1637 /**
1638  * gtk_selection_data_get_pixbuf:
1639  * @selection_data: a #GtkSelectionData
1640  * 
1641  * Gets the contents of the selection data as a #GdkPixbuf.
1642  * 
1643  * Return value: if the selection data contained a recognized
1644  *   image type and it could be converted to a #GdkPixbuf, a 
1645  *   newly allocated pixbuf is returned, otherwise %NULL.
1646  *   If the result is non-%NULL it must be freed with g_object_unref().
1647  *
1648  * Since: 2.6
1649  **/
1650 GdkPixbuf *
1651 gtk_selection_data_get_pixbuf (GtkSelectionData *selection_data)
1652 {
1653   GdkPixbufLoader *loader;
1654   GdkPixbuf *result = NULL;
1655
1656   g_return_val_if_fail (selection_data != NULL, NULL);
1657
1658   if (selection_data->length > 0)
1659     {
1660       loader = gdk_pixbuf_loader_new ();
1661       
1662       gdk_pixbuf_loader_write (loader, 
1663                                selection_data->data,
1664                                selection_data->length,
1665                                NULL);
1666       gdk_pixbuf_loader_close (loader, NULL);
1667       result = gdk_pixbuf_loader_get_pixbuf (loader);
1668       
1669       if (result)
1670         g_object_ref (result);
1671       
1672       g_object_unref (loader);
1673     }
1674
1675   return result;
1676 }
1677
1678 /**
1679  * gtk_selection_data_set_uris:
1680  * @selection_data: a #GtkSelectionData
1681  * @uris: a %NULL-terminated array of strings hilding URIs
1682  * 
1683  * Sets the contents of the selection from a list of URIs.
1684  * The string is converted to the form determined by
1685  * @selection_data->target.
1686  * 
1687  * Return value: %TRUE if the selection was successfully set,
1688  *   otherwise %FALSE.
1689  *
1690  * Since: 2.6
1691  **/
1692 gboolean
1693 gtk_selection_data_set_uris (GtkSelectionData  *selection_data,
1694                              gchar            **uris)
1695 {
1696   g_return_val_if_fail (selection_data != NULL, FALSE);
1697   g_return_val_if_fail (uris != NULL, FALSE);
1698
1699   init_atoms ();
1700
1701   if (selection_data->target == text_uri_list_atom)
1702     {
1703       GString *list;
1704       gint i;
1705       gchar *result;
1706       gsize length;
1707       
1708       list = g_string_new (NULL);
1709       for (i = 0; uris[i]; i++)
1710         {
1711           g_string_append (list, uris[i]);
1712           g_string_append (list, "\r\n");
1713         }
1714
1715       result = g_convert (list->str, list->len,
1716                           "ASCII", "UTF-8", 
1717                           NULL, &length, NULL);
1718       g_string_free (list, TRUE);
1719       
1720       if (result)
1721         {
1722           gtk_selection_data_set (selection_data,
1723                                   text_uri_list_atom,
1724                                   8, (guchar *)result, length);
1725           
1726           g_free (result);
1727
1728           return TRUE;
1729         }
1730     }
1731
1732   return FALSE;
1733 }
1734
1735 /**
1736  * gtk_selection_data_get_uris:
1737  * @selection_data: a #GtkSelectionData
1738  * 
1739  * Gets the contents of the selection data as array of URIs.
1740  * 
1741  * Return value: if the selection data contains a list of
1742  *   URIs, a newly allocated %NULL-terminated string array
1743  *   containing the URIs, otherwise %NULL. If the result is 
1744  *   non-%NULL it must be freed with g_strfreev().
1745  *
1746  * Since: 2.6
1747  **/
1748 gchar **
1749 gtk_selection_data_get_uris (GtkSelectionData *selection_data)
1750 {
1751   gchar **result = NULL;
1752
1753   g_return_val_if_fail (selection_data != NULL, NULL);
1754
1755   init_atoms ();
1756   
1757   if (selection_data->length >= 0 &&
1758       selection_data->type == text_uri_list_atom)
1759     {
1760       gchar **list;
1761       gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1762                                                                utf8_atom,
1763                                                                selection_data->format, 
1764                                                                selection_data->data,
1765                                                                selection_data->length,
1766                                                                &list);
1767       if (count > 0)
1768         result = g_uri_list_extract_uris (list[0]);
1769       
1770       g_strfreev (list);
1771     }
1772
1773   return result;
1774 }
1775
1776
1777 /**
1778  * gtk_selection_data_get_targets:
1779  * @selection_data: a #GtkSelectionData object
1780  * @targets: location to store an array of targets. The result
1781  *           stored here must be freed with g_free().
1782  * @n_atoms: location to store number of items in @targets.
1783  * 
1784  * Gets the contents of @selection_data as an array of targets.
1785  * This can be used to interpret the results of getting
1786  * the standard TARGETS target that is always supplied for
1787  * any selection.
1788  * 
1789  * Return value: %TRUE if @selection_data contains a valid
1790  *    array of targets, otherwise %FALSE.
1791  **/
1792 gboolean
1793 gtk_selection_data_get_targets (GtkSelectionData  *selection_data,
1794                                 GdkAtom          **targets,
1795                                 gint              *n_atoms)
1796 {
1797   g_return_val_if_fail (selection_data != NULL, FALSE);
1798
1799   if (selection_data->length >= 0 &&
1800       selection_data->format == 32 &&
1801       selection_data->type == GDK_SELECTION_TYPE_ATOM)
1802     {
1803       if (targets)
1804         *targets = g_memdup (selection_data->data, selection_data->length);
1805       if (n_atoms)
1806         *n_atoms = selection_data->length / sizeof (GdkAtom);
1807
1808       return TRUE;
1809     }
1810   else
1811     {
1812       if (targets)
1813         *targets = NULL;
1814       if (n_atoms)
1815         *n_atoms = -1;
1816
1817       return FALSE;
1818     }
1819 }
1820
1821 /**
1822  * gtk_targets_include_text:
1823  * @targets: an array of #GdkAtom<!-- -->s
1824  * @n_targets: the length of @targets
1825  * 
1826  * Determines if any of the targets in @targets can be used to
1827  * provide text.
1828  * 
1829  * Return value: %TRUE if @targets include a suitable target for text,
1830  *   otherwise %FALSE.
1831  *
1832  * Since: 2.10
1833  **/
1834 gboolean 
1835 gtk_targets_include_text (GdkAtom *targets,
1836                           gint     n_targets)
1837 {
1838   gint i;
1839   gboolean result = FALSE;
1840
1841   g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
1842
1843   /* Keep in sync with gtk_target_list_add_text_targets()
1844    */
1845  
1846   init_atoms ();
1847  
1848   for (i = 0; i < n_targets; i++)
1849     {
1850       if (targets[i] == utf8_atom ||
1851           targets[i] == text_atom ||
1852           targets[i] == GDK_TARGET_STRING ||
1853           targets[i] == ctext_atom ||
1854           targets[i] == text_plain_atom ||
1855           targets[i] == text_plain_utf8_atom ||
1856           targets[i] == text_plain_locale_atom)
1857         {
1858           result = TRUE;
1859           break;
1860         }
1861     }
1862   
1863   return result;
1864 }
1865
1866 /**
1867  * gtk_targets_include_rich_text:
1868  * @targets: an array of #GdkAtom<!-- -->s
1869  * @n_targets: the length of @targets
1870  * @buffer: a #GtkTextBuffer
1871  *
1872  * Determines if any of the targets in @targets can be used to
1873  * provide rich text.
1874  *
1875  * Return value: %TRUE if @targets include a suitable target for rich text,
1876  *               otherwise %FALSE.
1877  *
1878  * Since: 2.10
1879  **/
1880 gboolean
1881 gtk_targets_include_rich_text (GdkAtom       *targets,
1882                                gint           n_targets,
1883                                GtkTextBuffer *buffer)
1884 {
1885   GdkAtom *rich_targets;
1886   gint n_rich_targets;
1887   gint i, j;
1888   gboolean result = FALSE;
1889
1890   g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
1891   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1892
1893   init_atoms ();
1894
1895   rich_targets = gtk_text_buffer_get_deserialize_formats (buffer,
1896                                                           &n_rich_targets);
1897
1898   for (i = 0; i < n_targets; i++)
1899     {
1900       for (j = 0; j < n_rich_targets; j++)
1901         {
1902           if (targets[i] == rich_targets[j])
1903             {
1904               result = TRUE;
1905               goto done;
1906             }
1907         }
1908     }
1909
1910  done:
1911   g_free (rich_targets);
1912
1913   return result;
1914 }
1915
1916 /**
1917  * gtk_selection_data_targets_include_text:
1918  * @selection_data: a #GtkSelectionData object
1919  * 
1920  * Given a #GtkSelectionData object holding a list of targets,
1921  * determines if any of the targets in @targets can be used to
1922  * provide text.
1923  * 
1924  * Return value: %TRUE if @selection_data holds a list of targets,
1925  *   and a suitable target for text is included, otherwise %FALSE.
1926  **/
1927 gboolean
1928 gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
1929 {
1930   GdkAtom *targets;
1931   gint n_targets;
1932   gboolean result = FALSE;
1933
1934   g_return_val_if_fail (selection_data != NULL, FALSE);
1935
1936   init_atoms ();
1937
1938   if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1939     {
1940       result = gtk_targets_include_text (targets, n_targets);
1941       g_free (targets);
1942     }
1943
1944   return result;
1945 }
1946
1947 /**
1948  * gtk_selection_data_targets_include_rich_text:
1949  * @selection_data: a #GtkSelectionData object
1950  * @buffer: a #GtkTextBuffer
1951  *
1952  * Given a #GtkSelectionData object holding a list of targets,
1953  * determines if any of the targets in @targets can be used to
1954  * provide rich text.
1955  *
1956  * Return value: %TRUE if @selection_data holds a list of targets,
1957  *               and a suitable target for rich text is included,
1958  *               otherwise %FALSE.
1959  *
1960  * Since: 2.10
1961  **/
1962 gboolean
1963 gtk_selection_data_targets_include_rich_text (GtkSelectionData *selection_data,
1964                                               GtkTextBuffer    *buffer)
1965 {
1966   GdkAtom *targets;
1967   gint n_targets;
1968   gboolean result = FALSE;
1969
1970   g_return_val_if_fail (selection_data != NULL, FALSE);
1971   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1972
1973   init_atoms ();
1974
1975   if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1976     {
1977       result = gtk_targets_include_rich_text (targets, n_targets, buffer);
1978       g_free (targets);
1979     }
1980
1981   return result;
1982 }
1983
1984 /**
1985  * gtk_targets_include_image:
1986  * @targets: an array of #GdkAtom<!-- -->s
1987  * @n_targets: the length of @targets
1988  * @writable: whether to accept only targets for which GTK+ knows
1989  *   how to convert a pixbuf into the format
1990  * 
1991  * Determines if any of the targets in @targets can be used to
1992  * provide a #GdkPixbuf.
1993  * 
1994  * Return value: %TRUE if @targets include a suitable target for images,
1995  *   otherwise %FALSE.
1996  *
1997  * Since: 2.10
1998  **/
1999 gboolean 
2000 gtk_targets_include_image (GdkAtom *targets,
2001                            gint     n_targets,
2002                            gboolean writable)
2003 {
2004   GtkTargetList *list;
2005   GList *l;
2006   gint i;
2007   gboolean result = FALSE;
2008
2009   g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
2010
2011   list = gtk_target_list_new (NULL, 0);
2012   gtk_target_list_add_image_targets (list, 0, writable);
2013   for (i = 0; i < n_targets && !result; i++)
2014     {
2015       for (l = list->list; l; l = l->next)
2016         {
2017           GtkTargetPair *pair = (GtkTargetPair *)l->data;
2018           if (pair->target == targets[i])
2019             {
2020               result = TRUE;
2021               break;
2022             }
2023         }
2024     }
2025   gtk_target_list_unref (list);
2026
2027   return result;
2028 }
2029                                     
2030 /**
2031  * gtk_selection_data_targets_include_image:
2032  * @selection_data: a #GtkSelectionData object
2033  * @writable: whether to accept only targets for which GTK+ knows
2034  *   how to convert a pixbuf into the format
2035  * 
2036  * Given a #GtkSelectionData object holding a list of targets,
2037  * determines if any of the targets in @targets can be used to
2038  * provide a #GdkPixbuf.
2039  * 
2040  * Return value: %TRUE if @selection_data holds a list of targets,
2041  *   and a suitable target for images is included, otherwise %FALSE.
2042  *
2043  * Since: 2.6
2044  **/
2045 gboolean 
2046 gtk_selection_data_targets_include_image (GtkSelectionData *selection_data,
2047                                           gboolean          writable)
2048 {
2049   GdkAtom *targets;
2050   gint n_targets;
2051   gboolean result = FALSE;
2052
2053   g_return_val_if_fail (selection_data != NULL, FALSE);
2054
2055   init_atoms ();
2056
2057   if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
2058     {
2059       result = gtk_targets_include_image (targets, n_targets, writable);
2060       g_free (targets);
2061     }
2062
2063   return result;
2064 }
2065
2066 /**
2067  * gtk_targets_include_uri:
2068  * @targets: an array of #GdkAtom<!-- -->s
2069  * @n_targets: the length of @targets
2070  * 
2071  * Determines if any of the targets in @targets can be used to
2072  * provide an uri list.
2073  * 
2074  * Return value: %TRUE if @targets include a suitable target for uri lists,
2075  *   otherwise %FALSE.
2076  *
2077  * Since: 2.10
2078  **/
2079 gboolean 
2080 gtk_targets_include_uri (GdkAtom *targets,
2081                          gint     n_targets)
2082 {
2083   gint i;
2084   gboolean result = FALSE;
2085
2086   g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
2087
2088   /* Keep in sync with gtk_target_list_add_uri_targets()
2089    */
2090
2091   init_atoms ();
2092
2093   for (i = 0; i < n_targets; i++)
2094     {
2095       if (targets[i] == text_uri_list_atom)
2096         {
2097           result = TRUE;
2098           break;
2099         }
2100     }
2101   
2102   return result;
2103 }
2104
2105 /**
2106  * gtk_selection_data_targets_include_uri:
2107  * @selection_data: a #GtkSelectionData object
2108  * 
2109  * Given a #GtkSelectionData object holding a list of targets,
2110  * determines if any of the targets in @targets can be used to
2111  * provide a list or URIs.
2112  * 
2113  * Return value: %TRUE if @selection_data holds a list of targets,
2114  *   and a suitable target for URI lists is included, otherwise %FALSE.
2115  *
2116  * Since: 2.10
2117  **/
2118 gboolean
2119 gtk_selection_data_targets_include_uri (GtkSelectionData *selection_data)
2120 {
2121   GdkAtom *targets;
2122   gint n_targets;
2123   gboolean result = FALSE;
2124
2125   g_return_val_if_fail (selection_data != NULL, FALSE);
2126
2127   init_atoms ();
2128
2129   if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
2130     {
2131       result = gtk_targets_include_uri (targets, n_targets);
2132       g_free (targets);
2133     }
2134
2135   return result;
2136 }
2137
2138           
2139 /*************************************************************
2140  * gtk_selection_init:
2141  *     Initialize local variables
2142  *   arguments:
2143  *     
2144  *   results:
2145  *************************************************************/
2146
2147 static void
2148 gtk_selection_init (void)
2149 {
2150   gtk_selection_atoms[INCR] = gdk_atom_intern_static_string ("INCR");
2151   gtk_selection_atoms[MULTIPLE] = gdk_atom_intern_static_string ("MULTIPLE");
2152   gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern_static_string ("TIMESTAMP");
2153   gtk_selection_atoms[TARGETS] = gdk_atom_intern_static_string ("TARGETS");
2154
2155   initialize = FALSE;
2156 }
2157
2158 /**
2159  * gtk_selection_clear:
2160  * @widget: a #GtkWidget
2161  * @event: the event
2162  * 
2163  * The default handler for the GtkWidget::selection_clear_event
2164  * signal. 
2165  * 
2166  * Return value: %TRUE if the event was handled, otherwise false
2167  * 
2168  * Since: 2.2
2169  *
2170  * Deprecated: 2.4: Instead of calling this function, chain up from
2171  * your selection_clear_event handler. Calling this function
2172  * from any other context is illegal. 
2173  **/
2174 gboolean
2175 gtk_selection_clear (GtkWidget         *widget,
2176                      GdkEventSelection *event)
2177 {
2178   /* Note that we filter clear events in gdkselection-x11.c, so
2179    * that we only will get here if the clear event actually
2180    * represents a change that we didn't do ourself.
2181    */
2182   GList *tmp_list;
2183   GtkSelectionInfo *selection_info = NULL;
2184   
2185   tmp_list = current_selections;
2186   while (tmp_list)
2187     {
2188       selection_info = (GtkSelectionInfo *)tmp_list->data;
2189       
2190       if ((selection_info->selection == event->selection) &&
2191           (selection_info->widget == widget))
2192         break;
2193       
2194       tmp_list = tmp_list->next;
2195     }
2196   
2197   if (tmp_list)
2198     {
2199       current_selections = g_list_remove_link (current_selections, tmp_list);
2200       g_list_free (tmp_list);
2201       g_slice_free (GtkSelectionInfo, selection_info);
2202     }
2203   
2204   return TRUE;
2205 }
2206
2207
2208 /*************************************************************
2209  * _gtk_selection_request:
2210  *     Handler for "selection_request_event" 
2211  *   arguments:
2212  *     widget:
2213  *     event:
2214  *   results:
2215  *************************************************************/
2216
2217 gboolean
2218 _gtk_selection_request (GtkWidget *widget,
2219                         GdkEventSelection *event)
2220 {
2221   GdkDisplay *display = gtk_widget_get_display (widget);
2222   GtkIncrInfo *info;
2223   GList *tmp_list;
2224   int i;
2225   gulong selection_max_size;
2226
2227   if (initialize)
2228     gtk_selection_init ();
2229   
2230   selection_max_size = GTK_SELECTION_MAX_SIZE (display);
2231
2232   /* Check if we own selection */
2233   
2234   tmp_list = current_selections;
2235   while (tmp_list)
2236     {
2237       GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data;
2238       
2239       if ((selection_info->selection == event->selection) &&
2240           (selection_info->widget == widget))
2241         break;
2242       
2243       tmp_list = tmp_list->next;
2244     }
2245   
2246   if (tmp_list == NULL)
2247     return FALSE;
2248   
2249   info = g_slice_new (GtkIncrInfo);
2250
2251   g_object_ref (widget);
2252   
2253   info->selection = event->selection;
2254   info->num_incrs = 0;
2255   
2256   /* Create GdkWindow structure for the requestor */
2257   
2258   info->requestor = gdk_window_lookup_for_display (display,
2259                                                    event->requestor);
2260   if (!info->requestor)
2261     info->requestor = gdk_window_foreign_new_for_display (display,
2262                                                           event->requestor);
2263   
2264   /* Determine conversions we need to perform */
2265   
2266   if (event->target == gtk_selection_atoms[MULTIPLE])
2267     {
2268       GdkAtom  type;
2269       guchar  *mult_atoms;
2270       gint     format;
2271       gint     length;
2272       
2273       mult_atoms = NULL;
2274       
2275       gdk_error_trap_push ();
2276       if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */
2277                              0, selection_max_size, FALSE,
2278                              &type, &format, &length, &mult_atoms))
2279         {
2280           gdk_selection_send_notify_for_display (display,
2281                                                  event->requestor, 
2282                                                  event->selection,
2283                                                  event->target, 
2284                                                  GDK_NONE, 
2285                                                  event->time);
2286           g_free (mult_atoms);
2287           g_slice_free (GtkIncrInfo, info);
2288           gdk_error_trap_pop ();
2289           return TRUE;
2290         }
2291       gdk_error_trap_pop ();
2292
2293       /* This is annoying; the ICCCM doesn't specify the property type
2294        * used for the property contents, so the autoconversion for
2295        * ATOM / ATOM_PAIR in GDK doesn't work properly.
2296        */
2297 #ifdef GDK_WINDOWING_X11
2298       if (type != GDK_SELECTION_TYPE_ATOM &&
2299           type != gdk_atom_intern_static_string ("ATOM_PAIR"))
2300         {
2301           info->num_conversions = length / (2*sizeof (glong));
2302           info->conversions = g_new (GtkIncrConversion, info->num_conversions);
2303           
2304           for (i=0; i<info->num_conversions; i++)
2305             {
2306               info->conversions[i].target = gdk_x11_xatom_to_atom_for_display (display,
2307                                                                                ((glong *)mult_atoms)[2*i]);
2308               info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display,
2309                                                                                  ((glong *)mult_atoms)[2*i + 1]);
2310             }
2311
2312           g_free (mult_atoms);
2313         }
2314       else
2315 #endif
2316         {
2317           info->num_conversions = length / (2*sizeof (GdkAtom));
2318           info->conversions = g_new (GtkIncrConversion, info->num_conversions);
2319           
2320           for (i=0; i<info->num_conversions; i++)
2321             {
2322               info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
2323               info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
2324             }
2325
2326           g_free (mult_atoms);
2327         }
2328     }
2329   else                          /* only a single conversion */
2330     {
2331       info->conversions = g_new (GtkIncrConversion, 1);
2332       info->num_conversions = 1;
2333       info->conversions[0].target = event->target;
2334       info->conversions[0].property = event->property;
2335     }
2336   
2337   /* Loop through conversions and determine which of these are big
2338      enough to require doing them via INCR */
2339   for (i=0; i<info->num_conversions; i++)
2340     {
2341       GtkSelectionData data;
2342       glong items;
2343       
2344       data.selection = event->selection;
2345       data.target = info->conversions[i].target;
2346       data.data = NULL;
2347       data.length = -1;
2348       data.display = gtk_widget_get_display (widget);
2349       
2350 #ifdef DEBUG_SELECTION
2351       g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
2352                  event->selection, 
2353                  info->conversions[i].target,
2354                  gdk_atom_name (info->conversions[i].target),
2355                  event->requestor, info->conversions[i].property);
2356 #endif
2357       
2358       gtk_selection_invoke_handler (widget, &data, event->time);
2359       
2360       if (data.length < 0)
2361         {
2362           info->conversions[i].property = GDK_NONE;
2363           continue;
2364         }
2365       
2366       g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
2367       
2368       items = data.length / gtk_selection_bytes_per_item (data.format);
2369       
2370       if (data.length > selection_max_size)
2371         {
2372           /* Sending via INCR */
2373 #ifdef DEBUG_SELECTION
2374           g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n",
2375                      data.length, selection_max_size);
2376 #endif
2377           
2378           info->conversions[i].offset = 0;
2379           info->conversions[i].data = data;
2380           info->num_incrs++;
2381           
2382           gdk_property_change (info->requestor, 
2383                                info->conversions[i].property,
2384                                gtk_selection_atoms[INCR],
2385                                32,
2386                                GDK_PROP_MODE_REPLACE,
2387                                (guchar *)&items, 1);
2388         }
2389       else
2390         {
2391           info->conversions[i].offset = -1;
2392           
2393           gdk_property_change (info->requestor, 
2394                                info->conversions[i].property,
2395                                data.type,
2396                                data.format,
2397                                GDK_PROP_MODE_REPLACE,
2398                                data.data, items);
2399           
2400           g_free (data.data);
2401         }
2402     }
2403   
2404   /* If we have some INCR's, we need to send the rest of the data in
2405      a callback */
2406   
2407   if (info->num_incrs > 0)
2408     {
2409       /* FIXME: this could be dangerous if window doesn't still
2410          exist */
2411       
2412 #ifdef DEBUG_SELECTION
2413       g_message ("Starting INCR...");
2414 #endif
2415       
2416       gdk_window_set_events (info->requestor,
2417                              gdk_window_get_events (info->requestor) |
2418                              GDK_PROPERTY_CHANGE_MASK);
2419       current_incrs = g_list_append (current_incrs, info);
2420       gdk_threads_add_timeout (1000, (GSourceFunc) gtk_selection_incr_timeout, info);
2421     }
2422   
2423   /* If it was a MULTIPLE request, set the property to indicate which
2424      conversions succeeded */
2425   if (event->target == gtk_selection_atoms[MULTIPLE])
2426     {
2427       GdkAtom *mult_atoms = g_new (GdkAtom, 2 * info->num_conversions);
2428       for (i = 0; i < info->num_conversions; i++)
2429         {
2430           mult_atoms[2*i] = info->conversions[i].target;
2431           mult_atoms[2*i+1] = info->conversions[i].property;
2432         }
2433       
2434       gdk_property_change (info->requestor, event->property,
2435                            gdk_atom_intern_static_string ("ATOM_PAIR"), 32, 
2436                            GDK_PROP_MODE_REPLACE,
2437                            (guchar *)mult_atoms, 2*info->num_conversions);
2438       g_free (mult_atoms);
2439     }
2440
2441   if (info->num_conversions == 1 &&
2442       info->conversions[0].property == GDK_NONE)
2443     {
2444       /* Reject the entire conversion */
2445       gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
2446                                              event->requestor, 
2447                                              event->selection, 
2448                                              event->target, 
2449                                              GDK_NONE, 
2450                                              event->time);
2451     }
2452   else
2453     {
2454       gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
2455                                              event->requestor, 
2456                                              event->selection,
2457                                              event->target,
2458                                              event->property, 
2459                                              event->time);
2460     }
2461
2462   if (info->num_incrs == 0)
2463     {
2464       g_free (info->conversions);
2465       g_slice_free (GtkIncrInfo, info);
2466     }
2467
2468   g_object_unref (widget);
2469   
2470   return TRUE;
2471 }
2472
2473 /*************************************************************
2474  * _gtk_selection_incr_event:
2475  *     Called whenever an PropertyNotify event occurs for an 
2476  *     GdkWindow with user_data == NULL. These will be notifications
2477  *     that a window we are sending the selection to via the
2478  *     INCR protocol has deleted a property and is ready for
2479  *     more data.
2480  *
2481  *   arguments:
2482  *     window:  the requestor window
2483  *     event:   the property event structure
2484  *
2485  *   results:
2486  *************************************************************/
2487
2488 gboolean
2489 _gtk_selection_incr_event (GdkWindow       *window,
2490                            GdkEventProperty *event)
2491 {
2492   GList *tmp_list;
2493   GtkIncrInfo *info = NULL;
2494   gint num_bytes;
2495   guchar *buffer;
2496   gulong selection_max_size;
2497   
2498   int i;
2499   
2500   if (event->state != GDK_PROPERTY_DELETE)
2501     return FALSE;
2502   
2503 #ifdef DEBUG_SELECTION
2504   g_message ("PropertyDelete, property %ld", event->atom);
2505 #endif
2506
2507   selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window));  
2508
2509   /* Now find the appropriate ongoing INCR */
2510   tmp_list = current_incrs;
2511   while (tmp_list)
2512     {
2513       info = (GtkIncrInfo *)tmp_list->data;
2514       if (info->requestor == event->window)
2515         break;
2516       
2517       tmp_list = tmp_list->next;
2518     }
2519   
2520   if (tmp_list == NULL)
2521     return FALSE;
2522   
2523   /* Find out which target this is for */
2524   for (i=0; i<info->num_conversions; i++)
2525     {
2526       if (info->conversions[i].property == event->atom &&
2527           info->conversions[i].offset != -1)
2528         {
2529           int bytes_per_item;
2530           
2531           info->idle_time = 0;
2532           
2533           if (info->conversions[i].offset == -2) /* only the last 0-length
2534                                                     piece*/
2535             {
2536               num_bytes = 0;
2537               buffer = NULL;
2538             }
2539           else
2540             {
2541               num_bytes = info->conversions[i].data.length -
2542                 info->conversions[i].offset;
2543               buffer = info->conversions[i].data.data + 
2544                 info->conversions[i].offset;
2545               
2546               if (num_bytes > selection_max_size)
2547                 {
2548                   num_bytes = selection_max_size;
2549                   info->conversions[i].offset += selection_max_size;
2550                 }
2551               else
2552                 info->conversions[i].offset = -2;
2553             }
2554 #ifdef DEBUG_SELECTION
2555           g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
2556                      num_bytes, info->conversions[i].offset, 
2557                      GDK_WINDOW_XWINDOW(info->requestor), event->atom);
2558 #endif
2559
2560           bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
2561           gdk_property_change (info->requestor, event->atom,
2562                                info->conversions[i].data.type,
2563                                info->conversions[i].data.format,
2564                                GDK_PROP_MODE_REPLACE,
2565                                buffer,
2566                                num_bytes / bytes_per_item);
2567           
2568           if (info->conversions[i].offset == -2)
2569             {
2570               g_free (info->conversions[i].data.data);
2571               info->conversions[i].data.data = NULL;
2572             }
2573           
2574           if (num_bytes == 0)
2575             {
2576               info->num_incrs--;
2577               info->conversions[i].offset = -1;
2578             }
2579         }
2580     }
2581   
2582   /* Check if we're finished with all the targets */
2583   
2584   if (info->num_incrs == 0)
2585     {
2586       current_incrs = g_list_remove_link (current_incrs, tmp_list);
2587       g_list_free (tmp_list);
2588       /* Let the timeout free it */
2589     }
2590   
2591   return TRUE;
2592 }
2593
2594 /*************************************************************
2595  * gtk_selection_incr_timeout:
2596  *     Timeout callback for the sending portion of the INCR
2597  *     protocol
2598  *   arguments:
2599  *     info:    Information about this incr
2600  *   results:
2601  *************************************************************/
2602
2603 static gint
2604 gtk_selection_incr_timeout (GtkIncrInfo *info)
2605 {
2606   GList *tmp_list;
2607   gboolean retval;
2608
2609   /* Determine if retrieval has finished by checking if it still in
2610      list of pending retrievals */
2611   
2612   tmp_list = current_incrs;
2613   while (tmp_list)
2614     {
2615       if (info == (GtkIncrInfo *)tmp_list->data)
2616         break;
2617       tmp_list = tmp_list->next;
2618     }
2619   
2620   /* If retrieval is finished */
2621   if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2622     {
2623       if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2624         {
2625           current_incrs = g_list_remove_link (current_incrs, tmp_list);
2626           g_list_free (tmp_list);
2627         }
2628       
2629       g_free (info->conversions);
2630       /* FIXME: we should check if requestor window is still in use,
2631          and if not, remove it? */
2632       
2633       g_slice_free (GtkIncrInfo, info);
2634       
2635       retval =  FALSE;          /* remove timeout */
2636     }
2637   else
2638     {
2639       info->idle_time++;
2640       
2641       retval = TRUE;            /* timeout will happen again */
2642     }
2643   
2644   return retval;
2645 }
2646
2647 /*************************************************************
2648  * _gtk_selection_notify:
2649  *     Handler for "selection-notify-event" signals on windows
2650  *     where a retrieval is currently in process. The selection
2651  *     owner has responded to our conversion request.
2652  *   arguments:
2653  *     widget:          Widget getting signal
2654  *     event:           Selection event structure
2655  *     info:            Information about this retrieval
2656  *   results:
2657  *     was event handled?
2658  *************************************************************/
2659
2660 gboolean
2661 _gtk_selection_notify (GtkWidget               *widget,
2662                        GdkEventSelection *event)
2663 {
2664   GList *tmp_list;
2665   GtkRetrievalInfo *info = NULL;
2666   guchar  *buffer = NULL;
2667   gint length;
2668   GdkAtom type;
2669   gint    format;
2670   
2671 #ifdef DEBUG_SELECTION
2672   g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
2673              event->selection, event->target, event->property);
2674 #endif
2675   
2676   tmp_list = current_retrievals;
2677   while (tmp_list)
2678     {
2679       info = (GtkRetrievalInfo *)tmp_list->data;
2680       if (info->widget == widget && info->selection == event->selection)
2681         break;
2682       tmp_list = tmp_list->next;
2683     }
2684   
2685   if (!tmp_list)                /* no retrieval in progress */
2686     return FALSE;
2687
2688   if (event->property != GDK_NONE)
2689     length = gdk_selection_property_get (widget->window, &buffer, 
2690                                          &type, &format);
2691   else
2692     length = 0; /* silence gcc */
2693   
2694   if (event->property == GDK_NONE || buffer == NULL)
2695     {
2696       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2697       g_list_free (tmp_list);
2698       /* structure will be freed in timeout */
2699       gtk_selection_retrieval_report (info,
2700                                       GDK_NONE, 0, NULL, -1, event->time);
2701       
2702       return TRUE;
2703     }
2704   
2705   if (type == gtk_selection_atoms[INCR])
2706     {
2707       /* The remainder of the selection will come through PropertyNotify
2708          events */
2709
2710       info->notify_time = event->time;
2711       info->idle_time = 0;
2712       info->offset = 0;         /* Mark as OK to proceed */
2713       gdk_window_set_events (widget->window,
2714                              gdk_window_get_events (widget->window)
2715                              | GDK_PROPERTY_CHANGE_MASK);
2716     }
2717   else
2718     {
2719       /* We don't delete the info structure - that will happen in timeout */
2720       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2721       g_list_free (tmp_list);
2722       
2723       info->offset = length;
2724       gtk_selection_retrieval_report (info,
2725                                       type, format, 
2726                                       buffer, length, event->time);
2727     }
2728   
2729   gdk_property_delete (widget->window, event->property);
2730   
2731   g_free (buffer);
2732   
2733   return TRUE;
2734 }
2735
2736 /*************************************************************
2737  * _gtk_selection_property_notify:
2738  *     Handler for "property-notify-event" signals on windows
2739  *     where a retrieval is currently in process. The selection
2740  *     owner has added more data.
2741  *   arguments:
2742  *     widget:          Widget getting signal
2743  *     event:           Property event structure
2744  *     info:            Information about this retrieval
2745  *   results:
2746  *     was event handled?
2747  *************************************************************/
2748
2749 gboolean
2750 _gtk_selection_property_notify (GtkWidget       *widget,
2751                                 GdkEventProperty *event)
2752 {
2753   GList *tmp_list;
2754   GtkRetrievalInfo *info = NULL;
2755   guchar *new_buffer;
2756   int length;
2757   GdkAtom type;
2758   gint    format;
2759   
2760   g_return_val_if_fail (widget != NULL, FALSE);
2761   g_return_val_if_fail (event != NULL, FALSE);
2762
2763 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
2764   if ((event->state != GDK_PROPERTY_NEW_VALUE) ||  /* property was deleted */
2765       (event->atom != gdk_atom_intern_static_string ("GDK_SELECTION"))) /* not the right property */
2766 #endif
2767     return FALSE;
2768   
2769 #ifdef DEBUG_SELECTION
2770   g_message ("PropertyNewValue, property %ld",
2771              event->atom);
2772 #endif
2773   
2774   tmp_list = current_retrievals;
2775   while (tmp_list)
2776     {
2777       info = (GtkRetrievalInfo *)tmp_list->data;
2778       if (info->widget == widget)
2779         break;
2780       tmp_list = tmp_list->next;
2781     }
2782   
2783   if (!tmp_list)                /* No retrieval in progress */
2784     return FALSE;
2785   
2786   if (info->offset < 0)         /* We haven't got the SelectionNotify
2787                                    for this retrieval yet */
2788     return FALSE;
2789   
2790   info->idle_time = 0;
2791   
2792   length = gdk_selection_property_get (widget->window, &new_buffer, 
2793                                        &type, &format);
2794   gdk_property_delete (widget->window, event->atom);
2795   
2796   /* We could do a lot better efficiency-wise by paying attention to
2797      what length was sent in the initial INCR transaction, instead of
2798      doing memory allocation at every step. But its only guaranteed to
2799      be a _lower bound_ (pretty useless!) */
2800   
2801   if (length == 0 || type == GDK_NONE)          /* final zero length portion */
2802     {
2803       /* Info structure will be freed in timeout */
2804       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2805       g_list_free (tmp_list);
2806       gtk_selection_retrieval_report (info,
2807                                       type, format, 
2808                                       (type == GDK_NONE) ?  NULL : info->buffer,
2809                                       (type == GDK_NONE) ?  -1 : info->offset,
2810                                       info->notify_time);
2811     }
2812   else                          /* append on newly arrived data */
2813     {
2814       if (!info->buffer)
2815         {
2816 #ifdef DEBUG_SELECTION
2817           g_message ("Start - Adding %d bytes at offset 0",
2818                      length);
2819 #endif
2820           info->buffer = new_buffer;
2821           info->offset = length;
2822         }
2823       else
2824         {
2825           
2826 #ifdef DEBUG_SELECTION
2827           g_message ("Appending %d bytes at offset %d",
2828                      length,info->offset);
2829 #endif
2830           /* We copy length+1 bytes to preserve guaranteed null termination */
2831           info->buffer = g_realloc (info->buffer, info->offset+length+1);
2832           memcpy (info->buffer + info->offset, new_buffer, length+1);
2833           info->offset += length;
2834           g_free (new_buffer);
2835         }
2836     }
2837   
2838   return TRUE;
2839 }
2840
2841 /*************************************************************
2842  * gtk_selection_retrieval_timeout:
2843  *     Timeout callback while receiving a selection.
2844  *   arguments:
2845  *     info:    Information about this retrieval
2846  *   results:
2847  *************************************************************/
2848
2849 static gboolean
2850 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
2851 {
2852   GList *tmp_list;
2853   gboolean retval;
2854
2855   /* Determine if retrieval has finished by checking if it still in
2856      list of pending retrievals */
2857   
2858   tmp_list = current_retrievals;
2859   while (tmp_list)
2860     {
2861       if (info == (GtkRetrievalInfo *)tmp_list->data)
2862         break;
2863       tmp_list = tmp_list->next;
2864     }
2865   
2866   /* If retrieval is finished */
2867   if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2868     {
2869       if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2870         {
2871           current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2872           g_list_free (tmp_list);
2873           gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
2874         }
2875       
2876       g_free (info->buffer);
2877       g_slice_free (GtkRetrievalInfo, info);
2878       
2879       retval =  FALSE;          /* remove timeout */
2880     }
2881   else
2882     {
2883       info->idle_time++;
2884       
2885       retval =  TRUE;           /* timeout will happen again */
2886     }
2887
2888   return retval;
2889 }
2890
2891 /*************************************************************
2892  * gtk_selection_retrieval_report:
2893  *     Emits a "selection-received" signal.
2894  *   arguments:
2895  *     info:      information about the retrieval that completed
2896  *     buffer:    buffer containing data (NULL => errror)
2897  *     time:      timestamp for data in buffer
2898  *   results:
2899  *************************************************************/
2900
2901 static void
2902 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
2903                                 GdkAtom type, gint format, 
2904                                 guchar *buffer, gint length,
2905                                 guint32 time)
2906 {
2907   GtkSelectionData data;
2908   
2909   data.selection = info->selection;
2910   data.target = info->target;
2911   data.type = type;
2912   data.format = format;
2913   
2914   data.length = length;
2915   data.data = buffer;
2916   data.display = gtk_widget_get_display (info->widget);
2917   
2918   g_signal_emit_by_name (info->widget,
2919                          "selection-received", 
2920                          &data, time);
2921 }
2922
2923 /*************************************************************
2924  * gtk_selection_invoke_handler:
2925  *     Finds and invokes handler for specified
2926  *     widget/selection/target combination, calls 
2927  *     gtk_selection_default_handler if none exists.
2928  *
2929  *   arguments:
2930  *     widget:      selection owner
2931  *     data:        selection data [INOUT]
2932  *     time:        time from requeset
2933  *     
2934  *   results:
2935  *     Number of bytes written to buffer, -1 if error
2936  *************************************************************/
2937
2938 static void
2939 gtk_selection_invoke_handler (GtkWidget        *widget,
2940                               GtkSelectionData *data,
2941                               guint             time)
2942 {
2943   GtkTargetList *target_list;
2944   guint info;
2945   
2946
2947   g_return_if_fail (widget != NULL);
2948
2949   target_list = gtk_selection_target_list_get (widget, data->selection);
2950   if (target_list && 
2951       gtk_target_list_find (target_list, data->target, &info))
2952     {
2953       g_signal_emit_by_name (widget,
2954                              "selection-get",
2955                              data,
2956                              info, time);
2957     }
2958   else
2959     gtk_selection_default_handler (widget, data);
2960 }
2961
2962 /*************************************************************
2963  * gtk_selection_default_handler:
2964  *     Handles some default targets that exist for any widget
2965  *     If it can't fit results into buffer, returns -1. This
2966  *     won't happen in any conceivable case, since it would
2967  *     require 1000 selection targets!
2968  *
2969  *   arguments:
2970  *     widget:      selection owner
2971  *     data:        selection data [INOUT]
2972  *
2973  *************************************************************/
2974
2975 static void
2976 gtk_selection_default_handler (GtkWidget        *widget,
2977                                GtkSelectionData *data)
2978 {
2979   if (data->target == gtk_selection_atoms[TIMESTAMP])
2980     {
2981       /* Time which was used to obtain selection */
2982       GList *tmp_list;
2983       GtkSelectionInfo *selection_info;
2984       
2985       tmp_list = current_selections;
2986       while (tmp_list)
2987         {
2988           selection_info = (GtkSelectionInfo *)tmp_list->data;
2989           if ((selection_info->widget == widget) &&
2990               (selection_info->selection == data->selection))
2991             {
2992               gulong time = selection_info->time;
2993
2994               gtk_selection_data_set (data,
2995                                       GDK_SELECTION_TYPE_INTEGER,
2996                                       32,
2997                                       (guchar *)&time,
2998                                       sizeof (time));
2999               return;
3000             }
3001           
3002           tmp_list = tmp_list->next;
3003         }
3004       
3005       data->length = -1;
3006     }
3007   else if (data->target == gtk_selection_atoms[TARGETS])
3008     {
3009       /* List of all targets supported for this widget/selection pair */
3010       GdkAtom *p;
3011       guint count;
3012       GList *tmp_list;
3013       GtkTargetList *target_list;
3014       GtkTargetPair *pair;
3015       
3016       target_list = gtk_selection_target_list_get (widget,
3017                                                    data->selection);
3018       count = g_list_length (target_list->list) + 3;
3019       
3020       data->type = GDK_SELECTION_TYPE_ATOM;
3021       data->format = 32;
3022       data->length = count * sizeof (GdkAtom);
3023
3024       /* selection data is always terminated by a trailing \0
3025        */
3026       p = g_malloc (data->length + 1);
3027       data->data = (guchar *)p;
3028       data->data[data->length] = '\0';
3029       
3030       *p++ = gtk_selection_atoms[TIMESTAMP];
3031       *p++ = gtk_selection_atoms[TARGETS];
3032       *p++ = gtk_selection_atoms[MULTIPLE];
3033       
3034       tmp_list = target_list->list;
3035       while (tmp_list)
3036         {
3037           pair = (GtkTargetPair *)tmp_list->data;
3038           *p++ = pair->target;
3039           
3040           tmp_list = tmp_list->next;
3041         }
3042     }
3043   else
3044     {
3045       data->length = -1;
3046     }
3047 }
3048
3049
3050 /**
3051  * gtk_selection_data_copy:
3052  * @data: a pointer to a #GtkSelectionData structure.
3053  * 
3054  * Makes a copy of a #GtkSelectionData structure and its data.
3055  * 
3056  * Return value: a pointer to a copy of @data.
3057  **/
3058 GtkSelectionData*
3059 gtk_selection_data_copy (GtkSelectionData *data)
3060 {
3061   GtkSelectionData *new_data;
3062   
3063   g_return_val_if_fail (data != NULL, NULL);
3064   
3065   new_data = g_slice_new (GtkSelectionData);
3066   *new_data = *data;
3067
3068   if (data->data)
3069     {
3070       new_data->data = g_malloc (data->length + 1);
3071       memcpy (new_data->data, data->data, data->length + 1);
3072     }
3073   
3074   return new_data;
3075 }
3076
3077 /**
3078  * gtk_selection_data_free:
3079  * @data: a pointer to a #GtkSelectionData structure.
3080  * 
3081  * Frees a #GtkSelectionData structure returned from
3082  * gtk_selection_data_copy().
3083  **/
3084 void
3085 gtk_selection_data_free (GtkSelectionData *data)
3086 {
3087   g_return_if_fail (data != NULL);
3088   
3089   g_free (data->data);
3090   
3091   g_slice_free (GtkSelectionData, data);
3092 }
3093
3094 GType
3095 gtk_selection_data_get_type (void)
3096 {
3097   static GType our_type = 0;
3098   
3099   if (our_type == 0)
3100     our_type = g_boxed_type_register_static (I_("GtkSelectionData"),
3101                                              (GBoxedCopyFunc) gtk_selection_data_copy,
3102                                              (GBoxedFreeFunc) gtk_selection_data_free);
3103
3104   return our_type;
3105 }
3106
3107 GType
3108 gtk_target_list_get_type (void)
3109 {
3110   static GType our_type = 0;
3111
3112   if (our_type == 0)
3113     our_type = g_boxed_type_register_static (I_("GtkTargetList"),
3114                                              (GBoxedCopyFunc) gtk_target_list_ref,
3115                                              (GBoxedFreeFunc) gtk_target_list_unref);
3116
3117   return our_type;
3118 }
3119
3120 static int 
3121 gtk_selection_bytes_per_item (gint format)
3122 {
3123   switch (format)
3124     {
3125     case 8:
3126       return sizeof (char);
3127       break;
3128     case 16:
3129       return sizeof (short);
3130       break;
3131     case 32:
3132       return sizeof (long);
3133       break;
3134     default:
3135       g_assert_not_reached();
3136     }
3137   return 0;
3138 }
3139
3140 #define __GTK_SELECTION_C__
3141 #include "gtkaliasdef.c"