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