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