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