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