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