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