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