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