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