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