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