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