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