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