]> Pileus Git - ~andy/gtk/blob - gtk/gtkselection.c
451e5d860ee91753c2adde0f8f507a8e8e7a02d0
[~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 gint gtk_selection_incr_timeout      (GtkIncrInfo      *info);
156 static gint 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   g_timeout_add (1000, (GSourceFunc) gtk_selection_retrieval_timeout, info);
1094   
1095   return TRUE;
1096 }
1097
1098
1099 /**
1100  * gtk_selection_data_set:
1101  * @selection_data: a pointer to a #GtkSelectionData structure.
1102  * @type: the type of selection data
1103  * @format: format (number of bits in a unit)
1104  * @data: pointer to the data (will be copied)
1105  * @length: length of the data
1106  * 
1107  * Stores new data into a #GtkSelectionData object. Should
1108  * <emphasis>only</emphasis> be called from a selection handler callback.
1109  * Zero-terminates the stored data.
1110  **/
1111 void 
1112 gtk_selection_data_set (GtkSelectionData *selection_data,
1113                         GdkAtom           type,
1114                         gint              format,
1115                         const guchar     *data,
1116                         gint              length)
1117 {
1118   if (selection_data->data)
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
1201   while (1)
1202     {
1203       if (*p == '\n')
1204         g_string_append_c (result, '\r');
1205
1206       if (*p == '\r')
1207         {
1208           g_string_append_c (result, *p);
1209           p++;
1210           if (*p != '\n')
1211             g_string_append_c (result, '\n');
1212         }
1213
1214       if (*p == '\0')
1215         break;
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                                      charset, "UTF-8", 
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           return TRUE;
2135         }
2136       gdk_error_trap_pop ();
2137
2138       /* This is annoying; the ICCCM doesn't specify the property type
2139        * used for the property contents, so the autoconversion for
2140        * ATOM / ATOM_PAIR in GDK doesn't work properly.
2141        */
2142 #ifdef GDK_WINDOWING_X11
2143       if (type != GDK_SELECTION_TYPE_ATOM &&
2144           type != gdk_atom_intern_static_string ("ATOM_PAIR"))
2145         {
2146           info->num_conversions = length / (2*sizeof (glong));
2147           info->conversions = g_new (GtkIncrConversion, info->num_conversions);
2148           
2149           for (i=0; i<info->num_conversions; i++)
2150             {
2151               info->conversions[i].target = gdk_x11_xatom_to_atom_for_display (display,
2152                                                                                ((glong *)mult_atoms)[2*i]);
2153               info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display,
2154                                                                                  ((glong *)mult_atoms)[2*i + 1]);
2155             }
2156
2157           g_free (mult_atoms);
2158         }
2159       else
2160 #endif
2161         {
2162           info->num_conversions = length / (2*sizeof (GdkAtom));
2163           info->conversions = g_new (GtkIncrConversion, info->num_conversions);
2164           
2165           for (i=0; i<info->num_conversions; i++)
2166             {
2167               info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
2168               info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
2169             }
2170         }
2171     }
2172   else                          /* only a single conversion */
2173     {
2174       info->conversions = g_new (GtkIncrConversion, 1);
2175       info->num_conversions = 1;
2176       info->conversions[0].target = event->target;
2177       info->conversions[0].property = event->property;
2178     }
2179   
2180   /* Loop through conversions and determine which of these are big
2181      enough to require doing them via INCR */
2182   for (i=0; i<info->num_conversions; i++)
2183     {
2184       GtkSelectionData data;
2185       glong items;
2186       
2187       data.selection = event->selection;
2188       data.target = info->conversions[i].target;
2189       data.data = NULL;
2190       data.length = -1;
2191       data.display = gtk_widget_get_display (widget);
2192       
2193 #ifdef DEBUG_SELECTION
2194       g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
2195                  event->selection, 
2196                  info->conversions[i].target,
2197                  gdk_atom_name (info->conversions[i].target),
2198                  event->requestor, info->conversions[i].property);
2199 #endif
2200       
2201       gtk_selection_invoke_handler (widget, &data, event->time);
2202       
2203       if (data.length < 0)
2204         {
2205           info->conversions[i].property = GDK_NONE;
2206           continue;
2207         }
2208       
2209       g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
2210       
2211       items = data.length / gtk_selection_bytes_per_item (data.format);
2212       
2213       if (data.length > selection_max_size)
2214         {
2215           /* Sending via INCR */
2216 #ifdef DEBUG_SELECTION
2217           g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n",
2218                      data.length, selection_max_size);
2219 #endif
2220           
2221           info->conversions[i].offset = 0;
2222           info->conversions[i].data = data;
2223           info->num_incrs++;
2224           
2225           gdk_property_change (info->requestor, 
2226                                info->conversions[i].property,
2227                                gtk_selection_atoms[INCR],
2228                                32,
2229                                GDK_PROP_MODE_REPLACE,
2230                                (guchar *)&items, 1);
2231         }
2232       else
2233         {
2234           info->conversions[i].offset = -1;
2235           
2236           gdk_property_change (info->requestor, 
2237                                info->conversions[i].property,
2238                                data.type,
2239                                data.format,
2240                                GDK_PROP_MODE_REPLACE,
2241                                data.data, items);
2242           
2243           g_free (data.data);
2244         }
2245     }
2246   
2247   /* If we have some INCR's, we need to send the rest of the data in
2248      a callback */
2249   
2250   if (info->num_incrs > 0)
2251     {
2252       /* FIXME: this could be dangerous if window doesn't still
2253          exist */
2254       
2255 #ifdef DEBUG_SELECTION
2256       g_message ("Starting INCR...");
2257 #endif
2258       
2259       gdk_window_set_events (info->requestor,
2260                              gdk_window_get_events (info->requestor) |
2261                              GDK_PROPERTY_CHANGE_MASK);
2262       current_incrs = g_list_append (current_incrs, info);
2263       g_timeout_add (1000, (GSourceFunc) gtk_selection_incr_timeout, info);
2264     }
2265   
2266   /* If it was a MULTIPLE request, set the property to indicate which
2267      conversions succeeded */
2268   if (event->target == gtk_selection_atoms[MULTIPLE])
2269     {
2270       GdkAtom *mult_atoms = g_new (GdkAtom, 2 * info->num_conversions);
2271       for (i = 0; i < info->num_conversions; i++)
2272         {
2273           mult_atoms[2*i] = info->conversions[i].target;
2274           mult_atoms[2*i+1] = info->conversions[i].property;
2275         }
2276       
2277       gdk_property_change (info->requestor, event->property,
2278                            gdk_atom_intern_static_string ("ATOM_PAIR"), 32, 
2279                            GDK_PROP_MODE_REPLACE,
2280                            (guchar *)mult_atoms, 2*info->num_conversions);
2281       g_free (mult_atoms);
2282     }
2283
2284   if (info->num_conversions == 1 &&
2285       info->conversions[0].property == GDK_NONE)
2286     {
2287       /* Reject the entire conversion */
2288       gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
2289                                              event->requestor, 
2290                                              event->selection, 
2291                                              event->target, 
2292                                              GDK_NONE, 
2293                                              event->time);
2294     }
2295   else
2296     {
2297       gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
2298                                              event->requestor, 
2299                                              event->selection,
2300                                              event->target,
2301                                              event->property, 
2302                                              event->time);
2303     }
2304
2305   if (info->num_incrs == 0)
2306     {
2307       g_free (info->conversions);
2308       g_free (info);
2309     }
2310
2311   g_object_unref (widget);
2312   
2313   return TRUE;
2314 }
2315
2316 /*************************************************************
2317  * _gtk_selection_incr_event:
2318  *     Called whenever an PropertyNotify event occurs for an 
2319  *     GdkWindow with user_data == NULL. These will be notifications
2320  *     that a window we are sending the selection to via the
2321  *     INCR protocol has deleted a property and is ready for
2322  *     more data.
2323  *
2324  *   arguments:
2325  *     window:  the requestor window
2326  *     event:   the property event structure
2327  *
2328  *   results:
2329  *************************************************************/
2330
2331 gboolean
2332 _gtk_selection_incr_event (GdkWindow       *window,
2333                            GdkEventProperty *event)
2334 {
2335   GList *tmp_list;
2336   GtkIncrInfo *info = NULL;
2337   gint num_bytes;
2338   guchar *buffer;
2339   gulong selection_max_size;
2340   
2341   int i;
2342   
2343   if (event->state != GDK_PROPERTY_DELETE)
2344     return FALSE;
2345   
2346 #ifdef DEBUG_SELECTION
2347   g_message ("PropertyDelete, property %ld", event->atom);
2348 #endif
2349
2350   selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window));  
2351
2352   /* Now find the appropriate ongoing INCR */
2353   tmp_list = current_incrs;
2354   while (tmp_list)
2355     {
2356       info = (GtkIncrInfo *)tmp_list->data;
2357       if (info->requestor == event->window)
2358         break;
2359       
2360       tmp_list = tmp_list->next;
2361     }
2362   
2363   if (tmp_list == NULL)
2364     return FALSE;
2365   
2366   /* Find out which target this is for */
2367   for (i=0; i<info->num_conversions; i++)
2368     {
2369       if (info->conversions[i].property == event->atom &&
2370           info->conversions[i].offset != -1)
2371         {
2372           int bytes_per_item;
2373           
2374           info->idle_time = 0;
2375           
2376           if (info->conversions[i].offset == -2) /* only the last 0-length
2377                                                     piece*/
2378             {
2379               num_bytes = 0;
2380               buffer = NULL;
2381             }
2382           else
2383             {
2384               num_bytes = info->conversions[i].data.length -
2385                 info->conversions[i].offset;
2386               buffer = info->conversions[i].data.data + 
2387                 info->conversions[i].offset;
2388               
2389               if (num_bytes > selection_max_size)
2390                 {
2391                   num_bytes = selection_max_size;
2392                   info->conversions[i].offset += selection_max_size;
2393                 }
2394               else
2395                 info->conversions[i].offset = -2;
2396             }
2397 #ifdef DEBUG_SELECTION
2398           g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
2399                      num_bytes, info->conversions[i].offset, 
2400                      GDK_WINDOW_XWINDOW(info->requestor), event->atom);
2401 #endif
2402
2403           bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
2404           gdk_property_change (info->requestor, event->atom,
2405                                info->conversions[i].data.type,
2406                                info->conversions[i].data.format,
2407                                GDK_PROP_MODE_REPLACE,
2408                                buffer,
2409                                num_bytes / bytes_per_item);
2410           
2411           if (info->conversions[i].offset == -2)
2412             {
2413               g_free (info->conversions[i].data.data);
2414               info->conversions[i].data.data = NULL;
2415             }
2416           
2417           if (num_bytes == 0)
2418             {
2419               info->num_incrs--;
2420               info->conversions[i].offset = -1;
2421             }
2422         }
2423     }
2424   
2425   /* Check if we're finished with all the targets */
2426   
2427   if (info->num_incrs == 0)
2428     {
2429       current_incrs = g_list_remove_link (current_incrs, tmp_list);
2430       g_list_free (tmp_list);
2431       /* Let the timeout free it */
2432     }
2433   
2434   return TRUE;
2435 }
2436
2437 /*************************************************************
2438  * gtk_selection_incr_timeout:
2439  *     Timeout callback for the sending portion of the INCR
2440  *     protocol
2441  *   arguments:
2442  *     info:    Information about this incr
2443  *   results:
2444  *************************************************************/
2445
2446 static gint
2447 gtk_selection_incr_timeout (GtkIncrInfo *info)
2448 {
2449   GList *tmp_list;
2450   gboolean retval;
2451
2452   GDK_THREADS_ENTER ();
2453   
2454   /* Determine if retrieval has finished by checking if it still in
2455      list of pending retrievals */
2456   
2457   tmp_list = current_incrs;
2458   while (tmp_list)
2459     {
2460       if (info == (GtkIncrInfo *)tmp_list->data)
2461         break;
2462       tmp_list = tmp_list->next;
2463     }
2464   
2465   /* If retrieval is finished */
2466   if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2467     {
2468       if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2469         {
2470           current_incrs = g_list_remove_link (current_incrs, tmp_list);
2471           g_list_free (tmp_list);
2472         }
2473       
2474       g_free (info->conversions);
2475       /* FIXME: we should check if requestor window is still in use,
2476          and if not, remove it? */
2477       
2478       g_free (info);
2479       
2480       retval =  FALSE;          /* remove timeout */
2481     }
2482   else
2483     {
2484       info->idle_time++;
2485       
2486       retval = TRUE;            /* timeout will happen again */
2487     }
2488   
2489   GDK_THREADS_LEAVE ();
2490
2491   return retval;
2492 }
2493
2494 /*************************************************************
2495  * _gtk_selection_notify:
2496  *     Handler for "selection_notify_event" signals on windows
2497  *     where a retrieval is currently in process. The selection
2498  *     owner has responded to our conversion request.
2499  *   arguments:
2500  *     widget:          Widget getting signal
2501  *     event:           Selection event structure
2502  *     info:            Information about this retrieval
2503  *   results:
2504  *     was event handled?
2505  *************************************************************/
2506
2507 gboolean
2508 _gtk_selection_notify (GtkWidget               *widget,
2509                        GdkEventSelection *event)
2510 {
2511   GList *tmp_list;
2512   GtkRetrievalInfo *info = NULL;
2513   guchar  *buffer = NULL;
2514   gint length;
2515   GdkAtom type;
2516   gint    format;
2517   
2518 #ifdef DEBUG_SELECTION
2519   g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
2520              event->selection, event->target, event->property);
2521 #endif
2522   
2523   tmp_list = current_retrievals;
2524   while (tmp_list)
2525     {
2526       info = (GtkRetrievalInfo *)tmp_list->data;
2527       if (info->widget == widget && info->selection == event->selection)
2528         break;
2529       tmp_list = tmp_list->next;
2530     }
2531   
2532   if (!tmp_list)                /* no retrieval in progress */
2533     return FALSE;
2534
2535   if (event->property != GDK_NONE)
2536     length = gdk_selection_property_get (widget->window, &buffer, 
2537                                          &type, &format);
2538   else
2539     length = 0; /* silence gcc */
2540   
2541   if (event->property == GDK_NONE || buffer == NULL)
2542     {
2543       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2544       g_list_free (tmp_list);
2545       /* structure will be freed in timeout */
2546       gtk_selection_retrieval_report (info,
2547                                       GDK_NONE, 0, NULL, -1, event->time);
2548       
2549       return TRUE;
2550     }
2551   
2552   if (type == gtk_selection_atoms[INCR])
2553     {
2554       /* The remainder of the selection will come through PropertyNotify
2555          events */
2556
2557       info->notify_time = event->time;
2558       info->idle_time = 0;
2559       info->offset = 0;         /* Mark as OK to proceed */
2560       gdk_window_set_events (widget->window,
2561                              gdk_window_get_events (widget->window)
2562                              | GDK_PROPERTY_CHANGE_MASK);
2563     }
2564   else
2565     {
2566       /* We don't delete the info structure - that will happen in timeout */
2567       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2568       g_list_free (tmp_list);
2569       
2570       info->offset = length;
2571       gtk_selection_retrieval_report (info,
2572                                       type, format, 
2573                                       buffer, length, event->time);
2574     }
2575   
2576   gdk_property_delete (widget->window, event->property);
2577   
2578   g_free (buffer);
2579   
2580   return TRUE;
2581 }
2582
2583 /*************************************************************
2584  * _gtk_selection_property_notify:
2585  *     Handler for "property_notify_event" signals on windows
2586  *     where a retrieval is currently in process. The selection
2587  *     owner has added more data.
2588  *   arguments:
2589  *     widget:          Widget getting signal
2590  *     event:           Property event structure
2591  *     info:            Information about this retrieval
2592  *   results:
2593  *     was event handled?
2594  *************************************************************/
2595
2596 gboolean
2597 _gtk_selection_property_notify (GtkWidget       *widget,
2598                                 GdkEventProperty *event)
2599 {
2600   GList *tmp_list;
2601   GtkRetrievalInfo *info = NULL;
2602   guchar *new_buffer;
2603   int length;
2604   GdkAtom type;
2605   gint    format;
2606   
2607   g_return_val_if_fail (widget != NULL, FALSE);
2608   g_return_val_if_fail (event != NULL, FALSE);
2609
2610 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
2611   if ((event->state != GDK_PROPERTY_NEW_VALUE) ||  /* property was deleted */
2612       (event->atom != gdk_atom_intern_static_string ("GDK_SELECTION"))) /* not the right property */
2613 #endif
2614     return FALSE;
2615   
2616 #ifdef DEBUG_SELECTION
2617   g_message ("PropertyNewValue, property %ld",
2618              event->atom);
2619 #endif
2620   
2621   tmp_list = current_retrievals;
2622   while (tmp_list)
2623     {
2624       info = (GtkRetrievalInfo *)tmp_list->data;
2625       if (info->widget == widget)
2626         break;
2627       tmp_list = tmp_list->next;
2628     }
2629   
2630   if (!tmp_list)                /* No retrieval in progress */
2631     return FALSE;
2632   
2633   if (info->offset < 0)         /* We haven't got the SelectionNotify
2634                                    for this retrieval yet */
2635     return FALSE;
2636   
2637   info->idle_time = 0;
2638   
2639   length = gdk_selection_property_get (widget->window, &new_buffer, 
2640                                        &type, &format);
2641   gdk_property_delete (widget->window, event->atom);
2642   
2643   /* We could do a lot better efficiency-wise by paying attention to
2644      what length was sent in the initial INCR transaction, instead of
2645      doing memory allocation at every step. But its only guaranteed to
2646      be a _lower bound_ (pretty useless!) */
2647   
2648   if (length == 0 || type == GDK_NONE)          /* final zero length portion */
2649     {
2650       /* Info structure will be freed in timeout */
2651       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2652       g_list_free (tmp_list);
2653       gtk_selection_retrieval_report (info,
2654                                       type, format, 
2655                                       (type == GDK_NONE) ?  NULL : info->buffer,
2656                                       (type == GDK_NONE) ?  -1 : info->offset,
2657                                       info->notify_time);
2658     }
2659   else                          /* append on newly arrived data */
2660     {
2661       if (!info->buffer)
2662         {
2663 #ifdef DEBUG_SELECTION
2664           g_message ("Start - Adding %d bytes at offset 0",
2665                      length);
2666 #endif
2667           info->buffer = new_buffer;
2668           info->offset = length;
2669         }
2670       else
2671         {
2672           
2673 #ifdef DEBUG_SELECTION
2674           g_message ("Appending %d bytes at offset %d",
2675                      length,info->offset);
2676 #endif
2677           /* We copy length+1 bytes to preserve guaranteed null termination */
2678           info->buffer = g_realloc (info->buffer, info->offset+length+1);
2679           memcpy (info->buffer + info->offset, new_buffer, length+1);
2680           info->offset += length;
2681           g_free (new_buffer);
2682         }
2683     }
2684   
2685   return TRUE;
2686 }
2687
2688 /*************************************************************
2689  * gtk_selection_retrieval_timeout:
2690  *     Timeout callback while receiving a selection.
2691  *   arguments:
2692  *     info:    Information about this retrieval
2693  *   results:
2694  *************************************************************/
2695
2696 static gint
2697 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
2698 {
2699   GList *tmp_list;
2700   gboolean retval;
2701
2702   GDK_THREADS_ENTER ();
2703   
2704   /* Determine if retrieval has finished by checking if it still in
2705      list of pending retrievals */
2706   
2707   tmp_list = current_retrievals;
2708   while (tmp_list)
2709     {
2710       if (info == (GtkRetrievalInfo *)tmp_list->data)
2711         break;
2712       tmp_list = tmp_list->next;
2713     }
2714   
2715   /* If retrieval is finished */
2716   if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2717     {
2718       if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2719         {
2720           current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2721           g_list_free (tmp_list);
2722           gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
2723         }
2724       
2725       g_free (info->buffer);
2726       g_free (info);
2727       
2728       retval =  FALSE;          /* remove timeout */
2729     }
2730   else
2731     {
2732       info->idle_time++;
2733       
2734       retval =  TRUE;           /* timeout will happen again */
2735     }
2736
2737   GDK_THREADS_LEAVE ();
2738
2739   return retval;
2740 }
2741
2742 /*************************************************************
2743  * gtk_selection_retrieval_report:
2744  *     Emits a "selection_received" signal.
2745  *   arguments:
2746  *     info:      information about the retrieval that completed
2747  *     buffer:    buffer containing data (NULL => errror)
2748  *     time:      timestamp for data in buffer
2749  *   results:
2750  *************************************************************/
2751
2752 static void
2753 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
2754                                 GdkAtom type, gint format, 
2755                                 guchar *buffer, gint length,
2756                                 guint32 time)
2757 {
2758   GtkSelectionData data;
2759   
2760   data.selection = info->selection;
2761   data.target = info->target;
2762   data.type = type;
2763   data.format = format;
2764   
2765   data.length = length;
2766   data.data = buffer;
2767   data.display = gtk_widget_get_display (info->widget);
2768   
2769   g_signal_emit_by_name (info->widget,
2770                          "selection_received", 
2771                          &data, time);
2772 }
2773
2774 /*************************************************************
2775  * gtk_selection_invoke_handler:
2776  *     Finds and invokes handler for specified
2777  *     widget/selection/target combination, calls 
2778  *     gtk_selection_default_handler if none exists.
2779  *
2780  *   arguments:
2781  *     widget:      selection owner
2782  *     data:        selection data [INOUT]
2783  *     time:        time from requeset
2784  *     
2785  *   results:
2786  *     Number of bytes written to buffer, -1 if error
2787  *************************************************************/
2788
2789 static void
2790 gtk_selection_invoke_handler (GtkWidget        *widget,
2791                               GtkSelectionData *data,
2792                               guint             time)
2793 {
2794   GtkTargetList *target_list;
2795   guint info;
2796   
2797
2798   g_return_if_fail (widget != NULL);
2799
2800   target_list = gtk_selection_target_list_get (widget, data->selection);
2801   if (target_list && 
2802       gtk_target_list_find (target_list, data->target, &info))
2803     {
2804       g_signal_emit_by_name (widget,
2805                              "selection_get",
2806                              data,
2807                              info, time);
2808     }
2809   else
2810     gtk_selection_default_handler (widget, data);
2811 }
2812
2813 /*************************************************************
2814  * gtk_selection_default_handler:
2815  *     Handles some default targets that exist for any widget
2816  *     If it can't fit results into buffer, returns -1. This
2817  *     won't happen in any conceivable case, since it would
2818  *     require 1000 selection targets!
2819  *
2820  *   arguments:
2821  *     widget:      selection owner
2822  *     data:        selection data [INOUT]
2823  *
2824  *************************************************************/
2825
2826 static void
2827 gtk_selection_default_handler (GtkWidget        *widget,
2828                                GtkSelectionData *data)
2829 {
2830   if (data->target == gtk_selection_atoms[TIMESTAMP])
2831     {
2832       /* Time which was used to obtain selection */
2833       GList *tmp_list;
2834       GtkSelectionInfo *selection_info;
2835       
2836       tmp_list = current_selections;
2837       while (tmp_list)
2838         {
2839           selection_info = (GtkSelectionInfo *)tmp_list->data;
2840           if ((selection_info->widget == widget) &&
2841               (selection_info->selection == data->selection))
2842             {
2843               gulong time = selection_info->time;
2844
2845               gtk_selection_data_set (data,
2846                                       GDK_SELECTION_TYPE_INTEGER,
2847                                       32,
2848                                       (guchar *)&time,
2849                                       sizeof (time));
2850               return;
2851             }
2852           
2853           tmp_list = tmp_list->next;
2854         }
2855       
2856       data->length = -1;
2857     }
2858   else if (data->target == gtk_selection_atoms[TARGETS])
2859     {
2860       /* List of all targets supported for this widget/selection pair */
2861       GdkAtom *p;
2862       guint count;
2863       GList *tmp_list;
2864       GtkTargetList *target_list;
2865       GtkTargetPair *pair;
2866       
2867       target_list = gtk_selection_target_list_get (widget,
2868                                                    data->selection);
2869       count = g_list_length (target_list->list) + 3;
2870       
2871       data->type = GDK_SELECTION_TYPE_ATOM;
2872       data->format = 32;
2873       data->length = count * sizeof (GdkAtom);
2874
2875       /* selection data is always terminated by a trailing \0
2876        */
2877       p = g_malloc (data->length + 1);
2878       data->data = (guchar *)p;
2879       data->data[data->length] = '\0';
2880       
2881       *p++ = gtk_selection_atoms[TIMESTAMP];
2882       *p++ = gtk_selection_atoms[TARGETS];
2883       *p++ = gtk_selection_atoms[MULTIPLE];
2884       
2885       tmp_list = target_list->list;
2886       while (tmp_list)
2887         {
2888           pair = (GtkTargetPair *)tmp_list->data;
2889           *p++ = pair->target;
2890           
2891           tmp_list = tmp_list->next;
2892         }
2893     }
2894   else
2895     {
2896       data->length = -1;
2897     }
2898 }
2899
2900
2901 /**
2902  * gtk_selection_data_copy:
2903  * @data: a pointer to a #GtkSelectionData structure.
2904  * 
2905  * Makes a copy of a #GtkSelectionData structure and its data.
2906  * 
2907  * Return value: a pointer to a copy of @data.
2908  **/
2909 GtkSelectionData*
2910 gtk_selection_data_copy (GtkSelectionData *data)
2911 {
2912   GtkSelectionData *new_data;
2913   
2914   g_return_val_if_fail (data != NULL, NULL);
2915   
2916   new_data = g_new (GtkSelectionData, 1);
2917   *new_data = *data;
2918
2919   if (data->data)
2920     {
2921       new_data->data = g_malloc (data->length + 1);
2922       memcpy (new_data->data, data->data, data->length + 1);
2923     }
2924   
2925   return new_data;
2926 }
2927
2928 /**
2929  * gtk_selection_data_free:
2930  * @data: a pointer to a #GtkSelectionData structure.
2931  * 
2932  * Frees a #GtkSelectionData structure returned from
2933  * gtk_selection_data_copy().
2934  **/
2935 void
2936 gtk_selection_data_free (GtkSelectionData *data)
2937 {
2938   g_return_if_fail (data != NULL);
2939   
2940   if (data->data)
2941     g_free (data->data);
2942   
2943   g_free (data);
2944 }
2945
2946 GType
2947 gtk_selection_data_get_type (void)
2948 {
2949   static GType our_type = 0;
2950   
2951   if (our_type == 0)
2952     our_type = g_boxed_type_register_static (I_("GtkSelectionData"),
2953                                              (GBoxedCopyFunc) gtk_selection_data_copy,
2954                                              (GBoxedFreeFunc) gtk_selection_data_free);
2955
2956   return our_type;
2957 }
2958
2959 GType
2960 gtk_target_list_get_type (void)
2961 {
2962   static GType our_type = 0;
2963
2964   if (our_type == 0)
2965     our_type = g_boxed_type_register_static (I_("GtkTargetList"),
2966                                              (GBoxedCopyFunc) gtk_target_list_ref,
2967                                              (GBoxedFreeFunc) gtk_target_list_unref);
2968
2969   return our_type;
2970 }
2971
2972 static int 
2973 gtk_selection_bytes_per_item (gint format)
2974 {
2975   switch (format)
2976     {
2977     case 8:
2978       return sizeof (char);
2979       break;
2980     case 16:
2981       return sizeof (short);
2982       break;
2983     case 32:
2984       return sizeof (long);
2985       break;
2986     default:
2987       g_assert_not_reached();
2988     }
2989   return 0;
2990 }
2991
2992 #define __GTK_SELECTION_C__
2993 #include "gtkaliasdef.c"