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