1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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
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.
31 * By Owen Taylor <owt1@cornell.edu> 8/16/97
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 ....)
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 ... */
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/.
56 #include "gtkselection.h"
57 #include "gtkselectionprivate.h"
65 #include "gtktextbufferrichtext.h"
67 #include "gdk-pixbuf/gdk-pixbuf.h"
69 #ifdef GDK_WINDOWING_X11
73 #ifdef GDK_WINDOWING_WIN32
74 #include "win32/gdkwin32.h"
77 #undef DEBUG_SELECTION
79 /* Maximum size of a sent chunk, in bytes. Also the default size of
81 #ifdef GDK_WINDOWING_X11
82 #define GTK_SELECTION_MAX_SIZE(display) \
84 XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0 \
85 ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100 \
86 : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
88 /* No chunks on Win32 */
89 #define GTK_SELECTION_MAX_SIZE(display) G_MAXINT
92 #define IDLE_ABORT_TIME 30
103 typedef struct _GtkSelectionInfo GtkSelectionInfo;
104 typedef struct _GtkIncrConversion GtkIncrConversion;
105 typedef struct _GtkIncrInfo GtkIncrInfo;
106 typedef struct _GtkRetrievalInfo GtkRetrievalInfo;
108 struct _GtkSelectionInfo
111 GtkWidget *widget; /* widget that owns selection */
112 guint32 time; /* time used to acquire selection */
113 GdkDisplay *display; /* needed in gtk_selection_remove_all */
116 struct _GtkIncrConversion
118 GdkAtom target; /* Requested target */
119 GdkAtom property; /* Property to store in */
120 GtkSelectionData data; /* The data being supplied */
121 gint offset; /* Current offset in sent selection.
123 * -2 => Only the final (empty) portion
129 GdkWindow *requestor; /* Requestor window - we create a GdkWindow
130 so we can receive events */
131 GdkAtom selection; /* Selection we're sending */
133 GtkIncrConversion *conversions; /* Information about requested conversions -
134 * With MULTIPLE requests (benighted 1980's
135 * hardware idea), there can be more than
137 gint num_conversions;
138 gint num_incrs; /* number of remaining INCR style transactions */
143 struct _GtkRetrievalInfo
146 GdkAtom selection; /* Selection being retrieved. */
147 GdkAtom target; /* Form of selection that we requested */
148 guint32 idle_time; /* Number of seconds since we last heard
149 from selection owner */
150 guchar *buffer; /* Buffer in which to accumulate results */
151 gint offset; /* Current offset in buffer, -1 indicates
153 guint32 notify_time; /* Timestamp from SelectionNotify */
156 /* Local Functions */
157 static void gtk_selection_init (void);
158 static gboolean gtk_selection_incr_timeout (GtkIncrInfo *info);
159 static gboolean gtk_selection_retrieval_timeout (GtkRetrievalInfo *info);
160 static void gtk_selection_retrieval_report (GtkRetrievalInfo *info,
166 static void gtk_selection_invoke_handler (GtkWidget *widget,
167 GtkSelectionData *data,
169 static void gtk_selection_default_handler (GtkWidget *widget,
170 GtkSelectionData *data);
171 static int gtk_selection_bytes_per_item (gint format);
174 static gint initialize = TRUE;
175 static GList *current_retrievals = NULL;
176 static GList *current_incrs = NULL;
177 static GList *current_selections = NULL;
179 static GdkAtom gtk_selection_atoms[LAST_ATOM];
180 static const char gtk_selection_handler_key[] = "gtk-selection-handlers";
192 * gtk_target_list_new:
193 * @targets: Pointer to an array of #GtkTargetEntry
194 * @ntargets: number of entries in @targets.
196 * Creates a new #GtkTargetList from an array of #GtkTargetEntry.
198 * Return value: the new #GtkTargetList.
201 gtk_target_list_new (const GtkTargetEntry *targets,
204 GtkTargetList *result = g_slice_new (GtkTargetList);
206 result->ref_count = 1;
209 gtk_target_list_add_table (result, targets, ntargets);
215 * gtk_target_list_ref:
216 * @list: a #GtkTargetList
218 * Increases the reference count of a #GtkTargetList by one.
220 * Return value: the passed in #GtkTargetList.
223 gtk_target_list_ref (GtkTargetList *list)
225 g_return_val_if_fail (list != NULL, NULL);
233 * gtk_target_list_unref:
234 * @list: a #GtkTargetList
236 * Decreases the reference count of a #GtkTargetList by one.
237 * If the resulting reference count is zero, frees the list.
240 gtk_target_list_unref (GtkTargetList *list)
242 g_return_if_fail (list != NULL);
243 g_return_if_fail (list->ref_count > 0);
246 if (list->ref_count == 0)
248 GList *tmp_list = list->list;
251 GtkTargetPair *pair = tmp_list->data;
252 g_slice_free (GtkTargetPair, pair);
254 tmp_list = tmp_list->next;
257 g_list_free (list->list);
258 g_slice_free (GtkTargetList, list);
263 * gtk_target_list_add:
264 * @list: a #GtkTargetList
265 * @target: the interned atom representing the target
266 * @flags: the flags for this target
267 * @info: an ID that will be passed back to the application
269 * Appends another target to a #GtkTargetList.
272 gtk_target_list_add (GtkTargetList *list,
279 g_return_if_fail (list != NULL);
281 pair = g_slice_new (GtkTargetPair);
282 pair->target = target;
286 list->list = g_list_append (list->list, pair);
289 static GdkAtom utf8_atom;
290 static GdkAtom text_atom;
291 static GdkAtom ctext_atom;
292 static GdkAtom text_plain_atom;
293 static GdkAtom text_plain_utf8_atom;
294 static GdkAtom text_plain_locale_atom;
295 static GdkAtom text_uri_list_atom;
301 const gchar *charset;
305 utf8_atom = gdk_atom_intern_static_string ("UTF8_STRING");
306 text_atom = gdk_atom_intern_static_string ("TEXT");
307 ctext_atom = gdk_atom_intern_static_string ("COMPOUND_TEXT");
308 text_plain_atom = gdk_atom_intern_static_string ("text/plain");
309 text_plain_utf8_atom = gdk_atom_intern_static_string ("text/plain;charset=utf-8");
310 g_get_charset (&charset);
311 tmp = g_strdup_printf ("text/plain;charset=%s", charset);
312 text_plain_locale_atom = gdk_atom_intern (tmp, FALSE);
315 text_uri_list_atom = gdk_atom_intern_static_string ("text/uri-list");
320 * gtk_target_list_add_text_targets:
321 * @list: a #GtkTargetList
322 * @info: an ID that will be passed back to the application
324 * Appends the text targets supported by #GtkSelection to
325 * the target list. All targets are added with the same @info.
330 gtk_target_list_add_text_targets (GtkTargetList *list,
333 g_return_if_fail (list != NULL);
337 /* Keep in sync with gtk_selection_data_targets_include_text()
339 gtk_target_list_add (list, utf8_atom, 0, info);
340 gtk_target_list_add (list, ctext_atom, 0, info);
341 gtk_target_list_add (list, text_atom, 0, info);
342 gtk_target_list_add (list, GDK_TARGET_STRING, 0, info);
343 gtk_target_list_add (list, text_plain_utf8_atom, 0, info);
344 if (!g_get_charset (NULL))
345 gtk_target_list_add (list, text_plain_locale_atom, 0, info);
346 gtk_target_list_add (list, text_plain_atom, 0, info);
350 * gtk_target_list_add_rich_text_targets:
351 * @list: a #GtkTargetList
352 * @info: an ID that will be passed back to the application
353 * @deserializable: if %TRUE, then deserializable rich text formats
354 * will be added, serializable formats otherwise.
355 * @buffer: a #GtkTextBuffer.
357 * Appends the rich text targets registered with
358 * gtk_text_buffer_register_serialize_format() or
359 * gtk_text_buffer_register_deserialize_format() to the target list. All
360 * targets are added with the same @info.
365 gtk_target_list_add_rich_text_targets (GtkTargetList *list,
367 gboolean deserializable,
368 GtkTextBuffer *buffer)
374 g_return_if_fail (list != NULL);
375 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
378 atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
380 atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_atoms);
382 for (i = 0; i < n_atoms; i++)
383 gtk_target_list_add (list, atoms[i], 0, info);
389 * gtk_target_list_add_image_targets:
390 * @list: a #GtkTargetList
391 * @info: an ID that will be passed back to the application
392 * @writable: whether to add only targets for which GTK+ knows
393 * how to convert a pixbuf into the format
395 * Appends the image targets supported by #GtkSelection to
396 * the target list. All targets are added with the same @info.
401 gtk_target_list_add_image_targets (GtkTargetList *list,
409 g_return_if_fail (list != NULL);
411 formats = gdk_pixbuf_get_formats ();
413 /* Make sure png comes first */
414 for (f = formats; f; f = f->next)
416 GdkPixbufFormat *fmt = f->data;
419 name = gdk_pixbuf_format_get_name (fmt);
420 if (strcmp (name, "png") == 0)
422 formats = g_slist_delete_link (formats, f);
423 formats = g_slist_prepend (formats, fmt);
433 for (f = formats; f; f = f->next)
435 GdkPixbufFormat *fmt = f->data;
437 if (writable && !gdk_pixbuf_format_is_writable (fmt))
440 mimes = gdk_pixbuf_format_get_mime_types (fmt);
441 for (m = mimes; *m; m++)
443 atom = gdk_atom_intern (*m, FALSE);
444 gtk_target_list_add (list, atom, 0, info);
449 g_slist_free (formats);
453 * gtk_target_list_add_uri_targets:
454 * @list: a #GtkTargetList
455 * @info: an ID that will be passed back to the application
457 * Appends the URI targets supported by #GtkSelection to
458 * the target list. All targets are added with the same @info.
463 gtk_target_list_add_uri_targets (GtkTargetList *list,
466 g_return_if_fail (list != NULL);
470 gtk_target_list_add (list, text_uri_list_atom, 0, info);
474 * gtk_target_list_add_table:
475 * @list: a #GtkTargetList
476 * @targets: the table of #GtkTargetEntry
477 * @ntargets: number of targets in the table
479 * Prepends a table of #GtkTargetEntry to a target list.
482 gtk_target_list_add_table (GtkTargetList *list,
483 const GtkTargetEntry *targets,
488 for (i=ntargets-1; i >= 0; i--)
490 GtkTargetPair *pair = g_slice_new (GtkTargetPair);
491 pair->target = gdk_atom_intern (targets[i].target, FALSE);
492 pair->flags = targets[i].flags;
493 pair->info = targets[i].info;
495 list->list = g_list_prepend (list->list, pair);
500 * gtk_target_list_remove:
501 * @list: a #GtkTargetList
502 * @target: the interned atom representing the target
504 * Removes a target from a target list.
507 gtk_target_list_remove (GtkTargetList *list,
512 g_return_if_fail (list != NULL);
514 tmp_list = list->list;
517 GtkTargetPair *pair = tmp_list->data;
519 if (pair->target == target)
521 g_slice_free (GtkTargetPair, pair);
523 list->list = g_list_remove_link (list->list, tmp_list);
524 g_list_free_1 (tmp_list);
529 tmp_list = tmp_list->next;
534 * gtk_target_list_find:
535 * @list: a #GtkTargetList
536 * @target: an interned atom representing the target to search for
537 * @info: a pointer to the location to store application info for target,
540 * Looks up a given target in a #GtkTargetList.
542 * Return value: %TRUE if the target was found, otherwise %FALSE
545 gtk_target_list_find (GtkTargetList *list,
551 g_return_val_if_fail (list != NULL, FALSE);
553 tmp_list = list->list;
556 GtkTargetPair *pair = tmp_list->data;
558 if (pair->target == target)
566 tmp_list = tmp_list->next;
573 * gtk_target_table_new_from_list:
574 * @list: a #GtkTargetList
575 * @n_targets: return location for the number ot targets in the table
577 * This function creates an #GtkTargetEntry array that contains the
578 * same targets as the passed %list. The returned table is newly
579 * allocated and should be freed using gtk_target_table_free() when no
582 * Return value: the new table.
587 gtk_target_table_new_from_list (GtkTargetList *list,
590 GtkTargetEntry *targets;
594 g_return_val_if_fail (list != NULL, NULL);
595 g_return_val_if_fail (n_targets != NULL, NULL);
597 *n_targets = g_list_length (list->list);
598 targets = g_new0 (GtkTargetEntry, *n_targets);
600 for (i = 0, tmp_list = list->list;
602 i++, tmp_list = g_list_next (tmp_list))
604 GtkTargetPair *pair = tmp_list->data;
606 targets[i].target = gdk_atom_name (pair->target);
607 targets[i].flags = pair->flags;
608 targets[i].info = pair->info;
615 * gtk_target_table_free:
616 * @targets: a #GtkTargetEntry array
617 * @n_targets: the number of entries in the array
619 * This function frees a target table as returned by
620 * gtk_target_table_new_from_list()
625 gtk_target_table_free (GtkTargetEntry *targets,
630 g_return_if_fail (targets == NULL || n_targets > 0);
632 for (i = 0; i < n_targets; i++)
633 g_free (targets[i].target);
639 * gtk_selection_owner_set_for_display:
640 * @display: the #Gdkdisplay where the selection is set
641 * @widget: (allow-none): new selection owner (a #GdkWidget), or %NULL.
642 * @selection: an interned atom representing the selection to claim.
643 * @time_: timestamp with which to claim the selection
645 * Claim ownership of a given selection for a particular widget, or,
646 * if @widget is %NULL, release ownership of the selection.
648 * Return value: TRUE if the operation succeeded
653 gtk_selection_owner_set_for_display (GdkDisplay *display,
659 GtkWidget *old_owner;
660 GtkSelectionInfo *selection_info = NULL;
663 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
664 g_return_val_if_fail (selection != GDK_NONE, FALSE);
665 g_return_val_if_fail (widget == NULL || gtk_widget_get_realized (widget), FALSE);
666 g_return_val_if_fail (widget == NULL || gtk_widget_get_display (widget) == display, FALSE);
671 window = gtk_widget_get_window (widget);
673 tmp_list = current_selections;
676 if (((GtkSelectionInfo *)tmp_list->data)->selection == selection)
678 selection_info = tmp_list->data;
682 tmp_list = tmp_list->next;
685 if (gdk_selection_owner_set_for_display (display, window, selection, time, TRUE))
693 old_owner = selection_info->widget;
694 current_selections = g_list_remove_link (current_selections,
696 g_list_free (tmp_list);
697 g_slice_free (GtkSelectionInfo, selection_info);
702 if (selection_info == NULL)
704 selection_info = g_slice_new (GtkSelectionInfo);
705 selection_info->selection = selection;
706 selection_info->widget = widget;
707 selection_info->time = time;
708 selection_info->display = display;
709 current_selections = g_list_prepend (current_selections,
714 old_owner = selection_info->widget;
715 selection_info->widget = widget;
716 selection_info->time = time;
717 selection_info->display = display;
720 /* If another widget in the application lost the selection,
721 * send it a GDK_SELECTION_CLEAR event.
723 if (old_owner && old_owner != widget)
725 GdkEvent *event = gdk_event_new (GDK_SELECTION_CLEAR);
727 event->selection.window = g_object_ref (gtk_widget_get_window (old_owner));
728 event->selection.selection = selection;
729 event->selection.time = time;
731 gtk_widget_event (old_owner, event);
733 gdk_event_free (event);
742 * gtk_selection_owner_set:
743 * @widget: (allow-none): a #GtkWidget, or %NULL.
744 * @selection: an interned atom representing the selection to claim
745 * @time_: timestamp with which to claim the selection
747 * Claims ownership of a given selection for a particular widget,
748 * or, if @widget is %NULL, release ownership of the selection.
750 * Return value: %TRUE if the operation succeeded
753 gtk_selection_owner_set (GtkWidget *widget,
759 g_return_val_if_fail (widget == NULL || gtk_widget_get_realized (widget), FALSE);
760 g_return_val_if_fail (selection != GDK_NONE, FALSE);
763 display = gtk_widget_get_display (widget);
767 g_warning ("gtk_selection_owner_set (NULL,...) is not multihead safe"));
769 display = gdk_display_get_default ();
772 return gtk_selection_owner_set_for_display (display, widget,
776 typedef struct _GtkSelectionTargetList GtkSelectionTargetList;
778 struct _GtkSelectionTargetList {
783 static GtkTargetList *
784 gtk_selection_target_list_get (GtkWidget *widget,
787 GtkSelectionTargetList *sellist;
791 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
796 sellist = tmp_list->data;
797 if (sellist->selection == selection)
798 return sellist->list;
799 tmp_list = tmp_list->next;
802 sellist = g_slice_new (GtkSelectionTargetList);
803 sellist->selection = selection;
804 sellist->list = gtk_target_list_new (NULL, 0);
806 lists = g_list_prepend (lists, sellist);
807 g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), lists);
809 return sellist->list;
813 gtk_selection_target_list_remove (GtkWidget *widget)
815 GtkSelectionTargetList *sellist;
819 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
824 sellist = tmp_list->data;
826 gtk_target_list_unref (sellist->list);
828 g_slice_free (GtkSelectionTargetList, sellist);
829 tmp_list = tmp_list->next;
833 g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), NULL);
837 * gtk_selection_clear_targets:
838 * @widget: a #GtkWidget
839 * @selection: an atom representing a selection
841 * Remove all targets registered for the given selection for the
845 gtk_selection_clear_targets (GtkWidget *widget,
848 GtkSelectionTargetList *sellist;
852 g_return_if_fail (GTK_IS_WIDGET (widget));
853 g_return_if_fail (selection != GDK_NONE);
855 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
860 sellist = tmp_list->data;
861 if (sellist->selection == selection)
863 lists = g_list_delete_link (lists, tmp_list);
864 gtk_target_list_unref (sellist->list);
865 g_slice_free (GtkSelectionTargetList, sellist);
870 tmp_list = tmp_list->next;
873 g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), lists);
877 * gtk_selection_add_target:
878 * @widget: a #GtkTarget
879 * @selection: the selection
880 * @target: target to add.
881 * @info: A unsigned integer which will be passed back to the application.
883 * Appends a specified target to the list of supported targets for a
884 * given widget and selection.
887 gtk_selection_add_target (GtkWidget *widget,
894 g_return_if_fail (GTK_IS_WIDGET (widget));
895 g_return_if_fail (selection != GDK_NONE);
897 list = gtk_selection_target_list_get (widget, selection);
898 gtk_target_list_add (list, target, 0, info);
899 #ifdef GDK_WINDOWING_WIN32
900 gdk_win32_selection_add_targets (gtk_widget_get_window (widget), selection, 1, &target);
905 * gtk_selection_add_targets:
906 * @widget: a #GtkWidget
907 * @selection: the selection
908 * @targets: a table of targets to add
909 * @ntargets: number of entries in @targets
911 * Prepends a table of targets to the list of supported targets
912 * for a given widget and selection.
915 gtk_selection_add_targets (GtkWidget *widget,
917 const GtkTargetEntry *targets,
922 g_return_if_fail (GTK_IS_WIDGET (widget));
923 g_return_if_fail (selection != GDK_NONE);
924 g_return_if_fail (targets != NULL);
926 list = gtk_selection_target_list_get (widget, selection);
927 gtk_target_list_add_table (list, targets, ntargets);
929 #ifdef GDK_WINDOWING_WIN32
932 GdkAtom *atoms = g_new (GdkAtom, ntargets);
934 for (i = 0; i < ntargets; ++i)
935 atoms[i] = gdk_atom_intern (targets[i].target, FALSE);
936 gdk_win32_selection_add_targets (gtk_widget_get_window (widget), selection, ntargets, atoms);
944 * gtk_selection_remove_all:
945 * @widget: a #GtkWidget
947 * Removes all handlers and unsets ownership of all
948 * selections for a widget. Called when widget is being
949 * destroyed. This function will not generally be
950 * called by applications.
953 gtk_selection_remove_all (GtkWidget *widget)
957 GtkSelectionInfo *selection_info;
959 g_return_if_fail (GTK_IS_WIDGET (widget));
961 /* Remove pending requests/incrs for this widget */
963 tmp_list = current_retrievals;
966 next = tmp_list->next;
967 if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget)
969 current_retrievals = g_list_remove_link (current_retrievals,
971 /* structure will be freed in timeout */
972 g_list_free (tmp_list);
977 /* Disclaim ownership of any selections */
979 tmp_list = current_selections;
982 next = tmp_list->next;
983 selection_info = (GtkSelectionInfo *)tmp_list->data;
985 if (selection_info->widget == widget)
987 gdk_selection_owner_set_for_display (selection_info->display,
989 selection_info->selection,
990 GDK_CURRENT_TIME, FALSE);
991 current_selections = g_list_remove_link (current_selections,
993 g_list_free (tmp_list);
994 g_slice_free (GtkSelectionInfo, selection_info);
1000 /* Remove all selection lists */
1001 gtk_selection_target_list_remove (widget);
1006 * gtk_selection_convert:
1007 * @widget: The widget which acts as requestor
1008 * @selection: Which selection to get
1009 * @target: Form of information desired (e.g., STRING)
1010 * @time_: Time of request (usually of triggering event)
1011 In emergency, you could use #GDK_CURRENT_TIME
1013 * Requests the contents of a selection. When received,
1014 * a "selection-received" signal will be generated.
1016 * Return value: %TRUE if requested succeeded. %FALSE if we could not process
1017 * request. (e.g., there was already a request in process for
1021 gtk_selection_convert (GtkWidget *widget,
1026 GtkRetrievalInfo *info;
1028 GdkWindow *owner_window;
1029 GdkDisplay *display;
1031 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
1032 g_return_val_if_fail (selection != GDK_NONE, FALSE);
1035 gtk_selection_init ();
1037 if (!gtk_widget_get_realized (widget))
1038 gtk_widget_realize (widget);
1040 /* Check to see if there are already any retrievals in progress for
1041 this widget. If we changed GDK to use the selection for the
1042 window property in which to store the retrieved information, then
1043 we could support multiple retrievals for different selections.
1044 This might be useful for DND. */
1046 tmp_list = current_retrievals;
1049 info = (GtkRetrievalInfo *)tmp_list->data;
1050 if (info->widget == widget)
1052 tmp_list = tmp_list->next;
1055 info = g_slice_new (GtkRetrievalInfo);
1057 info->widget = widget;
1058 info->selection = selection;
1059 info->target = target;
1060 info->idle_time = 0;
1061 info->buffer = NULL;
1064 /* Check if this process has current owner. If so, call handler
1065 procedure directly to avoid deadlocks with INCR. */
1067 display = gtk_widget_get_display (widget);
1068 owner_window = gdk_selection_owner_get_for_display (display, selection);
1070 if (owner_window != NULL)
1072 GtkWidget *owner_widget;
1073 gpointer owner_widget_ptr;
1074 GtkSelectionData selection_data;
1076 selection_data.selection = selection;
1077 selection_data.target = target;
1078 selection_data.data = NULL;
1079 selection_data.length = -1;
1080 selection_data.display = display;
1082 gdk_window_get_user_data (owner_window, &owner_widget_ptr);
1083 owner_widget = owner_widget_ptr;
1085 if (owner_widget != NULL)
1087 gtk_selection_invoke_handler (owner_widget,
1091 gtk_selection_retrieval_report (info,
1092 selection_data.type,
1093 selection_data.format,
1094 selection_data.data,
1095 selection_data.length,
1098 g_free (selection_data.data);
1099 selection_data.data = NULL;
1100 selection_data.length = -1;
1102 g_slice_free (GtkRetrievalInfo, info);
1107 /* Otherwise, we need to go through X */
1109 current_retrievals = g_list_append (current_retrievals, info);
1110 gdk_selection_convert (gtk_widget_get_window (widget), selection, target, time_);
1111 gdk_threads_add_timeout (1000,
1112 (GSourceFunc) gtk_selection_retrieval_timeout, info);
1118 * gtk_selection_data_get_selection:
1119 * @selection_data: a pointer to a #GtkSelectionData structure.
1121 * Retrieves the selection #GdkAtom of the selection data.
1123 * Returns: the selection #GdkAtom of the selection data.
1128 gtk_selection_data_get_selection (const GtkSelectionData *selection_data)
1130 g_return_val_if_fail (selection_data != NULL, 0);
1132 return selection_data->selection;
1136 * gtk_selection_data_get_target:
1137 * @selection_data: a pointer to a #GtkSelectionData structure.
1139 * Retrieves the target of the selection.
1141 * Returns: the target of the selection.
1146 gtk_selection_data_get_target (const GtkSelectionData *selection_data)
1148 g_return_val_if_fail (selection_data != NULL, 0);
1150 return selection_data->target;
1154 * gtk_selection_data_get_data_type:
1155 * @selection_data: a pointer to a #GtkSelectionData structure.
1157 * Retrieves the data type of the selection.
1159 * Returns: the data type of the selection.
1164 gtk_selection_data_get_data_type (const GtkSelectionData *selection_data)
1166 g_return_val_if_fail (selection_data != NULL, 0);
1168 return selection_data->type;
1172 * gtk_selection_data_get_format:
1173 * @selection_data: a pointer to a #GtkSelectionData structure.
1175 * Retrieves the format of the selection.
1177 * Returns: the format of the selection.
1182 gtk_selection_data_get_format (const GtkSelectionData *selection_data)
1184 g_return_val_if_fail (selection_data != NULL, 0);
1186 return selection_data->format;
1190 * gtk_selection_data_get_data:
1191 * @selection_data: a pointer to a #GtkSelectionData structure.
1193 * Retrieves the raw data of the selection.
1195 * Returns: the raw data of the selection.
1200 gtk_selection_data_get_data (const GtkSelectionData *selection_data)
1202 g_return_val_if_fail (selection_data != NULL, NULL);
1204 return selection_data->data;
1208 * gtk_selection_data_get_length:
1209 * @selection_data: a pointer to a #GtkSelectionData structure.
1211 * Retrieves the length of the raw data of the selection.
1213 * Returns: the length of the data of the selection.
1218 gtk_selection_data_get_length (const GtkSelectionData *selection_data)
1220 g_return_val_if_fail (selection_data != NULL, -1);
1222 return selection_data->length;
1226 * gtk_selection_data_get_display:
1227 * @selection_data: a pointer to a #GtkSelectionData structure.
1229 * Retrieves the display of the selection.
1231 * Returns: (transfer none): the display of the selection.
1236 gtk_selection_data_get_display (const GtkSelectionData *selection_data)
1238 g_return_val_if_fail (selection_data != NULL, NULL);
1240 return selection_data->display;
1244 * gtk_selection_data_set:
1245 * @selection_data: a pointer to a #GtkSelectionData structure.
1246 * @type: the type of selection data
1247 * @format: format (number of bits in a unit)
1248 * @data: (array) (element-type guchar): pointer to the data (will be copied)
1249 * @length: length of the data
1251 * Stores new data into a #GtkSelectionData object. Should
1252 * <emphasis>only</emphasis> be called from a selection handler callback.
1253 * Zero-terminates the stored data.
1256 gtk_selection_data_set (GtkSelectionData *selection_data,
1262 g_return_if_fail (selection_data != NULL);
1264 g_free (selection_data->data);
1266 selection_data->type = type;
1267 selection_data->format = format;
1271 selection_data->data = g_new (guchar, length+1);
1272 memcpy (selection_data->data, data, length);
1273 selection_data->data[length] = 0;
1277 g_return_if_fail (length <= 0);
1280 selection_data->data = NULL;
1282 selection_data->data = (guchar *) g_strdup ("");
1285 selection_data->length = length;
1289 selection_set_string (GtkSelectionData *selection_data,
1293 gchar *tmp = g_strndup (str, len);
1294 gchar *latin1 = gdk_utf8_to_string_target (tmp);
1299 gtk_selection_data_set (selection_data,
1300 GDK_SELECTION_TYPE_STRING,
1301 8, (guchar *) latin1, strlen (latin1));
1311 selection_set_compound_text (GtkSelectionData *selection_data,
1320 gboolean result = FALSE;
1322 #ifdef GDK_WINDOWING_X11
1323 if (GDK_IS_X11_DISPLAY (selection_data->display))
1325 tmp = g_strndup (str, len);
1326 if (gdk_x11_display_utf8_to_compound_text (selection_data->display, tmp,
1327 &encoding, &format, &text, &new_length))
1329 gtk_selection_data_set (selection_data, encoding, format, text, new_length);
1330 gdk_x11_free_compound_text (text);
1341 /* Normalize \r and \n into \r\n
1344 normalize_to_crlf (const gchar *str,
1347 GString *result = g_string_sized_new (len);
1348 const gchar *p = str;
1349 const gchar *end = str + len;
1354 g_string_append_c (result, '\r');
1358 g_string_append_c (result, *p);
1360 if (p == end || *p != '\n')
1361 g_string_append_c (result, '\n');
1366 g_string_append_c (result, *p);
1370 return g_string_free (result, FALSE);
1373 /* Normalize \r and \r\n into \n
1376 normalize_to_lf (gchar *str,
1379 GString *result = g_string_sized_new (len);
1380 const gchar *p = str;
1388 g_string_append_c (result, '\n');
1394 g_string_append_c (result, *p);
1398 return g_string_free (result, FALSE);
1402 selection_set_text_plain (GtkSelectionData *selection_data,
1406 const gchar *charset = NULL;
1408 GError *error = NULL;
1410 result = normalize_to_crlf (str, len);
1411 if (selection_data->target == text_plain_atom)
1413 else if (selection_data->target == text_plain_locale_atom)
1414 g_get_charset (&charset);
1418 gchar *tmp = result;
1419 result = g_convert_with_fallback (tmp, -1,
1421 NULL, NULL, NULL, &error);
1427 g_warning ("Error converting from %s to %s: %s",
1428 "UTF-8", charset, error->message);
1429 g_error_free (error);
1434 gtk_selection_data_set (selection_data,
1435 selection_data->target,
1436 8, (guchar *) result, strlen (result));
1443 selection_get_text_plain (const GtkSelectionData *selection_data)
1445 const gchar *charset = NULL;
1446 gchar *str, *result;
1448 GError *error = NULL;
1450 str = g_strdup ((const gchar *) selection_data->data);
1451 len = selection_data->length;
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);
1461 str = g_convert_with_fallback (tmp, len,
1463 NULL, NULL, &len, &error);
1468 g_warning ("Error converting from %s to %s: %s",
1469 charset, "UTF-8", error->message);
1470 g_error_free (error);
1475 else if (!g_utf8_validate (str, -1, NULL))
1477 g_warning ("Error converting from %s to %s: %s",
1478 "text/plain;charset=utf-8", "UTF-8", "invalid UTF-8");
1484 result = normalize_to_lf (str, len);
1487 return (guchar *) result;
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.
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.
1500 * Return value: %TRUE if the selection was successfully set,
1504 gtk_selection_data_set_text (GtkSelectionData *selection_data,
1508 g_return_val_if_fail (selection_data != NULL, FALSE);
1515 if (selection_data->target == utf8_atom)
1517 gtk_selection_data_set (selection_data,
1519 8, (guchar *)str, len);
1522 else if (selection_data->target == GDK_TARGET_STRING)
1524 return selection_set_string (selection_data, str, len);
1526 else if (selection_data->target == ctext_atom ||
1527 selection_data->target == text_atom)
1529 if (selection_set_compound_text (selection_data, str, len))
1531 else if (selection_data->target == text_atom)
1532 return selection_set_string (selection_data, str, len);
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)
1538 return selection_set_text_plain (selection_data, str, len);
1545 * gtk_selection_data_get_text:
1546 * @selection_data: a #GtkSelectionData
1548 * Gets the contents of the selection data as a UTF-8 string.
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().
1556 gtk_selection_data_get_text (const GtkSelectionData *selection_data)
1558 guchar *result = NULL;
1560 g_return_val_if_fail (selection_data != NULL, NULL);
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))
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,
1578 result = (guchar *) list[0];
1580 for (i = 1; i < count; i++)
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))
1589 result = selection_get_text_plain (selection_data);
1596 * gtk_selection_data_set_pixbuf:
1597 * @selection_data: a #GtkSelectionData
1598 * @pixbuf: a #GdkPixbuf
1600 * Sets the contents of the selection from a #GdkPixbuf
1601 * The pixbuf is converted to the form determined by
1602 * @selection_data->target.
1604 * Return value: %TRUE if the selection was successfully set,
1610 gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data,
1613 GSList *formats, *f;
1620 g_return_val_if_fail (selection_data != NULL, FALSE);
1621 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
1623 formats = gdk_pixbuf_get_formats ();
1625 for (f = formats; f; f = f->next)
1627 GdkPixbufFormat *fmt = f->data;
1629 mimes = gdk_pixbuf_format_get_mime_types (fmt);
1630 for (m = mimes; *m; m++)
1632 atom = gdk_atom_intern (*m, FALSE);
1633 if (selection_data->target == atom)
1636 type = gdk_pixbuf_format_get_name (fmt);
1637 result = gdk_pixbuf_save_to_buffer (pixbuf, &str, &len,
1639 ((strcmp (type, "png") == 0) ?
1640 "compression" : NULL), "2",
1643 gtk_selection_data_set (selection_data,
1644 atom, 8, (guchar *)str, len);
1648 g_slist_free (formats);
1657 g_slist_free (formats);
1663 * gtk_selection_data_get_pixbuf:
1664 * @selection_data: a #GtkSelectionData
1666 * Gets the contents of the selection data as a #GdkPixbuf.
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().
1676 gtk_selection_data_get_pixbuf (const GtkSelectionData *selection_data)
1678 GdkPixbufLoader *loader;
1679 GdkPixbuf *result = NULL;
1681 g_return_val_if_fail (selection_data != NULL, NULL);
1683 if (selection_data->length > 0)
1685 loader = gdk_pixbuf_loader_new ();
1687 gdk_pixbuf_loader_write (loader,
1688 selection_data->data,
1689 selection_data->length,
1691 gdk_pixbuf_loader_close (loader, NULL);
1692 result = gdk_pixbuf_loader_get_pixbuf (loader);
1695 g_object_ref (result);
1697 g_object_unref (loader);
1704 * gtk_selection_data_set_uris:
1705 * @selection_data: a #GtkSelectionData
1706 * @uris: a %NULL-terminated array of strings holding URIs
1708 * Sets the contents of the selection from a list of URIs.
1709 * The string is converted to the form determined by
1710 * @selection_data->target.
1712 * Return value: %TRUE if the selection was successfully set,
1718 gtk_selection_data_set_uris (GtkSelectionData *selection_data,
1721 g_return_val_if_fail (selection_data != NULL, FALSE);
1722 g_return_val_if_fail (uris != NULL, FALSE);
1726 if (selection_data->target == text_uri_list_atom)
1733 list = g_string_new (NULL);
1734 for (i = 0; uris[i]; i++)
1736 g_string_append (list, uris[i]);
1737 g_string_append (list, "\r\n");
1740 result = g_convert (list->str, list->len,
1742 NULL, &length, NULL);
1743 g_string_free (list, TRUE);
1747 gtk_selection_data_set (selection_data,
1749 8, (guchar *)result, length);
1761 * gtk_selection_data_get_uris:
1762 * @selection_data: a #GtkSelectionData
1764 * Gets the contents of the selection data as array of URIs.
1766 * Return value: (array zero-terminated=1) (element-type utf8) (transfer full): if
1767 * the selection data contains a list of
1768 * URIs, a newly allocated %NULL-terminated string array
1769 * containing the URIs, otherwise %NULL. If the result is
1770 * non-%NULL it must be freed with g_strfreev().
1775 gtk_selection_data_get_uris (const GtkSelectionData *selection_data)
1777 gchar **result = NULL;
1779 g_return_val_if_fail (selection_data != NULL, NULL);
1783 if (selection_data->length >= 0 &&
1784 selection_data->type == text_uri_list_atom)
1787 gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1789 selection_data->format,
1790 selection_data->data,
1791 selection_data->length,
1794 result = g_uri_list_extract_uris (list[0]);
1804 * gtk_selection_data_get_targets:
1805 * @selection_data: a #GtkSelectionData object
1806 * @targets: location to store an array of targets. The result
1807 * stored here must be freed with g_free().
1808 * @n_atoms: location to store number of items in @targets.
1810 * Gets the contents of @selection_data as an array of targets.
1811 * This can be used to interpret the results of getting
1812 * the standard TARGETS target that is always supplied for
1815 * Return value: %TRUE if @selection_data contains a valid
1816 * array of targets, otherwise %FALSE.
1819 gtk_selection_data_get_targets (const GtkSelectionData *selection_data,
1823 g_return_val_if_fail (selection_data != NULL, FALSE);
1825 if (selection_data->length >= 0 &&
1826 selection_data->format == 32 &&
1827 selection_data->type == GDK_SELECTION_TYPE_ATOM)
1830 *targets = g_memdup (selection_data->data, selection_data->length);
1832 *n_atoms = selection_data->length / sizeof (GdkAtom);
1848 * gtk_targets_include_text:
1849 * @targets: an array of #GdkAtom<!-- -->s
1850 * @n_targets: the length of @targets
1852 * Determines if any of the targets in @targets can be used to
1855 * Return value: %TRUE if @targets include a suitable target for text,
1861 gtk_targets_include_text (GdkAtom *targets,
1865 gboolean result = FALSE;
1867 g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
1869 /* Keep in sync with gtk_target_list_add_text_targets()
1874 for (i = 0; i < n_targets; i++)
1876 if (targets[i] == utf8_atom ||
1877 targets[i] == text_atom ||
1878 targets[i] == GDK_TARGET_STRING ||
1879 targets[i] == ctext_atom ||
1880 targets[i] == text_plain_atom ||
1881 targets[i] == text_plain_utf8_atom ||
1882 targets[i] == text_plain_locale_atom)
1893 * gtk_targets_include_rich_text:
1894 * @targets: an array of #GdkAtom<!-- -->s
1895 * @n_targets: the length of @targets
1896 * @buffer: a #GtkTextBuffer
1898 * Determines if any of the targets in @targets can be used to
1899 * provide rich text.
1901 * Return value: %TRUE if @targets include a suitable target for rich text,
1907 gtk_targets_include_rich_text (GdkAtom *targets,
1909 GtkTextBuffer *buffer)
1911 GdkAtom *rich_targets;
1912 gint n_rich_targets;
1914 gboolean result = FALSE;
1916 g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
1917 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1921 rich_targets = gtk_text_buffer_get_deserialize_formats (buffer,
1924 for (i = 0; i < n_targets; i++)
1926 for (j = 0; j < n_rich_targets; j++)
1928 if (targets[i] == rich_targets[j])
1937 g_free (rich_targets);
1943 * gtk_selection_data_targets_include_text:
1944 * @selection_data: a #GtkSelectionData object
1946 * Given a #GtkSelectionData object holding a list of targets,
1947 * determines if any of the targets in @targets can be used to
1950 * Return value: %TRUE if @selection_data holds a list of targets,
1951 * and a suitable target for text is included, otherwise %FALSE.
1954 gtk_selection_data_targets_include_text (const GtkSelectionData *selection_data)
1958 gboolean result = FALSE;
1960 g_return_val_if_fail (selection_data != NULL, FALSE);
1964 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1966 result = gtk_targets_include_text (targets, n_targets);
1974 * gtk_selection_data_targets_include_rich_text:
1975 * @selection_data: a #GtkSelectionData object
1976 * @buffer: a #GtkTextBuffer
1978 * Given a #GtkSelectionData object holding a list of targets,
1979 * determines if any of the targets in @targets can be used to
1980 * provide rich text.
1982 * Return value: %TRUE if @selection_data holds a list of targets,
1983 * and a suitable target for rich text is included,
1989 gtk_selection_data_targets_include_rich_text (const GtkSelectionData *selection_data,
1990 GtkTextBuffer *buffer)
1994 gboolean result = FALSE;
1996 g_return_val_if_fail (selection_data != NULL, FALSE);
1997 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
2001 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
2003 result = gtk_targets_include_rich_text (targets, n_targets, buffer);
2011 * gtk_targets_include_image:
2012 * @targets: an array of #GdkAtom<!-- -->s
2013 * @n_targets: the length of @targets
2014 * @writable: whether to accept only targets for which GTK+ knows
2015 * how to convert a pixbuf into the format
2017 * Determines if any of the targets in @targets can be used to
2018 * provide a #GdkPixbuf.
2020 * Return value: %TRUE if @targets include a suitable target for images,
2026 gtk_targets_include_image (GdkAtom *targets,
2030 GtkTargetList *list;
2033 gboolean result = FALSE;
2035 g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
2037 list = gtk_target_list_new (NULL, 0);
2038 gtk_target_list_add_image_targets (list, 0, writable);
2039 for (i = 0; i < n_targets && !result; i++)
2041 for (l = list->list; l; l = l->next)
2043 GtkTargetPair *pair = (GtkTargetPair *)l->data;
2044 if (pair->target == targets[i])
2051 gtk_target_list_unref (list);
2057 * gtk_selection_data_targets_include_image:
2058 * @selection_data: a #GtkSelectionData object
2059 * @writable: whether to accept only targets for which GTK+ knows
2060 * how to convert a pixbuf into the format
2062 * Given a #GtkSelectionData object holding a list of targets,
2063 * determines if any of the targets in @targets can be used to
2064 * provide a #GdkPixbuf.
2066 * Return value: %TRUE if @selection_data holds a list of targets,
2067 * and a suitable target for images is included, otherwise %FALSE.
2072 gtk_selection_data_targets_include_image (const GtkSelectionData *selection_data,
2077 gboolean result = FALSE;
2079 g_return_val_if_fail (selection_data != NULL, FALSE);
2083 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
2085 result = gtk_targets_include_image (targets, n_targets, writable);
2093 * gtk_targets_include_uri:
2094 * @targets: an array of #GdkAtom<!-- -->s
2095 * @n_targets: the length of @targets
2097 * Determines if any of the targets in @targets can be used to
2098 * provide an uri list.
2100 * Return value: %TRUE if @targets include a suitable target for uri lists,
2106 gtk_targets_include_uri (GdkAtom *targets,
2110 gboolean result = FALSE;
2112 g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
2114 /* Keep in sync with gtk_target_list_add_uri_targets()
2119 for (i = 0; i < n_targets; i++)
2121 if (targets[i] == text_uri_list_atom)
2132 * gtk_selection_data_targets_include_uri:
2133 * @selection_data: a #GtkSelectionData object
2135 * Given a #GtkSelectionData object holding a list of targets,
2136 * determines if any of the targets in @targets can be used to
2137 * provide a list or URIs.
2139 * Return value: %TRUE if @selection_data holds a list of targets,
2140 * and a suitable target for URI lists is included, otherwise %FALSE.
2145 gtk_selection_data_targets_include_uri (const GtkSelectionData *selection_data)
2149 gboolean result = FALSE;
2151 g_return_val_if_fail (selection_data != NULL, FALSE);
2155 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
2157 result = gtk_targets_include_uri (targets, n_targets);
2165 /*************************************************************
2166 * gtk_selection_init:
2167 * Initialize local variables
2171 *************************************************************/
2174 gtk_selection_init (void)
2176 gtk_selection_atoms[INCR] = gdk_atom_intern_static_string ("INCR");
2177 gtk_selection_atoms[MULTIPLE] = gdk_atom_intern_static_string ("MULTIPLE");
2178 gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern_static_string ("TIMESTAMP");
2179 gtk_selection_atoms[TARGETS] = gdk_atom_intern_static_string ("TARGETS");
2180 gtk_selection_atoms[SAVE_TARGETS] = gdk_atom_intern_static_string ("SAVE_TARGETS");
2186 * _gtk_selection_clear:
2187 * @widget: a #GtkWidget
2190 * The default handler for the #GtkWidget::selection-clear-event
2193 * Return value: %TRUE if the event was handled, otherwise false
2196 _gtk_selection_clear (GtkWidget *widget,
2197 GdkEventSelection *event)
2199 /* Note that we filter clear events in gdkselection-x11.c, so
2200 * that we only will get here if the clear event actually
2201 * represents a change that we didn't do ourself.
2204 GtkSelectionInfo *selection_info = NULL;
2206 tmp_list = current_selections;
2209 selection_info = (GtkSelectionInfo *)tmp_list->data;
2211 if ((selection_info->selection == event->selection) &&
2212 (selection_info->widget == widget))
2215 tmp_list = tmp_list->next;
2220 current_selections = g_list_remove_link (current_selections, tmp_list);
2221 g_list_free (tmp_list);
2222 g_slice_free (GtkSelectionInfo, selection_info);
2229 /*************************************************************
2230 * _gtk_selection_request:
2231 * Handler for "selection_request_event"
2236 *************************************************************/
2239 _gtk_selection_request (GtkWidget *widget,
2240 GdkEventSelection *event)
2242 GdkDisplay *display = gtk_widget_get_display (widget);
2246 gulong selection_max_size;
2249 gtk_selection_init ();
2251 selection_max_size = GTK_SELECTION_MAX_SIZE (display);
2253 /* Check if we own selection */
2255 tmp_list = current_selections;
2258 GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data;
2260 if ((selection_info->selection == event->selection) &&
2261 (selection_info->widget == widget))
2264 tmp_list = tmp_list->next;
2267 if (tmp_list == NULL)
2270 info = g_slice_new (GtkIncrInfo);
2272 g_object_ref (widget);
2274 info->selection = event->selection;
2275 info->num_incrs = 0;
2277 /* Create GdkWindow structure for the requestor */
2279 #ifdef GDK_WINDOWING_X11
2280 if (GDK_IS_X11_DISPLAY (display))
2281 info->requestor = gdk_x11_window_foreign_new_for_display (display, event->requestor);
2284 info->requestor = NULL;
2286 /* Determine conversions we need to perform */
2287 if (event->target == gtk_selection_atoms[MULTIPLE])
2296 gdk_error_trap_push ();
2297 if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */
2298 0, selection_max_size, FALSE,
2299 &type, &format, &length, &mult_atoms))
2301 gdk_selection_send_notify_for_display (display,
2307 g_free (mult_atoms);
2308 g_slice_free (GtkIncrInfo, info);
2309 gdk_error_trap_pop_ignored ();
2312 gdk_error_trap_pop_ignored ();
2314 /* This is annoying; the ICCCM doesn't specify the property type
2315 * used for the property contents, so the autoconversion for
2316 * ATOM / ATOM_PAIR in GDK doesn't work properly.
2318 #ifdef GDK_WINDOWING_X11
2319 if (type != GDK_SELECTION_TYPE_ATOM &&
2320 type != gdk_atom_intern_static_string ("ATOM_PAIR"))
2322 info->num_conversions = length / (2*sizeof (glong));
2323 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
2325 for (i=0; i<info->num_conversions; i++)
2327 info->conversions[i].target = gdk_x11_xatom_to_atom_for_display (display,
2328 ((glong *)mult_atoms)[2*i]);
2329 info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display,
2330 ((glong *)mult_atoms)[2*i + 1]);
2333 g_free (mult_atoms);
2338 info->num_conversions = length / (2*sizeof (GdkAtom));
2339 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
2341 for (i=0; i<info->num_conversions; i++)
2343 info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
2344 info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
2347 g_free (mult_atoms);
2350 else /* only a single conversion */
2352 info->conversions = g_new (GtkIncrConversion, 1);
2353 info->num_conversions = 1;
2354 info->conversions[0].target = event->target;
2355 info->conversions[0].property = event->property;
2358 /* Loop through conversions and determine which of these are big
2359 enough to require doing them via INCR */
2360 for (i=0; i<info->num_conversions; i++)
2362 GtkSelectionData data;
2365 data.selection = event->selection;
2366 data.target = info->conversions[i].target;
2369 data.display = gtk_widget_get_display (widget);
2371 #ifdef DEBUG_SELECTION
2372 g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
2374 info->conversions[i].target,
2375 gdk_atom_name (info->conversions[i].target),
2376 event->requestor, info->conversions[i].property);
2379 gtk_selection_invoke_handler (widget, &data, event->time);
2380 if (data.length < 0)
2382 info->conversions[i].property = GDK_NONE;
2386 g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
2388 items = data.length / gtk_selection_bytes_per_item (data.format);
2390 if (data.length > selection_max_size)
2392 /* Sending via INCR */
2393 #ifdef DEBUG_SELECTION
2394 g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n",
2395 data.length, selection_max_size);
2398 info->conversions[i].offset = 0;
2399 info->conversions[i].data = data;
2402 gdk_property_change (info->requestor,
2403 info->conversions[i].property,
2404 gtk_selection_atoms[INCR],
2406 GDK_PROP_MODE_REPLACE,
2407 (guchar *)&items, 1);
2411 info->conversions[i].offset = -1;
2413 gdk_property_change (info->requestor,
2414 info->conversions[i].property,
2417 GDK_PROP_MODE_REPLACE,
2424 /* If we have some INCR's, we need to send the rest of the data in
2427 if (info->num_incrs > 0)
2429 /* FIXME: this could be dangerous if window doesn't still
2432 #ifdef DEBUG_SELECTION
2433 g_message ("Starting INCR...");
2436 gdk_window_set_events (info->requestor,
2437 gdk_window_get_events (info->requestor) |
2438 GDK_PROPERTY_CHANGE_MASK);
2439 current_incrs = g_list_append (current_incrs, info);
2440 gdk_threads_add_timeout (1000, (GSourceFunc) gtk_selection_incr_timeout, info);
2443 /* If it was a MULTIPLE request, set the property to indicate which
2444 conversions succeeded */
2445 if (event->target == gtk_selection_atoms[MULTIPLE])
2447 GdkAtom *mult_atoms = g_new (GdkAtom, 2 * info->num_conversions);
2448 for (i = 0; i < info->num_conversions; i++)
2450 mult_atoms[2*i] = info->conversions[i].target;
2451 mult_atoms[2*i+1] = info->conversions[i].property;
2454 gdk_property_change (info->requestor, event->property,
2455 gdk_atom_intern_static_string ("ATOM_PAIR"), 32,
2456 GDK_PROP_MODE_REPLACE,
2457 (guchar *)mult_atoms, 2*info->num_conversions);
2458 g_free (mult_atoms);
2461 if (info->num_conversions == 1 &&
2462 info->conversions[0].property == GDK_NONE)
2464 /* Reject the entire conversion */
2465 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
2474 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
2482 if (info->num_incrs == 0)
2484 g_free (info->conversions);
2485 g_slice_free (GtkIncrInfo, info);
2488 g_object_unref (widget);
2493 /*************************************************************
2494 * _gtk_selection_incr_event:
2495 * Called whenever an PropertyNotify event occurs for an
2496 * GdkWindow with user_data == NULL. These will be notifications
2497 * that a window we are sending the selection to via the
2498 * INCR protocol has deleted a property and is ready for
2502 * window: the requestor window
2503 * event: the property event structure
2506 *************************************************************/
2509 _gtk_selection_incr_event (GdkWindow *window,
2510 GdkEventProperty *event)
2513 GtkIncrInfo *info = NULL;
2516 gulong selection_max_size;
2520 if (event->state != GDK_PROPERTY_DELETE)
2523 #ifdef DEBUG_SELECTION
2524 g_message ("PropertyDelete, property %ld", event->atom);
2527 selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_window_get_display (window));
2529 /* Now find the appropriate ongoing INCR */
2530 tmp_list = current_incrs;
2533 info = (GtkIncrInfo *)tmp_list->data;
2534 if (info->requestor == event->window)
2537 tmp_list = tmp_list->next;
2540 if (tmp_list == NULL)
2543 /* Find out which target this is for */
2544 for (i=0; i<info->num_conversions; i++)
2546 if (info->conversions[i].property == event->atom &&
2547 info->conversions[i].offset != -1)
2551 info->idle_time = 0;
2553 if (info->conversions[i].offset == -2) /* only the last 0-length
2561 num_bytes = info->conversions[i].data.length -
2562 info->conversions[i].offset;
2563 buffer = info->conversions[i].data.data +
2564 info->conversions[i].offset;
2566 if (num_bytes > selection_max_size)
2568 num_bytes = selection_max_size;
2569 info->conversions[i].offset += selection_max_size;
2572 info->conversions[i].offset = -2;
2574 #ifdef DEBUG_SELECTION
2575 g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
2576 num_bytes, info->conversions[i].offset,
2577 GDK_WINDOW_XID(info->requestor), event->atom);
2580 bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
2581 gdk_property_change (info->requestor, event->atom,
2582 info->conversions[i].data.type,
2583 info->conversions[i].data.format,
2584 GDK_PROP_MODE_REPLACE,
2586 num_bytes / bytes_per_item);
2588 if (info->conversions[i].offset == -2)
2590 g_free (info->conversions[i].data.data);
2591 info->conversions[i].data.data = NULL;
2597 info->conversions[i].offset = -1;
2602 /* Check if we're finished with all the targets */
2604 if (info->num_incrs == 0)
2606 current_incrs = g_list_remove_link (current_incrs, tmp_list);
2607 g_list_free (tmp_list);
2608 /* Let the timeout free it */
2614 /*************************************************************
2615 * gtk_selection_incr_timeout:
2616 * Timeout callback for the sending portion of the INCR
2619 * info: Information about this incr
2621 *************************************************************/
2624 gtk_selection_incr_timeout (GtkIncrInfo *info)
2629 /* Determine if retrieval has finished by checking if it still in
2630 list of pending retrievals */
2632 tmp_list = current_incrs;
2635 if (info == (GtkIncrInfo *)tmp_list->data)
2637 tmp_list = tmp_list->next;
2640 /* If retrieval is finished */
2641 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2643 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2645 current_incrs = g_list_remove_link (current_incrs, tmp_list);
2646 g_list_free (tmp_list);
2649 g_free (info->conversions);
2650 /* FIXME: we should check if requestor window is still in use,
2651 and if not, remove it? */
2653 g_slice_free (GtkIncrInfo, info);
2655 retval = FALSE; /* remove timeout */
2661 retval = TRUE; /* timeout will happen again */
2667 /*************************************************************
2668 * _gtk_selection_notify:
2669 * Handler for "selection-notify-event" signals on windows
2670 * where a retrieval is currently in process. The selection
2671 * owner has responded to our conversion request.
2673 * widget: Widget getting signal
2674 * event: Selection event structure
2675 * info: Information about this retrieval
2677 * was event handled?
2678 *************************************************************/
2681 _gtk_selection_notify (GtkWidget *widget,
2682 GdkEventSelection *event)
2685 GtkRetrievalInfo *info = NULL;
2687 guchar *buffer = NULL;
2692 #ifdef DEBUG_SELECTION
2693 g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
2694 event->selection, event->target, event->property);
2697 window = gtk_widget_get_window (widget);
2699 tmp_list = current_retrievals;
2702 info = (GtkRetrievalInfo *)tmp_list->data;
2703 if (info->widget == widget && info->selection == event->selection)
2705 tmp_list = tmp_list->next;
2708 if (!tmp_list) /* no retrieval in progress */
2711 if (event->property != GDK_NONE)
2712 length = gdk_selection_property_get (window, &buffer,
2715 length = 0; /* silence gcc */
2717 if (event->property == GDK_NONE || buffer == NULL)
2719 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2720 g_list_free (tmp_list);
2721 /* structure will be freed in timeout */
2722 gtk_selection_retrieval_report (info,
2723 GDK_NONE, 0, NULL, -1, event->time);
2728 if (type == gtk_selection_atoms[INCR])
2730 /* The remainder of the selection will come through PropertyNotify
2733 info->notify_time = event->time;
2734 info->idle_time = 0;
2735 info->offset = 0; /* Mark as OK to proceed */
2736 gdk_window_set_events (window,
2737 gdk_window_get_events (window)
2738 | GDK_PROPERTY_CHANGE_MASK);
2742 /* We don't delete the info structure - that will happen in timeout */
2743 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2744 g_list_free (tmp_list);
2746 info->offset = length;
2747 gtk_selection_retrieval_report (info,
2749 buffer, length, event->time);
2752 gdk_property_delete (window, event->property);
2759 /*************************************************************
2760 * _gtk_selection_property_notify:
2761 * Handler for "property-notify-event" signals on windows
2762 * where a retrieval is currently in process. The selection
2763 * owner has added more data.
2765 * widget: Widget getting signal
2766 * event: Property event structure
2767 * info: Information about this retrieval
2769 * was event handled?
2770 *************************************************************/
2773 _gtk_selection_property_notify (GtkWidget *widget,
2774 GdkEventProperty *event)
2777 GtkRetrievalInfo *info = NULL;
2784 g_return_val_if_fail (widget != NULL, FALSE);
2785 g_return_val_if_fail (event != NULL, FALSE);
2787 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
2788 if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */
2789 (event->atom != gdk_atom_intern_static_string ("GDK_SELECTION"))) /* not the right property */
2793 #ifdef DEBUG_SELECTION
2794 g_message ("PropertyNewValue, property %ld",
2798 tmp_list = current_retrievals;
2801 info = (GtkRetrievalInfo *)tmp_list->data;
2802 if (info->widget == widget)
2804 tmp_list = tmp_list->next;
2807 if (!tmp_list) /* No retrieval in progress */
2810 if (info->offset < 0) /* We haven't got the SelectionNotify
2811 for this retrieval yet */
2814 info->idle_time = 0;
2816 window = gtk_widget_get_window (widget);
2817 length = gdk_selection_property_get (window, &new_buffer,
2819 gdk_property_delete (window, event->atom);
2821 /* We could do a lot better efficiency-wise by paying attention to
2822 what length was sent in the initial INCR transaction, instead of
2823 doing memory allocation at every step. But its only guaranteed to
2824 be a _lower bound_ (pretty useless!) */
2826 if (length == 0 || type == GDK_NONE) /* final zero length portion */
2828 /* Info structure will be freed in timeout */
2829 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2830 g_list_free (tmp_list);
2831 gtk_selection_retrieval_report (info,
2833 (type == GDK_NONE) ? NULL : info->buffer,
2834 (type == GDK_NONE) ? -1 : info->offset,
2837 else /* append on newly arrived data */
2841 #ifdef DEBUG_SELECTION
2842 g_message ("Start - Adding %d bytes at offset 0",
2845 info->buffer = new_buffer;
2846 info->offset = length;
2851 #ifdef DEBUG_SELECTION
2852 g_message ("Appending %d bytes at offset %d",
2853 length,info->offset);
2855 /* We copy length+1 bytes to preserve guaranteed null termination */
2856 info->buffer = g_realloc (info->buffer, info->offset+length+1);
2857 memcpy (info->buffer + info->offset, new_buffer, length+1);
2858 info->offset += length;
2859 g_free (new_buffer);
2866 /*************************************************************
2867 * gtk_selection_retrieval_timeout:
2868 * Timeout callback while receiving a selection.
2870 * info: Information about this retrieval
2872 *************************************************************/
2875 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
2880 /* Determine if retrieval has finished by checking if it still in
2881 list of pending retrievals */
2883 tmp_list = current_retrievals;
2886 if (info == (GtkRetrievalInfo *)tmp_list->data)
2888 tmp_list = tmp_list->next;
2891 /* If retrieval is finished */
2892 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2894 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2896 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2897 g_list_free (tmp_list);
2898 gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
2901 g_free (info->buffer);
2902 g_slice_free (GtkRetrievalInfo, info);
2904 retval = FALSE; /* remove timeout */
2910 retval = TRUE; /* timeout will happen again */
2916 /*************************************************************
2917 * gtk_selection_retrieval_report:
2918 * Emits a "selection-received" signal.
2920 * info: information about the retrieval that completed
2921 * buffer: buffer containing data (NULL => errror)
2922 * time: timestamp for data in buffer
2924 *************************************************************/
2927 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
2928 GdkAtom type, gint format,
2929 guchar *buffer, gint length,
2932 GtkSelectionData data;
2934 data.selection = info->selection;
2935 data.target = info->target;
2937 data.format = format;
2939 data.length = length;
2941 data.display = gtk_widget_get_display (info->widget);
2943 g_signal_emit_by_name (info->widget,
2944 "selection-received",
2948 /*************************************************************
2949 * gtk_selection_invoke_handler:
2950 * Finds and invokes handler for specified
2951 * widget/selection/target combination, calls
2952 * gtk_selection_default_handler if none exists.
2955 * widget: selection owner
2956 * data: selection data [INOUT]
2957 * time: time from requeset
2960 * Number of bytes written to buffer, -1 if error
2961 *************************************************************/
2964 gtk_selection_invoke_handler (GtkWidget *widget,
2965 GtkSelectionData *data,
2968 GtkTargetList *target_list;
2972 g_return_if_fail (widget != NULL);
2974 target_list = gtk_selection_target_list_get (widget, data->selection);
2975 if (data->target != gtk_selection_atoms[SAVE_TARGETS] &&
2977 gtk_target_list_find (target_list, data->target, &info))
2979 g_signal_emit_by_name (widget,
2985 gtk_selection_default_handler (widget, data);
2988 /*************************************************************
2989 * gtk_selection_default_handler:
2990 * Handles some default targets that exist for any widget
2991 * If it can't fit results into buffer, returns -1. This
2992 * won't happen in any conceivable case, since it would
2993 * require 1000 selection targets!
2996 * widget: selection owner
2997 * data: selection data [INOUT]
2999 *************************************************************/
3002 gtk_selection_default_handler (GtkWidget *widget,
3003 GtkSelectionData *data)
3005 if (data->target == gtk_selection_atoms[TIMESTAMP])
3007 /* Time which was used to obtain selection */
3009 GtkSelectionInfo *selection_info;
3011 tmp_list = current_selections;
3014 selection_info = (GtkSelectionInfo *)tmp_list->data;
3015 if ((selection_info->widget == widget) &&
3016 (selection_info->selection == data->selection))
3018 gulong time = selection_info->time;
3020 gtk_selection_data_set (data,
3021 GDK_SELECTION_TYPE_INTEGER,
3028 tmp_list = tmp_list->next;
3033 else if (data->target == gtk_selection_atoms[TARGETS])
3035 /* List of all targets supported for this widget/selection pair */
3039 GtkTargetList *target_list;
3040 GtkTargetPair *pair;
3042 target_list = gtk_selection_target_list_get (widget,
3044 count = g_list_length (target_list->list) + 3;
3046 data->type = GDK_SELECTION_TYPE_ATOM;
3048 data->length = count * sizeof (GdkAtom);
3050 /* selection data is always terminated by a trailing \0
3052 p = g_malloc (data->length + 1);
3053 data->data = (guchar *)p;
3054 data->data[data->length] = '\0';
3056 *p++ = gtk_selection_atoms[TIMESTAMP];
3057 *p++ = gtk_selection_atoms[TARGETS];
3058 *p++ = gtk_selection_atoms[MULTIPLE];
3060 tmp_list = target_list->list;
3063 pair = (GtkTargetPair *)tmp_list->data;
3064 *p++ = pair->target;
3066 tmp_list = tmp_list->next;
3069 else if (data->target == gtk_selection_atoms[SAVE_TARGETS])
3071 gtk_selection_data_set (data,
3072 gdk_atom_intern_static_string ("NULL"),
3083 * gtk_selection_data_copy:
3084 * @data: a pointer to a #GtkSelectionData structure.
3086 * Makes a copy of a #GtkSelectionData structure and its data.
3088 * Return value: a pointer to a copy of @data.
3091 gtk_selection_data_copy (const GtkSelectionData *data)
3093 GtkSelectionData *new_data;
3095 g_return_val_if_fail (data != NULL, NULL);
3097 new_data = g_slice_new (GtkSelectionData);
3102 new_data->data = g_malloc (data->length + 1);
3103 memcpy (new_data->data, data->data, data->length + 1);
3110 * gtk_selection_data_free:
3111 * @data: a pointer to a #GtkSelectionData structure.
3113 * Frees a #GtkSelectionData structure returned from
3114 * gtk_selection_data_copy().
3117 gtk_selection_data_free (GtkSelectionData *data)
3119 g_return_if_fail (data != NULL);
3121 g_free (data->data);
3123 g_slice_free (GtkSelectionData, data);
3127 * gtk_target_entry_new:
3128 * @target: String identifier for target
3129 * @flags: Set of flags, see #GtkTargetFlags
3130 * @info: an ID that will be passed back to the application
3132 * Makes a new #GtkTargetEntry structure.
3134 * Return value: a pointer to a new GtkTargetEntry structure.
3135 * Free with gtk_target_entry_free()
3138 gtk_target_entry_new (const char *target,
3142 GtkTargetEntry entry = { (char *) target, flags, info };
3143 return gtk_target_entry_copy (&entry);
3147 * gtk_target_entry_copy:
3148 * @data: a pointer to a #GtkTargetEntry structure.
3150 * Makes a copy of a #GtkTargetEntry structure and its data.
3152 * Return value: a pointer to a copy of @data.
3153 * Free with gtk_target_entry_free()
3156 gtk_target_entry_copy (GtkTargetEntry *data)
3158 GtkTargetEntry *new_data;
3160 g_return_val_if_fail (data != NULL, NULL);
3162 new_data = g_slice_new (GtkTargetEntry);
3163 new_data->target = g_strdup (data->target);
3164 new_data->flags = data->flags;
3165 new_data->info = data->info;
3171 * gtk_target_entry_free:
3172 * @data: a pointer to a #GtkTargetEntry structure.
3174 * Frees a #GtkTargetEntry structure returned from
3175 * gtk_target_entry_new() or gtk_target_entry_copy().
3178 gtk_target_entry_free (GtkTargetEntry *data)
3180 g_return_if_fail (data != NULL);
3182 g_free (data->target);
3184 g_slice_free (GtkTargetEntry, data);
3188 G_DEFINE_BOXED_TYPE (GtkSelectionData, gtk_selection_data,
3189 gtk_selection_data_copy,
3190 gtk_selection_data_free)
3192 G_DEFINE_BOXED_TYPE (GtkTargetList, gtk_target_list,
3193 gtk_target_list_ref,
3194 gtk_target_list_unref)
3196 G_DEFINE_BOXED_TYPE (GtkTargetEntry, gtk_target_entry,
3197 gtk_target_entry_copy,
3198 gtk_target_entry_free)
3201 gtk_selection_bytes_per_item (gint format)
3206 return sizeof (char);
3209 return sizeof (short);
3212 return sizeof (long);
3215 g_assert_not_reached();