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