]> Pileus Git - ~andy/gtk/blob - gtk/gtkselection.c
5715b50f4036c8efd930b81dbb18d11028ead88b
[~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 i;
1624       gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1625                                                                utf8_atom,
1626                                                                selection_data->format, 
1627                                                                selection_data->data,
1628                                                                selection_data->length,
1629                                                                &list);
1630       if (count > 0)
1631         result = g_uri_list_extract_uris (list[0]);
1632       
1633       g_strfreev (list);
1634     }
1635
1636   return result;
1637 }
1638
1639
1640 /**
1641  * gtk_selection_data_get_targets:
1642  * @selection_data: a #GtkSelectionData object
1643  * @targets: location to store an array of targets. The result
1644  *           stored here must be freed with g_free().
1645  * @n_atoms: location to store number of items in @targets.
1646  * 
1647  * Gets the contents of @selection_data as an array of targets.
1648  * This can be used to interpret the results of getting
1649  * the standard TARGETS target that is always supplied for
1650  * any selection.
1651  * 
1652  * Return value: %TRUE if @selection_data contains a valid
1653  *    array of targets, otherwise %FALSE.
1654  **/
1655 gboolean
1656 gtk_selection_data_get_targets (GtkSelectionData  *selection_data,
1657                                 GdkAtom          **targets,
1658                                 gint              *n_atoms)
1659 {
1660   if (selection_data->length >= 0 &&
1661       selection_data->format == 32 &&
1662       selection_data->type == GDK_SELECTION_TYPE_ATOM)
1663     {
1664       if (targets)
1665         *targets = g_memdup (selection_data->data, selection_data->length);
1666       if (n_atoms)
1667         *n_atoms = selection_data->length / sizeof (GdkAtom);
1668
1669       return TRUE;
1670     }
1671   else
1672     {
1673       if (targets)
1674         *targets = NULL;
1675       if (n_atoms)
1676         *n_atoms = -1;
1677
1678       return FALSE;
1679     }
1680 }
1681
1682 /**
1683  * gtk_targets_include_text:
1684  * @targets: an array of #GdkAtom<!-- -->s
1685  * @n_targets: the length of @targets
1686  * 
1687  * Determines if any of the targets in @targets can be used to
1688  * provide text.
1689  * 
1690  * Return value: %TRUE if @targets include a suitable target for text,
1691  *   otherwise %FALSE.
1692  *
1693  * Since: 2.10
1694  **/
1695 gboolean 
1696 gtk_targets_include_text (GdkAtom *targets,
1697                            gint     n_targets)
1698 {
1699   gint i;
1700   gboolean result = FALSE;
1701
1702   /* Keep in sync with gtk_target_list_add_text_targets()
1703    */
1704  
1705   init_atoms ();
1706  
1707   for (i = 0; i < n_targets; i++)
1708     {
1709       if (targets[i] == utf8_atom ||
1710           targets[i] == text_atom ||
1711           targets[i] == GDK_TARGET_STRING ||
1712           targets[i] == ctext_atom ||
1713           targets[i] == text_plain_atom ||
1714           targets[i] == text_plain_utf8_atom ||
1715           targets[i] == text_plain_locale_atom)
1716         {
1717           result = TRUE;
1718           break;
1719         }
1720     }
1721   
1722   return result;
1723 }
1724
1725 /**
1726  * gtk_targets_include_rich_text:
1727  * @targets: an array of #GdkAtom<!-- -->s
1728  * @n_targets: the length of @targets
1729  * @buffer: a #GtkTextBuffer
1730  *
1731  * Determines if any of the targets in @targets can be used to
1732  * provide rich text.
1733  *
1734  * Return value: %TRUE if @targets include a suitable target for rich text,
1735  *               otherwise %FALSE.
1736  *
1737  * Since: 2.10
1738  **/
1739 gboolean
1740 gtk_targets_include_rich_text (GdkAtom       *targets,
1741                                gint           n_targets,
1742                                GtkTextBuffer *buffer)
1743 {
1744   GdkAtom *rich_targets;
1745   gint n_rich_targets;
1746   gint i, j;
1747   gboolean result = FALSE;
1748
1749   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1750
1751   init_atoms ();
1752
1753   rich_targets = gtk_text_buffer_get_deserialize_formats (buffer,
1754                                                           &n_rich_targets);
1755
1756   for (i = 0; i < n_targets; i++)
1757     {
1758       for (j = 0; j < n_rich_targets; j++)
1759         {
1760           if (targets[i] == rich_targets[j])
1761             {
1762               result = TRUE;
1763               goto done;
1764             }
1765         }
1766     }
1767
1768  done:
1769   g_free (rich_targets);
1770
1771   return result;
1772 }
1773
1774 /**
1775  * gtk_selection_data_targets_include_text:
1776  * @selection_data: a #GtkSelectionData object
1777  * 
1778  * Given a #GtkSelectionData object holding a list of targets,
1779  * determines if any of the targets in @targets can be used to
1780  * provide text.
1781  * 
1782  * Return value: %TRUE if @selection_data holds a list of targets,
1783  *   and a suitable target for text is included, otherwise %FALSE.
1784  **/
1785 gboolean
1786 gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
1787 {
1788   GdkAtom *targets;
1789   gint n_targets;
1790   gboolean result = FALSE;
1791
1792   init_atoms ();
1793
1794   if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1795     {
1796       result = gtk_targets_include_text (targets, n_targets);
1797       g_free (targets);
1798     }
1799
1800   return result;
1801 }
1802
1803 /**
1804  * gtk_selection_data_targets_include_rich_text:
1805  * @selection_data: a #GtkSelectionData object
1806  * @buffer: a #GtkTextBuffer
1807  *
1808  * Given a #GtkSelectionData object holding a list of targets,
1809  * determines if any of the targets in @targets can be used to
1810  * provide rich text.
1811  *
1812  * Return value: %TRUE if @selection_data holds a list of targets,
1813  *               and a suitable target for rich text is included,
1814  *               otherwise %FALSE.
1815  *
1816  * Since: 2.10
1817  **/
1818 gboolean
1819 gtk_selection_data_targets_include_rich_text (GtkSelectionData *selection_data,
1820                                               GtkTextBuffer    *buffer)
1821 {
1822   GdkAtom *targets;
1823   gint n_targets;
1824   gboolean result = FALSE;
1825
1826   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1827
1828   init_atoms ();
1829
1830   if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1831     {
1832       result = gtk_targets_include_rich_text (targets, n_targets, buffer);
1833       g_free (targets);
1834     }
1835
1836   return result;
1837 }
1838
1839 /**
1840  * gtk_targets_include_image:
1841  * @targets: an array of #GdkAtom<!-- -->s
1842  * @n_targets: the length of @targets
1843  * @writable: whether to accept only targets for which GTK+ knows
1844  *   how to convert a pixbuf into the format
1845  * 
1846  * Determines if any of the targets in @targets can be used to
1847  * provide a #GdkPixbuf.
1848  * 
1849  * Return value: %TRUE if @targets include a suitable target for images,
1850  *   otherwise %FALSE.
1851  *
1852  * Since: 2.10
1853  **/
1854 gboolean 
1855 gtk_targets_include_image (GdkAtom *targets,
1856                            gint     n_targets,
1857                            gboolean writable)
1858 {
1859   GtkTargetList *list;
1860   GList *l;
1861   gint i;
1862   gboolean result = FALSE;
1863
1864   list = gtk_target_list_new (NULL, 0);
1865   gtk_target_list_add_image_targets (list, 0, writable);
1866   for (i = 0; i < n_targets && !result; i++)
1867     {
1868       for (l = list->list; l; l = l->next)
1869         {
1870           GtkTargetPair *pair = (GtkTargetPair *)l->data;
1871           if (pair->target == targets[i])
1872             {
1873               result = TRUE;
1874               break;
1875             }
1876         }
1877     }
1878   gtk_target_list_unref (list);
1879
1880   return result;
1881 }
1882                                     
1883 /**
1884  * gtk_selection_data_targets_include_image:
1885  * @selection_data: a #GtkSelectionData object
1886  * @writable: whether to accept only targets for which GTK+ knows
1887  *   how to convert a pixbuf into the format
1888  * 
1889  * Given a #GtkSelectionData object holding a list of targets,
1890  * determines if any of the targets in @targets can be used to
1891  * provide a #GdkPixbuf.
1892  * 
1893  * Return value: %TRUE if @selection_data holds a list of targets,
1894  *   and a suitable target for images is included, otherwise %FALSE.
1895  *
1896  * Since: 2.6
1897  **/
1898 gboolean 
1899 gtk_selection_data_targets_include_image (GtkSelectionData *selection_data,
1900                                           gboolean          writable)
1901 {
1902   GdkAtom *targets;
1903   gint n_targets;
1904   gboolean result = FALSE;
1905
1906   init_atoms ();
1907
1908   if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1909     {
1910       result = gtk_targets_include_image (targets, n_targets, writable);
1911       g_free (targets);
1912     }
1913
1914   return result;
1915 }
1916
1917 /**
1918  * gtk_targets_include_uri:
1919  * @targets: an array of #GdkAtom<!-- -->s
1920  * @n_targets: the length of @targets
1921  * 
1922  * Determines if any of the targets in @targets can be used to
1923  * provide an uri list.
1924  * 
1925  * Return value: %TRUE if @targets include a suitable target for uri lists,
1926  *   otherwise %FALSE.
1927  *
1928  * Since: 2.10
1929  **/
1930 gboolean 
1931 gtk_targets_include_uri (GdkAtom *targets,
1932                          gint     n_targets)
1933 {
1934   gint i;
1935   gboolean result = FALSE;
1936
1937   /* Keep in sync with gtk_target_list_add_uri_targets()
1938    */
1939
1940   init_atoms ();
1941
1942   for (i = 0; i < n_targets; i++)
1943     {
1944       if (targets[i] == text_uri_list_atom)
1945         {
1946           result = TRUE;
1947           break;
1948         }
1949     }
1950   
1951   return result;
1952 }
1953
1954 /**
1955  * gtk_selection_data_targets_include_uri:
1956  * @selection_data: a #GtkSelectionData object
1957  * 
1958  * Given a #GtkSelectionData object holding a list of targets,
1959  * determines if any of the targets in @targets can be used to
1960  * provide a list or URIs.
1961  * 
1962  * Return value: %TRUE if @selection_data holds a list of targets,
1963  *   and a suitable target for text is included, otherwise %FALSE.
1964  *
1965  * Since: 2.10
1966  **/
1967 gboolean
1968 gtk_selection_data_targets_include_uri (GtkSelectionData *selection_data)
1969 {
1970   GdkAtom *targets;
1971   gint n_targets;
1972   gboolean result = FALSE;
1973
1974   init_atoms ();
1975
1976   if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1977     {
1978       result = gtk_targets_include_uri (targets, n_targets);
1979       g_free (targets);
1980     }
1981
1982   return result;
1983 }
1984
1985           
1986 /*************************************************************
1987  * gtk_selection_init:
1988  *     Initialize local variables
1989  *   arguments:
1990  *     
1991  *   results:
1992  *************************************************************/
1993
1994 static void
1995 gtk_selection_init (void)
1996 {
1997   gtk_selection_atoms[INCR] = gdk_atom_intern_static_string ("INCR");
1998   gtk_selection_atoms[MULTIPLE] = gdk_atom_intern_static_string ("MULTIPLE");
1999   gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern_static_string ("TIMESTAMP");
2000   gtk_selection_atoms[TARGETS] = gdk_atom_intern_static_string ("TARGETS");
2001
2002   initialize = FALSE;
2003 }
2004
2005 /**
2006  * gtk_selection_clear:
2007  * @widget: a #GtkWidget
2008  * @event: the event
2009  * 
2010  * The default handler for the GtkWidget::selection_clear_event
2011  * signal. 
2012  * 
2013  * Return value: %TRUE if the event was handled, otherwise false
2014  * 
2015  * Since: 2.2
2016  *
2017  * Deprecated: 2.4: Instead of calling this function, chain up from
2018  * your selection_clear_event handler. Calling this function
2019  * from any other context is illegal. 
2020  **/
2021 gboolean
2022 gtk_selection_clear (GtkWidget         *widget,
2023                      GdkEventSelection *event)
2024 {
2025   /* Note that we filter clear events in gdkselection-x11.c, so
2026    * that we only will get here if the clear event actually
2027    * represents a change that we didn't do ourself.
2028    */
2029   GList *tmp_list;
2030   GtkSelectionInfo *selection_info = NULL;
2031   
2032   tmp_list = current_selections;
2033   while (tmp_list)
2034     {
2035       selection_info = (GtkSelectionInfo *)tmp_list->data;
2036       
2037       if ((selection_info->selection == event->selection) &&
2038           (selection_info->widget == widget))
2039         break;
2040       
2041       tmp_list = tmp_list->next;
2042     }
2043   
2044   if (tmp_list)
2045     {
2046       current_selections = g_list_remove_link (current_selections, tmp_list);
2047       g_list_free (tmp_list);
2048       g_free (selection_info);
2049     }
2050   
2051   return TRUE;
2052 }
2053
2054
2055 /*************************************************************
2056  * _gtk_selection_request:
2057  *     Handler for "selection_request_event" 
2058  *   arguments:
2059  *     widget:
2060  *     event:
2061  *   results:
2062  *************************************************************/
2063
2064 gboolean
2065 _gtk_selection_request (GtkWidget *widget,
2066                         GdkEventSelection *event)
2067 {
2068   GdkDisplay *display = gtk_widget_get_display (widget);
2069   GtkIncrInfo *info;
2070   GList *tmp_list;
2071   int i;
2072   gulong selection_max_size;
2073
2074   if (initialize)
2075     gtk_selection_init ();
2076   
2077   selection_max_size = GTK_SELECTION_MAX_SIZE (display);
2078
2079   /* Check if we own selection */
2080   
2081   tmp_list = current_selections;
2082   while (tmp_list)
2083     {
2084       GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data;
2085       
2086       if ((selection_info->selection == event->selection) &&
2087           (selection_info->widget == widget))
2088         break;
2089       
2090       tmp_list = tmp_list->next;
2091     }
2092   
2093   if (tmp_list == NULL)
2094     return FALSE;
2095   
2096   info = g_new (GtkIncrInfo, 1);
2097
2098   g_object_ref (widget);
2099   
2100   info->selection = event->selection;
2101   info->num_incrs = 0;
2102   
2103   /* Create GdkWindow structure for the requestor */
2104   
2105   info->requestor = gdk_window_lookup_for_display (display,
2106                                                    event->requestor);
2107   if (!info->requestor)
2108     info->requestor = gdk_window_foreign_new_for_display (display,
2109                                                           event->requestor);
2110   
2111   /* Determine conversions we need to perform */
2112   
2113   if (event->target == gtk_selection_atoms[MULTIPLE])
2114     {
2115       GdkAtom  type;
2116       guchar  *mult_atoms;
2117       gint     format;
2118       gint     length;
2119       
2120       mult_atoms = NULL;
2121       
2122       gdk_error_trap_push ();
2123       if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */
2124                              0, selection_max_size, FALSE,
2125                              &type, &format, &length, &mult_atoms))
2126         {
2127           gdk_selection_send_notify_for_display (display,
2128                                                  event->requestor, 
2129                                                  event->selection,
2130                                                  event->target, 
2131                                                  GDK_NONE, 
2132                                                  event->time);
2133           g_free (mult_atoms);
2134           g_free (info);
2135           return TRUE;
2136         }
2137       gdk_error_trap_pop ();
2138
2139       /* This is annoying; the ICCCM doesn't specify the property type
2140        * used for the property contents, so the autoconversion for
2141        * ATOM / ATOM_PAIR in GDK doesn't work properly.
2142        */
2143 #ifdef GDK_WINDOWING_X11
2144       if (type != GDK_SELECTION_TYPE_ATOM &&
2145           type != gdk_atom_intern_static_string ("ATOM_PAIR"))
2146         {
2147           info->num_conversions = length / (2*sizeof (glong));
2148           info->conversions = g_new (GtkIncrConversion, info->num_conversions);
2149           
2150           for (i=0; i<info->num_conversions; i++)
2151             {
2152               info->conversions[i].target = gdk_x11_xatom_to_atom_for_display (display,
2153                                                                                ((glong *)mult_atoms)[2*i]);
2154               info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display,
2155                                                                                  ((glong *)mult_atoms)[2*i + 1]);
2156             }
2157
2158           g_free (mult_atoms);
2159         }
2160       else
2161 #endif
2162         {
2163           info->num_conversions = length / (2*sizeof (GdkAtom));
2164           info->conversions = g_new (GtkIncrConversion, info->num_conversions);
2165           
2166           for (i=0; i<info->num_conversions; i++)
2167             {
2168               info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
2169               info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
2170             }
2171         }
2172     }
2173   else                          /* only a single conversion */
2174     {
2175       info->conversions = g_new (GtkIncrConversion, 1);
2176       info->num_conversions = 1;
2177       info->conversions[0].target = event->target;
2178       info->conversions[0].property = event->property;
2179     }
2180   
2181   /* Loop through conversions and determine which of these are big
2182      enough to require doing them via INCR */
2183   for (i=0; i<info->num_conversions; i++)
2184     {
2185       GtkSelectionData data;
2186       glong items;
2187       
2188       data.selection = event->selection;
2189       data.target = info->conversions[i].target;
2190       data.data = NULL;
2191       data.length = -1;
2192       data.display = gtk_widget_get_display (widget);
2193       
2194 #ifdef DEBUG_SELECTION
2195       g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
2196                  event->selection, 
2197                  info->conversions[i].target,
2198                  gdk_atom_name (info->conversions[i].target),
2199                  event->requestor, info->conversions[i].property);
2200 #endif
2201       
2202       gtk_selection_invoke_handler (widget, &data, event->time);
2203       
2204       if (data.length < 0)
2205         {
2206           info->conversions[i].property = GDK_NONE;
2207           continue;
2208         }
2209       
2210       g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
2211       
2212       items = data.length / gtk_selection_bytes_per_item (data.format);
2213       
2214       if (data.length > selection_max_size)
2215         {
2216           /* Sending via INCR */
2217 #ifdef DEBUG_SELECTION
2218           g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n",
2219                      data.length, selection_max_size);
2220 #endif
2221           
2222           info->conversions[i].offset = 0;
2223           info->conversions[i].data = data;
2224           info->num_incrs++;
2225           
2226           gdk_property_change (info->requestor, 
2227                                info->conversions[i].property,
2228                                gtk_selection_atoms[INCR],
2229                                32,
2230                                GDK_PROP_MODE_REPLACE,
2231                                (guchar *)&items, 1);
2232         }
2233       else
2234         {
2235           info->conversions[i].offset = -1;
2236           
2237           gdk_property_change (info->requestor, 
2238                                info->conversions[i].property,
2239                                data.type,
2240                                data.format,
2241                                GDK_PROP_MODE_REPLACE,
2242                                data.data, items);
2243           
2244           g_free (data.data);
2245         }
2246     }
2247   
2248   /* If we have some INCR's, we need to send the rest of the data in
2249      a callback */
2250   
2251   if (info->num_incrs > 0)
2252     {
2253       /* FIXME: this could be dangerous if window doesn't still
2254          exist */
2255       
2256 #ifdef DEBUG_SELECTION
2257       g_message ("Starting INCR...");
2258 #endif
2259       
2260       gdk_window_set_events (info->requestor,
2261                              gdk_window_get_events (info->requestor) |
2262                              GDK_PROPERTY_CHANGE_MASK);
2263       current_incrs = g_list_append (current_incrs, info);
2264       g_timeout_add (1000, (GSourceFunc) gtk_selection_incr_timeout, info);
2265     }
2266   
2267   /* If it was a MULTIPLE request, set the property to indicate which
2268      conversions succeeded */
2269   if (event->target == gtk_selection_atoms[MULTIPLE])
2270     {
2271       GdkAtom *mult_atoms = g_new (GdkAtom, 2 * info->num_conversions);
2272       for (i = 0; i < info->num_conversions; i++)
2273         {
2274           mult_atoms[2*i] = info->conversions[i].target;
2275           mult_atoms[2*i+1] = info->conversions[i].property;
2276         }
2277       
2278       gdk_property_change (info->requestor, event->property,
2279                            gdk_atom_intern_static_string ("ATOM_PAIR"), 32, 
2280                            GDK_PROP_MODE_REPLACE,
2281                            (guchar *)mult_atoms, 2*info->num_conversions);
2282       g_free (mult_atoms);
2283     }
2284
2285   if (info->num_conversions == 1 &&
2286       info->conversions[0].property == GDK_NONE)
2287     {
2288       /* Reject the entire conversion */
2289       gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
2290                                              event->requestor, 
2291                                              event->selection, 
2292                                              event->target, 
2293                                              GDK_NONE, 
2294                                              event->time);
2295     }
2296   else
2297     {
2298       gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
2299                                              event->requestor, 
2300                                              event->selection,
2301                                              event->target,
2302                                              event->property, 
2303                                              event->time);
2304     }
2305
2306   if (info->num_incrs == 0)
2307     {
2308       g_free (info->conversions);
2309       g_free (info);
2310     }
2311
2312   g_object_unref (widget);
2313   
2314   return TRUE;
2315 }
2316
2317 /*************************************************************
2318  * _gtk_selection_incr_event:
2319  *     Called whenever an PropertyNotify event occurs for an 
2320  *     GdkWindow with user_data == NULL. These will be notifications
2321  *     that a window we are sending the selection to via the
2322  *     INCR protocol has deleted a property and is ready for
2323  *     more data.
2324  *
2325  *   arguments:
2326  *     window:  the requestor window
2327  *     event:   the property event structure
2328  *
2329  *   results:
2330  *************************************************************/
2331
2332 gboolean
2333 _gtk_selection_incr_event (GdkWindow       *window,
2334                            GdkEventProperty *event)
2335 {
2336   GList *tmp_list;
2337   GtkIncrInfo *info = NULL;
2338   gint num_bytes;
2339   guchar *buffer;
2340   gulong selection_max_size;
2341   
2342   int i;
2343   
2344   if (event->state != GDK_PROPERTY_DELETE)
2345     return FALSE;
2346   
2347 #ifdef DEBUG_SELECTION
2348   g_message ("PropertyDelete, property %ld", event->atom);
2349 #endif
2350
2351   selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window));  
2352
2353   /* Now find the appropriate ongoing INCR */
2354   tmp_list = current_incrs;
2355   while (tmp_list)
2356     {
2357       info = (GtkIncrInfo *)tmp_list->data;
2358       if (info->requestor == event->window)
2359         break;
2360       
2361       tmp_list = tmp_list->next;
2362     }
2363   
2364   if (tmp_list == NULL)
2365     return FALSE;
2366   
2367   /* Find out which target this is for */
2368   for (i=0; i<info->num_conversions; i++)
2369     {
2370       if (info->conversions[i].property == event->atom &&
2371           info->conversions[i].offset != -1)
2372         {
2373           int bytes_per_item;
2374           
2375           info->idle_time = 0;
2376           
2377           if (info->conversions[i].offset == -2) /* only the last 0-length
2378                                                     piece*/
2379             {
2380               num_bytes = 0;
2381               buffer = NULL;
2382             }
2383           else
2384             {
2385               num_bytes = info->conversions[i].data.length -
2386                 info->conversions[i].offset;
2387               buffer = info->conversions[i].data.data + 
2388                 info->conversions[i].offset;
2389               
2390               if (num_bytes > selection_max_size)
2391                 {
2392                   num_bytes = selection_max_size;
2393                   info->conversions[i].offset += selection_max_size;
2394                 }
2395               else
2396                 info->conversions[i].offset = -2;
2397             }
2398 #ifdef DEBUG_SELECTION
2399           g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
2400                      num_bytes, info->conversions[i].offset, 
2401                      GDK_WINDOW_XWINDOW(info->requestor), event->atom);
2402 #endif
2403
2404           bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
2405           gdk_property_change (info->requestor, event->atom,
2406                                info->conversions[i].data.type,
2407                                info->conversions[i].data.format,
2408                                GDK_PROP_MODE_REPLACE,
2409                                buffer,
2410                                num_bytes / bytes_per_item);
2411           
2412           if (info->conversions[i].offset == -2)
2413             {
2414               g_free (info->conversions[i].data.data);
2415               info->conversions[i].data.data = NULL;
2416             }
2417           
2418           if (num_bytes == 0)
2419             {
2420               info->num_incrs--;
2421               info->conversions[i].offset = -1;
2422             }
2423         }
2424     }
2425   
2426   /* Check if we're finished with all the targets */
2427   
2428   if (info->num_incrs == 0)
2429     {
2430       current_incrs = g_list_remove_link (current_incrs, tmp_list);
2431       g_list_free (tmp_list);
2432       /* Let the timeout free it */
2433     }
2434   
2435   return TRUE;
2436 }
2437
2438 /*************************************************************
2439  * gtk_selection_incr_timeout:
2440  *     Timeout callback for the sending portion of the INCR
2441  *     protocol
2442  *   arguments:
2443  *     info:    Information about this incr
2444  *   results:
2445  *************************************************************/
2446
2447 static gint
2448 gtk_selection_incr_timeout (GtkIncrInfo *info)
2449 {
2450   GList *tmp_list;
2451   gboolean retval;
2452
2453   GDK_THREADS_ENTER ();
2454   
2455   /* Determine if retrieval has finished by checking if it still in
2456      list of pending retrievals */
2457   
2458   tmp_list = current_incrs;
2459   while (tmp_list)
2460     {
2461       if (info == (GtkIncrInfo *)tmp_list->data)
2462         break;
2463       tmp_list = tmp_list->next;
2464     }
2465   
2466   /* If retrieval is finished */
2467   if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2468     {
2469       if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2470         {
2471           current_incrs = g_list_remove_link (current_incrs, tmp_list);
2472           g_list_free (tmp_list);
2473         }
2474       
2475       g_free (info->conversions);
2476       /* FIXME: we should check if requestor window is still in use,
2477          and if not, remove it? */
2478       
2479       g_free (info);
2480       
2481       retval =  FALSE;          /* remove timeout */
2482     }
2483   else
2484     {
2485       info->idle_time++;
2486       
2487       retval = TRUE;            /* timeout will happen again */
2488     }
2489   
2490   GDK_THREADS_LEAVE ();
2491
2492   return retval;
2493 }
2494
2495 /*************************************************************
2496  * _gtk_selection_notify:
2497  *     Handler for "selection_notify_event" signals on windows
2498  *     where a retrieval is currently in process. The selection
2499  *     owner has responded to our conversion request.
2500  *   arguments:
2501  *     widget:          Widget getting signal
2502  *     event:           Selection event structure
2503  *     info:            Information about this retrieval
2504  *   results:
2505  *     was event handled?
2506  *************************************************************/
2507
2508 gboolean
2509 _gtk_selection_notify (GtkWidget               *widget,
2510                        GdkEventSelection *event)
2511 {
2512   GList *tmp_list;
2513   GtkRetrievalInfo *info = NULL;
2514   guchar  *buffer = NULL;
2515   gint length;
2516   GdkAtom type;
2517   gint    format;
2518   
2519 #ifdef DEBUG_SELECTION
2520   g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
2521              event->selection, event->target, event->property);
2522 #endif
2523   
2524   tmp_list = current_retrievals;
2525   while (tmp_list)
2526     {
2527       info = (GtkRetrievalInfo *)tmp_list->data;
2528       if (info->widget == widget && info->selection == event->selection)
2529         break;
2530       tmp_list = tmp_list->next;
2531     }
2532   
2533   if (!tmp_list)                /* no retrieval in progress */
2534     return FALSE;
2535
2536   if (event->property != GDK_NONE)
2537     length = gdk_selection_property_get (widget->window, &buffer, 
2538                                          &type, &format);
2539   else
2540     length = 0; /* silence gcc */
2541   
2542   if (event->property == GDK_NONE || buffer == NULL)
2543     {
2544       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2545       g_list_free (tmp_list);
2546       /* structure will be freed in timeout */
2547       gtk_selection_retrieval_report (info,
2548                                       GDK_NONE, 0, NULL, -1, event->time);
2549       
2550       return TRUE;
2551     }
2552   
2553   if (type == gtk_selection_atoms[INCR])
2554     {
2555       /* The remainder of the selection will come through PropertyNotify
2556          events */
2557
2558       info->notify_time = event->time;
2559       info->idle_time = 0;
2560       info->offset = 0;         /* Mark as OK to proceed */
2561       gdk_window_set_events (widget->window,
2562                              gdk_window_get_events (widget->window)
2563                              | GDK_PROPERTY_CHANGE_MASK);
2564     }
2565   else
2566     {
2567       /* We don't delete the info structure - that will happen in timeout */
2568       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2569       g_list_free (tmp_list);
2570       
2571       info->offset = length;
2572       gtk_selection_retrieval_report (info,
2573                                       type, format, 
2574                                       buffer, length, event->time);
2575     }
2576   
2577   gdk_property_delete (widget->window, event->property);
2578   
2579   g_free (buffer);
2580   
2581   return TRUE;
2582 }
2583
2584 /*************************************************************
2585  * _gtk_selection_property_notify:
2586  *     Handler for "property_notify_event" signals on windows
2587  *     where a retrieval is currently in process. The selection
2588  *     owner has added more data.
2589  *   arguments:
2590  *     widget:          Widget getting signal
2591  *     event:           Property event structure
2592  *     info:            Information about this retrieval
2593  *   results:
2594  *     was event handled?
2595  *************************************************************/
2596
2597 gboolean
2598 _gtk_selection_property_notify (GtkWidget       *widget,
2599                                 GdkEventProperty *event)
2600 {
2601   GList *tmp_list;
2602   GtkRetrievalInfo *info = NULL;
2603   guchar *new_buffer;
2604   int length;
2605   GdkAtom type;
2606   gint    format;
2607   
2608   g_return_val_if_fail (widget != NULL, FALSE);
2609   g_return_val_if_fail (event != NULL, FALSE);
2610
2611 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
2612   if ((event->state != GDK_PROPERTY_NEW_VALUE) ||  /* property was deleted */
2613       (event->atom != gdk_atom_intern_static_string ("GDK_SELECTION"))) /* not the right property */
2614 #endif
2615     return FALSE;
2616   
2617 #ifdef DEBUG_SELECTION
2618   g_message ("PropertyNewValue, property %ld",
2619              event->atom);
2620 #endif
2621   
2622   tmp_list = current_retrievals;
2623   while (tmp_list)
2624     {
2625       info = (GtkRetrievalInfo *)tmp_list->data;
2626       if (info->widget == widget)
2627         break;
2628       tmp_list = tmp_list->next;
2629     }
2630   
2631   if (!tmp_list)                /* No retrieval in progress */
2632     return FALSE;
2633   
2634   if (info->offset < 0)         /* We haven't got the SelectionNotify
2635                                    for this retrieval yet */
2636     return FALSE;
2637   
2638   info->idle_time = 0;
2639   
2640   length = gdk_selection_property_get (widget->window, &new_buffer, 
2641                                        &type, &format);
2642   gdk_property_delete (widget->window, event->atom);
2643   
2644   /* We could do a lot better efficiency-wise by paying attention to
2645      what length was sent in the initial INCR transaction, instead of
2646      doing memory allocation at every step. But its only guaranteed to
2647      be a _lower bound_ (pretty useless!) */
2648   
2649   if (length == 0 || type == GDK_NONE)          /* final zero length portion */
2650     {
2651       /* Info structure will be freed in timeout */
2652       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2653       g_list_free (tmp_list);
2654       gtk_selection_retrieval_report (info,
2655                                       type, format, 
2656                                       (type == GDK_NONE) ?  NULL : info->buffer,
2657                                       (type == GDK_NONE) ?  -1 : info->offset,
2658                                       info->notify_time);
2659     }
2660   else                          /* append on newly arrived data */
2661     {
2662       if (!info->buffer)
2663         {
2664 #ifdef DEBUG_SELECTION
2665           g_message ("Start - Adding %d bytes at offset 0",
2666                      length);
2667 #endif
2668           info->buffer = new_buffer;
2669           info->offset = length;
2670         }
2671       else
2672         {
2673           
2674 #ifdef DEBUG_SELECTION
2675           g_message ("Appending %d bytes at offset %d",
2676                      length,info->offset);
2677 #endif
2678           /* We copy length+1 bytes to preserve guaranteed null termination */
2679           info->buffer = g_realloc (info->buffer, info->offset+length+1);
2680           memcpy (info->buffer + info->offset, new_buffer, length+1);
2681           info->offset += length;
2682           g_free (new_buffer);
2683         }
2684     }
2685   
2686   return TRUE;
2687 }
2688
2689 /*************************************************************
2690  * gtk_selection_retrieval_timeout:
2691  *     Timeout callback while receiving a selection.
2692  *   arguments:
2693  *     info:    Information about this retrieval
2694  *   results:
2695  *************************************************************/
2696
2697 static gint
2698 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
2699 {
2700   GList *tmp_list;
2701   gboolean retval;
2702
2703   GDK_THREADS_ENTER ();
2704   
2705   /* Determine if retrieval has finished by checking if it still in
2706      list of pending retrievals */
2707   
2708   tmp_list = current_retrievals;
2709   while (tmp_list)
2710     {
2711       if (info == (GtkRetrievalInfo *)tmp_list->data)
2712         break;
2713       tmp_list = tmp_list->next;
2714     }
2715   
2716   /* If retrieval is finished */
2717   if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2718     {
2719       if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2720         {
2721           current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2722           g_list_free (tmp_list);
2723           gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
2724         }
2725       
2726       g_free (info->buffer);
2727       g_free (info);
2728       
2729       retval =  FALSE;          /* remove timeout */
2730     }
2731   else
2732     {
2733       info->idle_time++;
2734       
2735       retval =  TRUE;           /* timeout will happen again */
2736     }
2737
2738   GDK_THREADS_LEAVE ();
2739
2740   return retval;
2741 }
2742
2743 /*************************************************************
2744  * gtk_selection_retrieval_report:
2745  *     Emits a "selection_received" signal.
2746  *   arguments:
2747  *     info:      information about the retrieval that completed
2748  *     buffer:    buffer containing data (NULL => errror)
2749  *     time:      timestamp for data in buffer
2750  *   results:
2751  *************************************************************/
2752
2753 static void
2754 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
2755                                 GdkAtom type, gint format, 
2756                                 guchar *buffer, gint length,
2757                                 guint32 time)
2758 {
2759   GtkSelectionData data;
2760   
2761   data.selection = info->selection;
2762   data.target = info->target;
2763   data.type = type;
2764   data.format = format;
2765   
2766   data.length = length;
2767   data.data = buffer;
2768   data.display = gtk_widget_get_display (info->widget);
2769   
2770   g_signal_emit_by_name (info->widget,
2771                          "selection_received", 
2772                          &data, time);
2773 }
2774
2775 /*************************************************************
2776  * gtk_selection_invoke_handler:
2777  *     Finds and invokes handler for specified
2778  *     widget/selection/target combination, calls 
2779  *     gtk_selection_default_handler if none exists.
2780  *
2781  *   arguments:
2782  *     widget:      selection owner
2783  *     data:        selection data [INOUT]
2784  *     time:        time from requeset
2785  *     
2786  *   results:
2787  *     Number of bytes written to buffer, -1 if error
2788  *************************************************************/
2789
2790 static void
2791 gtk_selection_invoke_handler (GtkWidget        *widget,
2792                               GtkSelectionData *data,
2793                               guint             time)
2794 {
2795   GtkTargetList *target_list;
2796   guint info;
2797   
2798
2799   g_return_if_fail (widget != NULL);
2800
2801   target_list = gtk_selection_target_list_get (widget, data->selection);
2802   if (target_list && 
2803       gtk_target_list_find (target_list, data->target, &info))
2804     {
2805       g_signal_emit_by_name (widget,
2806                              "selection_get",
2807                              data,
2808                              info, time);
2809     }
2810   else
2811     gtk_selection_default_handler (widget, data);
2812 }
2813
2814 /*************************************************************
2815  * gtk_selection_default_handler:
2816  *     Handles some default targets that exist for any widget
2817  *     If it can't fit results into buffer, returns -1. This
2818  *     won't happen in any conceivable case, since it would
2819  *     require 1000 selection targets!
2820  *
2821  *   arguments:
2822  *     widget:      selection owner
2823  *     data:        selection data [INOUT]
2824  *
2825  *************************************************************/
2826
2827 static void
2828 gtk_selection_default_handler (GtkWidget        *widget,
2829                                GtkSelectionData *data)
2830 {
2831   if (data->target == gtk_selection_atoms[TIMESTAMP])
2832     {
2833       /* Time which was used to obtain selection */
2834       GList *tmp_list;
2835       GtkSelectionInfo *selection_info;
2836       
2837       tmp_list = current_selections;
2838       while (tmp_list)
2839         {
2840           selection_info = (GtkSelectionInfo *)tmp_list->data;
2841           if ((selection_info->widget == widget) &&
2842               (selection_info->selection == data->selection))
2843             {
2844               gulong time = selection_info->time;
2845
2846               gtk_selection_data_set (data,
2847                                       GDK_SELECTION_TYPE_INTEGER,
2848                                       32,
2849                                       (guchar *)&time,
2850                                       sizeof (time));
2851               return;
2852             }
2853           
2854           tmp_list = tmp_list->next;
2855         }
2856       
2857       data->length = -1;
2858     }
2859   else if (data->target == gtk_selection_atoms[TARGETS])
2860     {
2861       /* List of all targets supported for this widget/selection pair */
2862       GdkAtom *p;
2863       guint count;
2864       GList *tmp_list;
2865       GtkTargetList *target_list;
2866       GtkTargetPair *pair;
2867       
2868       target_list = gtk_selection_target_list_get (widget,
2869                                                    data->selection);
2870       count = g_list_length (target_list->list) + 3;
2871       
2872       data->type = GDK_SELECTION_TYPE_ATOM;
2873       data->format = 32;
2874       data->length = count * sizeof (GdkAtom);
2875
2876       /* selection data is always terminated by a trailing \0
2877        */
2878       p = g_malloc (data->length + 1);
2879       data->data = (guchar *)p;
2880       data->data[data->length] = '\0';
2881       
2882       *p++ = gtk_selection_atoms[TIMESTAMP];
2883       *p++ = gtk_selection_atoms[TARGETS];
2884       *p++ = gtk_selection_atoms[MULTIPLE];
2885       
2886       tmp_list = target_list->list;
2887       while (tmp_list)
2888         {
2889           pair = (GtkTargetPair *)tmp_list->data;
2890           *p++ = pair->target;
2891           
2892           tmp_list = tmp_list->next;
2893         }
2894     }
2895   else
2896     {
2897       data->length = -1;
2898     }
2899 }
2900
2901
2902 /**
2903  * gtk_selection_data_copy:
2904  * @data: a pointer to a #GtkSelectionData structure.
2905  * 
2906  * Makes a copy of a #GtkSelectionData structure and its data.
2907  * 
2908  * Return value: a pointer to a copy of @data.
2909  **/
2910 GtkSelectionData*
2911 gtk_selection_data_copy (GtkSelectionData *data)
2912 {
2913   GtkSelectionData *new_data;
2914   
2915   g_return_val_if_fail (data != NULL, NULL);
2916   
2917   new_data = g_new (GtkSelectionData, 1);
2918   *new_data = *data;
2919
2920   if (data->data)
2921     {
2922       new_data->data = g_malloc (data->length + 1);
2923       memcpy (new_data->data, data->data, data->length + 1);
2924     }
2925   
2926   return new_data;
2927 }
2928
2929 /**
2930  * gtk_selection_data_free:
2931  * @data: a pointer to a #GtkSelectionData structure.
2932  * 
2933  * Frees a #GtkSelectionData structure returned from
2934  * gtk_selection_data_copy().
2935  **/
2936 void
2937 gtk_selection_data_free (GtkSelectionData *data)
2938 {
2939   g_return_if_fail (data != NULL);
2940   
2941   if (data->data)
2942     g_free (data->data);
2943   
2944   g_free (data);
2945 }
2946
2947 GType
2948 gtk_selection_data_get_type (void)
2949 {
2950   static GType our_type = 0;
2951   
2952   if (our_type == 0)
2953     our_type = g_boxed_type_register_static (I_("GtkSelectionData"),
2954                                              (GBoxedCopyFunc) gtk_selection_data_copy,
2955                                              (GBoxedFreeFunc) gtk_selection_data_free);
2956
2957   return our_type;
2958 }
2959
2960 GType
2961 gtk_target_list_get_type (void)
2962 {
2963   static GType our_type = 0;
2964
2965   if (our_type == 0)
2966     our_type = g_boxed_type_register_static (I_("GtkTargetList"),
2967                                              (GBoxedCopyFunc) gtk_target_list_ref,
2968                                              (GBoxedFreeFunc) gtk_target_list_unref);
2969
2970   return our_type;
2971 }
2972
2973 static int 
2974 gtk_selection_bytes_per_item (gint format)
2975 {
2976   switch (format)
2977     {
2978     case 8:
2979       return sizeof (char);
2980       break;
2981     case 16:
2982       return sizeof (short);
2983       break;
2984     case 32:
2985       return sizeof (long);
2986       break;
2987     default:
2988       g_assert_not_reached();
2989     }
2990   return 0;
2991 }
2992
2993 #define __GTK_SELECTION_C__
2994 #include "gtkaliasdef.c"