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