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