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/.
61 #include "gtkselection.h"
63 #ifdef GDK_WINDOWING_X11
67 #undef DEBUG_SELECTION
69 /* Maximum size of a sent chunk, in bytes. Also the default size of
71 #ifdef GDK_WINDOWING_X11
72 #define GTK_SELECTION_MAX_SIZE(display) \
74 XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0 \
75 ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100 \
76 : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
78 /* No chunks on Win32 */
79 #define GTK_SELECTION_MAX_SIZE(display) G_MAXINT
82 #define IDLE_ABORT_TIME 300
92 typedef struct _GtkSelectionInfo GtkSelectionInfo;
93 typedef struct _GtkIncrConversion GtkIncrConversion;
94 typedef struct _GtkIncrInfo GtkIncrInfo;
95 typedef struct _GtkRetrievalInfo GtkRetrievalInfo;
97 struct _GtkSelectionInfo
100 GtkWidget *widget; /* widget that owns selection */
101 guint32 time; /* time used to acquire selection */
102 GdkDisplay *display; /* needed in gtk_selection_remove_all */
105 struct _GtkIncrConversion
107 GdkAtom target; /* Requested target */
108 GdkAtom property; /* Property to store in */
109 GtkSelectionData data; /* The data being supplied */
110 gint offset; /* Current offset in sent selection.
112 * -2 => Only the final (empty) portion
118 GdkWindow *requestor; /* Requestor window - we create a GdkWindow
119 so we can receive events */
120 GdkAtom selection; /* Selection we're sending */
122 GtkIncrConversion *conversions; /* Information about requested conversions -
123 * With MULTIPLE requests (benighted 1980's
124 * hardware idea), there can be more than
126 gint num_conversions;
127 gint num_incrs; /* number of remaining INCR style transactions */
132 struct _GtkRetrievalInfo
135 GdkAtom selection; /* Selection being retrieved. */
136 GdkAtom target; /* Form of selection that we requested */
137 guint32 idle_time; /* Number of seconds since we last heard
138 from selection owner */
139 guchar *buffer; /* Buffer in which to accumulate results */
140 gint offset; /* Current offset in buffer, -1 indicates
142 guint32 notify_time; /* Timestamp from SelectionNotify */
145 /* Local Functions */
146 static void gtk_selection_init (void);
147 static gint gtk_selection_incr_timeout (GtkIncrInfo *info);
148 static gint gtk_selection_retrieval_timeout (GtkRetrievalInfo *info);
149 static void gtk_selection_retrieval_report (GtkRetrievalInfo *info,
155 static void gtk_selection_invoke_handler (GtkWidget *widget,
156 GtkSelectionData *data,
158 static void gtk_selection_default_handler (GtkWidget *widget,
159 GtkSelectionData *data);
160 static int gtk_selection_bytes_per_item (gint format);
163 static gint initialize = TRUE;
164 static GList *current_retrievals = NULL;
165 static GList *current_incrs = NULL;
166 static GList *current_selections = NULL;
168 static GdkAtom gtk_selection_atoms[LAST_ATOM];
169 static const char gtk_selection_handler_key[] = "gtk-selection-handlers";
180 gtk_target_list_new (const GtkTargetEntry *targets,
183 GtkTargetList *result = g_new (GtkTargetList, 1);
185 result->ref_count = 1;
188 gtk_target_list_add_table (result, targets, ntargets);
194 gtk_target_list_ref (GtkTargetList *list)
196 g_return_if_fail (list != NULL);
202 gtk_target_list_unref (GtkTargetList *list)
204 g_return_if_fail (list != NULL);
205 g_return_if_fail (list->ref_count > 0);
208 if (list->ref_count == 0)
210 GList *tmp_list = list->list;
213 GtkTargetPair *pair = tmp_list->data;
216 tmp_list = tmp_list->next;
219 g_list_free (list->list);
225 gtk_target_list_add (GtkTargetList *list,
232 g_return_if_fail (list != NULL);
234 pair = g_new (GtkTargetPair, 1);
235 pair->target = target;
239 list->list = g_list_append (list->list, pair);
242 static GdkAtom utf8_atom;
243 static GdkAtom text_atom;
244 static GdkAtom ctext_atom;
245 static GdkAtom text_plain_atom;
246 static GdkAtom text_plain_utf8_atom;
247 static GdkAtom text_plain_locale_atom;
253 const gchar *charset;
257 utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
258 text_atom = gdk_atom_intern ("TEXT", FALSE);
259 ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
260 text_plain_atom = gdk_atom_intern ("text/plain", FALSE);
261 text_plain_utf8_atom = gdk_atom_intern ("text/plain;charset=utf-8", FALSE);
262 g_get_charset (&charset);
263 tmp = g_strdup_printf ("text/plain;charset=%s", charset);
264 text_plain_locale_atom = gdk_atom_intern (tmp, FALSE);
270 * gtk_target_list_add_text_targets:
271 * @list: a #GtkTargetList
273 * Adds the text targets supported by #GtkSelection to
274 * the target list. The targets are added with both flags
275 * and info being zero.
280 gtk_target_list_add_text_targets (GtkTargetList *list)
282 g_return_if_fail (list != NULL);
286 /* Keep in sync with gtk_selection_data_targets_include_text()
288 gtk_target_list_add (list, utf8_atom, 0, 0);
289 gtk_target_list_add (list, ctext_atom, 0, 0);
290 gtk_target_list_add (list, text_atom, 0, 0);
291 gtk_target_list_add (list, GDK_TARGET_STRING, 0, 0);
292 gtk_target_list_add (list, text_plain_utf8_atom, 0, 0);
293 gtk_target_list_add (list, text_plain_locale_atom, 0, 0);
294 gtk_target_list_add (list, text_plain_atom, 0, 0);
298 gtk_target_list_add_table (GtkTargetList *list,
299 const GtkTargetEntry *targets,
304 for (i=ntargets-1; i >= 0; i--)
306 GtkTargetPair *pair = g_new (GtkTargetPair, 1);
307 pair->target = gdk_atom_intern (targets[i].target, FALSE);
308 pair->flags = targets[i].flags;
309 pair->info = targets[i].info;
311 list->list = g_list_prepend (list->list, pair);
316 gtk_target_list_remove (GtkTargetList *list,
321 g_return_if_fail (list != NULL);
323 tmp_list = list->list;
326 GtkTargetPair *pair = tmp_list->data;
328 if (pair->target == target)
332 list->list = g_list_remove_link (list->list, tmp_list);
333 g_list_free_1 (tmp_list);
338 tmp_list = tmp_list->next;
343 gtk_target_list_find (GtkTargetList *list,
347 GList *tmp_list = list->list;
350 GtkTargetPair *pair = tmp_list->data;
352 if (pair->target == target)
357 tmp_list = tmp_list->next;
364 * gtk_selection_owner_set_for_display:
365 * @display: the #Gdkdisplay where the selection is set
366 * @widget: new selection owner (a #GdkWidget), or %NULL.
367 * @selection: an interned atom representing the selection to claim.
368 * @time_: timestamp with which to claim the selection
370 * Claim ownership of a given selection for a particular widget, or,
371 * if @widget is %NULL, release ownership of the selection.
373 * Return value: TRUE if the operation succeeded
378 gtk_selection_owner_set_for_display (GdkDisplay *display,
384 GtkWidget *old_owner;
385 GtkSelectionInfo *selection_info = NULL;
388 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
389 g_return_val_if_fail (selection != GDK_NONE, FALSE);
390 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
391 g_return_val_if_fail (widget == NULL || gtk_widget_get_display (widget) == display, FALSE);
396 window = widget->window;
398 tmp_list = current_selections;
401 if (((GtkSelectionInfo *)tmp_list->data)->selection == selection)
403 selection_info = tmp_list->data;
407 tmp_list = tmp_list->next;
410 if (gdk_selection_owner_set_for_display (display, window, selection, time, TRUE))
418 old_owner = selection_info->widget;
419 current_selections = g_list_remove_link (current_selections,
421 g_list_free (tmp_list);
422 g_free (selection_info);
427 if (selection_info == NULL)
429 selection_info = g_new (GtkSelectionInfo, 1);
430 selection_info->selection = selection;
431 selection_info->widget = widget;
432 selection_info->time = time;
433 selection_info->display = display;
434 current_selections = g_list_prepend (current_selections,
439 old_owner = selection_info->widget;
440 selection_info->widget = widget;
441 selection_info->time = time;
442 selection_info->display = display;
445 /* If another widget in the application lost the selection,
446 * send it a GDK_SELECTION_CLEAR event.
448 if (old_owner && old_owner != widget)
450 GdkEvent *event = gdk_event_new (GDK_SELECTION_CLEAR);
452 event->selection.window = g_object_ref (old_owner->window);
453 event->selection.selection = selection;
454 event->selection.time = time;
456 gtk_widget_event (old_owner, event);
458 gdk_event_free (event);
467 * gtk_selection_owner_set:
468 * @widget: a #GtkWidget, or %NULL.
469 * @selection: an interned atom representing the selection to claim
470 * @time_: timestamp with which to claim the selection
472 * Claims ownership of a given selection for a particular widget,
473 * or, if @widget is %NULL, release ownership of the selection.
475 * Return value: %TRUE if the operation succeeded
478 gtk_selection_owner_set (GtkWidget *widget,
484 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
485 g_return_val_if_fail (selection != GDK_NONE, FALSE);
488 display = gtk_widget_get_display (widget);
492 g_warning ("gtk_selection_owner_set (NULL,...) is not multihead safe"));
494 display = gdk_display_get_default ();
497 return gtk_selection_owner_set_for_display (display, widget,
501 /*************************************************************
502 * gtk_selection_add_target
503 * Add specified target to list of supported targets
506 * widget: The widget for which this target applies
509 * info: guint to pass to to the selection_get signal
512 *************************************************************/
514 typedef struct _GtkSelectionTargetList GtkSelectionTargetList;
516 struct _GtkSelectionTargetList {
521 static GtkTargetList *
522 gtk_selection_target_list_get (GtkWidget *widget,
525 GtkSelectionTargetList *sellist;
529 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
534 sellist = tmp_list->data;
535 if (sellist->selection == selection)
536 return sellist->list;
537 tmp_list = tmp_list->next;
540 sellist = g_new (GtkSelectionTargetList, 1);
541 sellist->selection = selection;
542 sellist->list = gtk_target_list_new (NULL, 0);
544 lists = g_list_prepend (lists, sellist);
545 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
547 return sellist->list;
551 gtk_selection_target_list_remove (GtkWidget *widget)
553 GtkSelectionTargetList *sellist;
557 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
562 sellist = tmp_list->data;
564 gtk_target_list_unref (sellist->list);
567 tmp_list = tmp_list->next;
571 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, NULL);
575 * gtk_selection_clear_targets:
576 * @widget: a #GtkWidget
577 * @selection: an atom representing a selection
579 * Remove all targets registered for the given selection for the
583 gtk_selection_clear_targets (GtkWidget *widget,
586 GtkSelectionTargetList *sellist;
590 g_return_if_fail (GTK_IS_WIDGET (widget));
591 g_return_if_fail (selection != GDK_NONE);
593 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
598 sellist = tmp_list->data;
599 if (sellist->selection == selection)
601 lists = g_list_delete_link (lists, tmp_list);
602 gtk_target_list_unref (sellist->list);
608 tmp_list = tmp_list->next;
611 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
615 gtk_selection_add_target (GtkWidget *widget,
622 g_return_if_fail (GTK_IS_WIDGET (widget));
623 g_return_if_fail (selection != GDK_NONE);
625 list = gtk_selection_target_list_get (widget, selection);
626 gtk_target_list_add (list, target, 0, info);
630 gtk_selection_add_targets (GtkWidget *widget,
632 const GtkTargetEntry *targets,
637 g_return_if_fail (GTK_IS_WIDGET (widget));
638 g_return_if_fail (selection != GDK_NONE);
639 g_return_if_fail (targets != NULL);
641 list = gtk_selection_target_list_get (widget, selection);
642 gtk_target_list_add_table (list, targets, ntargets);
646 /*************************************************************
647 * gtk_selection_remove_all:
648 * Removes all handlers and unsets ownership of all
649 * selections for a widget. Called when widget is being
655 *************************************************************/
658 gtk_selection_remove_all (GtkWidget *widget)
662 GtkSelectionInfo *selection_info;
664 /* Remove pending requests/incrs for this widget */
666 tmp_list = current_retrievals;
669 next = tmp_list->next;
670 if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget)
672 current_retrievals = g_list_remove_link (current_retrievals,
674 /* structure will be freed in timeout */
675 g_list_free (tmp_list);
680 /* Disclaim ownership of any selections */
682 tmp_list = current_selections;
685 next = tmp_list->next;
686 selection_info = (GtkSelectionInfo *)tmp_list->data;
688 if (selection_info->widget == widget)
690 gdk_selection_owner_set_for_display (selection_info->display,
692 selection_info->selection,
693 GDK_CURRENT_TIME, FALSE);
694 current_selections = g_list_remove_link (current_selections,
696 g_list_free (tmp_list);
697 g_free (selection_info);
703 /* Remove all selection lists */
704 gtk_selection_target_list_remove (widget);
707 /*************************************************************
708 * gtk_selection_convert:
709 * Request the contents of a selection. When received,
710 * a "selection_received" signal will be generated.
713 * widget: The widget which acts as requestor
714 * selection: Which selection to get
715 * target: Form of information desired (e.g., STRING)
716 * time: Time of request (usually of triggering event)
717 * In emergency, you could use GDK_CURRENT_TIME
720 * TRUE if requested succeeded. FALSE if we could not process
721 * request. (e.g., there was already a request in process for
723 *************************************************************/
726 gtk_selection_convert (GtkWidget *widget,
731 GtkRetrievalInfo *info;
733 GdkWindow *owner_window;
736 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
737 g_return_val_if_fail (selection != GDK_NONE, FALSE);
740 gtk_selection_init ();
742 if (!GTK_WIDGET_REALIZED (widget))
743 gtk_widget_realize (widget);
745 /* Check to see if there are already any retrievals in progress for
746 this widget. If we changed GDK to use the selection for the
747 window property in which to store the retrieved information, then
748 we could support multiple retrievals for different selections.
749 This might be useful for DND. */
751 tmp_list = current_retrievals;
754 info = (GtkRetrievalInfo *)tmp_list->data;
755 if (info->widget == widget)
757 tmp_list = tmp_list->next;
760 info = g_new (GtkRetrievalInfo, 1);
762 info->widget = widget;
763 info->selection = selection;
764 info->target = target;
769 /* Check if this process has current owner. If so, call handler
770 procedure directly to avoid deadlocks with INCR. */
772 display = gtk_widget_get_display (widget);
773 owner_window = gdk_selection_owner_get_for_display (display, selection);
775 if (owner_window != NULL)
777 GtkWidget *owner_widget;
778 GtkSelectionData selection_data;
780 selection_data.selection = selection;
781 selection_data.target = target;
782 selection_data.data = NULL;
783 selection_data.length = -1;
784 selection_data.display = display;
786 gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget);
788 if (owner_widget != NULL)
790 gtk_selection_invoke_handler (owner_widget,
794 gtk_selection_retrieval_report (info,
796 selection_data.format,
798 selection_data.length,
801 g_free (selection_data.data);
808 /* Otherwise, we need to go through X */
810 current_retrievals = g_list_append (current_retrievals, info);
811 gdk_selection_convert (widget->window, selection, target, time);
812 g_timeout_add (1000, (GSourceFunc) gtk_selection_retrieval_timeout, info);
817 /*************************************************************
818 * gtk_selection_data_set:
819 * Store new data into a GtkSelectionData object. Should
820 * _only_ by called from a selection handler callback.
821 * Null terminates the stored data.
823 * type: the type of selection data
824 * format: format (number of bits in a unit)
825 * data: pointer to the data (will be copied)
826 * length: length of the data
828 *************************************************************/
831 gtk_selection_data_set (GtkSelectionData *selection_data,
837 if (selection_data->data)
838 g_free (selection_data->data);
840 selection_data->type = type;
841 selection_data->format = format;
845 selection_data->data = g_new (guchar, length+1);
846 memcpy (selection_data->data, data, length);
847 selection_data->data[length] = 0;
851 g_return_if_fail (length <= 0);
854 selection_data->data = NULL;
856 selection_data->data = g_strdup("");
859 selection_data->length = length;
863 selection_set_string (GtkSelectionData *selection_data,
867 gchar *tmp = g_strndup (str, len);
868 gchar *latin1 = gdk_utf8_to_string_target (tmp);
873 gtk_selection_data_set (selection_data,
874 GDK_SELECTION_TYPE_STRING,
875 8, latin1, strlen (latin1));
885 selection_set_compound_text (GtkSelectionData *selection_data,
894 gboolean result = FALSE;
896 tmp = g_strndup (str, len);
897 if (gdk_utf8_to_compound_text_for_display (selection_data->display, tmp,
898 &encoding, &format, &text, &new_length))
900 gtk_selection_data_set (selection_data, encoding, format, text, new_length);
901 gdk_free_compound_text (text);
911 /* Normalize \r and \n into \r\n
914 normalize_to_crlf (const gchar *str,
917 GString *result = g_string_sized_new (len);
918 const gchar *p = str;
923 g_string_append_c (result, '\r');
927 g_string_append_c (result, *p);
930 g_string_append_c (result, '\n');
936 g_string_append_c (result, *p);
940 return g_string_free (result, FALSE);
943 /* Normalize \r and \r\n into \n
946 normalize_to_lf (gchar *str,
949 GString *result = g_string_sized_new (len);
950 const gchar *p = str;
958 g_string_append_c (result, '\n');
964 g_string_append_c (result, *p);
968 return g_string_free (result, FALSE);
972 selection_set_text_plain (GtkSelectionData *selection_data,
976 const gchar *charset = NULL;
978 GError *error = NULL;
980 result = normalize_to_crlf (str, len);
981 if (selection_data->target == text_plain_atom)
983 else if (selection_data->target == text_plain_locale_atom)
984 g_get_charset (&charset);
989 result = g_convert_with_fallback (tmp, -1,
991 NULL, NULL, NULL, &error);
997 g_warning ("Error converting from UTF-8 to %s: %s",
998 charset, error->message);
999 g_error_free (error);
1004 gtk_selection_data_set (selection_data,
1005 selection_data->target,
1006 8, result, strlen (result));
1013 selection_get_text_plain (GtkSelectionData *selection_data)
1015 const gchar *charset = NULL;
1016 gchar *str, *result;
1018 GError *error = NULL;
1020 str = g_strdup (selection_data->data);
1021 len = selection_data->length;
1023 if (selection_data->type == text_plain_atom)
1024 charset = "ISO-8859-1";
1025 else if (selection_data->type == text_plain_locale_atom)
1026 g_get_charset (&charset);
1031 str = g_convert_with_fallback (tmp, len,
1033 NULL, NULL, &len, &error);
1038 g_warning ("Error converting from %s to UTF-8: %s",
1039 charset, error->message);
1040 g_error_free (error);
1045 else if (!g_utf8_validate (str, -1, NULL))
1047 g_warning ("Error converting from text/plain;charset=utf-8 to UTF-8");
1053 result = normalize_to_lf (str, len);
1060 * gtk_selection_data_set_text:
1061 * @selection_data: a #GtkSelectionData
1062 * @str: a UTF-8 string
1063 * @len: the length of @str, or -1 if @str is nul-terminated.
1065 * Sets the contents of the selection from a UTF-8 encoded string.
1066 * The string is converted to the form determined by
1067 * @selection_data->target.
1069 * Return value: %TRUE if the selection was successfully set,
1073 gtk_selection_data_set_text (GtkSelectionData *selection_data,
1082 if (selection_data->target == utf8_atom)
1084 gtk_selection_data_set (selection_data,
1086 8, (guchar *)str, len);
1089 else if (selection_data->target == GDK_TARGET_STRING)
1091 return selection_set_string (selection_data, str, len);
1093 else if (selection_data->target == ctext_atom ||
1094 selection_data->target == text_atom)
1096 if (selection_set_compound_text (selection_data, str, len))
1098 else if (selection_data->target == text_atom)
1099 return selection_set_string (selection_data, str, len);
1101 else if (selection_data->target == text_plain_atom ||
1102 selection_data->target == text_plain_utf8_atom ||
1103 selection_data->target == text_plain_locale_atom)
1105 return selection_set_text_plain (selection_data, str, len);
1112 * gtk_selection_data_get_text:
1113 * @selection_data: a #GtkSelectionData
1115 * Gets the contents of the selection data as a UTF-8 string.
1117 * Return value: if the selection data contained a recognized
1118 * text type and it could be converted to UTF-8, a newly allocated
1119 * string containing the converted text, otherwise %NULL.
1120 * If the result is non-%NULL it must be freed with g_free().
1123 gtk_selection_data_get_text (GtkSelectionData *selection_data)
1125 guchar *result = NULL;
1129 if (selection_data->length >= 0 &&
1130 (selection_data->type == GDK_TARGET_STRING ||
1131 selection_data->type == ctext_atom ||
1132 selection_data->type == utf8_atom))
1136 gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1137 selection_data->type,
1138 selection_data->format,
1139 selection_data->data,
1140 selection_data->length,
1145 for (i = 1; i < count; i++)
1149 else if (selection_data->length >= 0 &&
1150 (selection_data->type == text_plain_atom ||
1151 selection_data->type == text_plain_utf8_atom ||
1152 selection_data->type == text_plain_locale_atom))
1154 result = selection_get_text_plain (selection_data);
1161 * gtk_selection_data_get_targets:
1162 * @selection_data: a #GtkSelectionData object
1163 * @targets: location to store an array of targets. The result
1164 * stored here must be freed with g_free().
1165 * @n_atoms: location to store number of items in @targets.
1167 * Gets the contents of @selection_data as an array of targets.
1168 * This can be used to interpret the results of getting
1169 * the standard TARGETS target that is always supplied for
1172 * Return value: %TRUE if @selection_data contains a valid
1173 * array of targets, otherwise %FALSE.
1176 gtk_selection_data_get_targets (GtkSelectionData *selection_data,
1180 if (selection_data->length >= 0 &&
1181 selection_data->format == 32 &&
1182 selection_data->type == GDK_SELECTION_TYPE_ATOM)
1185 *targets = g_memdup (selection_data->data, selection_data->length);
1187 *n_atoms = selection_data->length / sizeof (GdkAtom);
1203 * gtk_selection_data_targets_include_text:
1204 * @selection_data: a #GtkSelectionData object
1206 * Given a #GtkSelectionData object holding a list of targets,
1207 * determines if any of the targets in @targets can be used to
1210 * Return value: %TRUE if @selection_data holds a list of targets,
1211 * and a suitable target for text is included, otherwise %FALSE.
1214 gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
1219 gboolean result = FALSE;
1223 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1225 for (i=0; i < n_targets; i++)
1227 if (targets[i] == utf8_atom ||
1228 targets[i] == text_atom ||
1229 targets[i] == GDK_TARGET_STRING ||
1230 targets[i] == ctext_atom ||
1231 targets[i] == text_plain_atom ||
1232 targets[i] == text_plain_utf8_atom ||
1233 targets[i] == text_plain_locale_atom)
1243 /*************************************************************
1244 * gtk_selection_init:
1245 * Initialize local variables
1249 *************************************************************/
1252 gtk_selection_init (void)
1254 gtk_selection_atoms[INCR] = gdk_atom_intern ("INCR", FALSE);
1255 gtk_selection_atoms[MULTIPLE] = gdk_atom_intern ("MULTIPLE", FALSE);
1256 gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern ("TIMESTAMP", FALSE);
1257 gtk_selection_atoms[TARGETS] = gdk_atom_intern ("TARGETS", FALSE);
1263 * gtk_selection_clear:
1264 * @widget: a #GtkWidget
1267 * The default handler for the GtkWidget::selection_clear_event
1270 * Return value: %TRUE if the event was handled, otherwise false
1274 * Deprecated: Instead of calling this function, chain up from
1275 * your selection_clear_event handler. Calling this function
1276 * from any other context is illegal.
1279 gtk_selection_clear (GtkWidget *widget,
1280 GdkEventSelection *event)
1282 /* Note that we filter clear events in gdkselection-x11.c, so
1283 * that we only will get here if the clear event actually
1284 * represents a change that we didn't do ourself.
1287 GtkSelectionInfo *selection_info = NULL;
1289 tmp_list = current_selections;
1292 selection_info = (GtkSelectionInfo *)tmp_list->data;
1294 if ((selection_info->selection == event->selection) &&
1295 (selection_info->widget == widget))
1298 tmp_list = tmp_list->next;
1303 current_selections = g_list_remove_link (current_selections, tmp_list);
1304 g_list_free (tmp_list);
1305 g_free (selection_info);
1312 /*************************************************************
1313 * _gtk_selection_request:
1314 * Handler for "selection_request_event"
1319 *************************************************************/
1322 _gtk_selection_request (GtkWidget *widget,
1323 GdkEventSelection *event)
1325 GdkDisplay *display = gtk_widget_get_display (widget);
1329 gulong selection_max_size;
1332 gtk_selection_init ();
1334 selection_max_size = GTK_SELECTION_MAX_SIZE (display);
1336 /* Check if we own selection */
1338 tmp_list = current_selections;
1341 GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data;
1343 if ((selection_info->selection == event->selection) &&
1344 (selection_info->widget == widget))
1347 tmp_list = tmp_list->next;
1350 if (tmp_list == NULL)
1353 info = g_new (GtkIncrInfo, 1);
1355 g_object_ref (widget);
1357 info->selection = event->selection;
1358 info->num_incrs = 0;
1360 /* Create GdkWindow structure for the requestor */
1362 info->requestor = gdk_window_lookup_for_display (display,
1364 if (!info->requestor)
1365 info->requestor = gdk_window_foreign_new_for_display (display,
1368 /* Determine conversions we need to perform */
1370 if (event->target == gtk_selection_atoms[MULTIPLE])
1379 gdk_error_trap_push ();
1380 if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */
1381 0, selection_max_size, FALSE,
1382 &type, &format, &length, &mult_atoms))
1384 gdk_selection_send_notify_for_display (display,
1390 g_free (mult_atoms);
1394 gdk_error_trap_pop ();
1396 /* This is annoying; the ICCCM doesn't specify the property type
1397 * used for the property contents, so the autoconversion for
1398 * ATOM / ATOM_PAIR in GDK doesn't work properly.
1400 #ifdef GDK_WINDOWING_X11
1401 if (type != GDK_SELECTION_TYPE_ATOM &&
1402 type != gdk_atom_intern ("ATOM_PAIR", FALSE))
1404 info->num_conversions = length / (2*sizeof (glong));
1405 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1407 for (i=0; i<info->num_conversions; i++)
1409 info->conversions[i].target = gdk_x11_xatom_to_atom_for_display (display,
1410 ((glong *)mult_atoms)[2*i]);
1411 info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display,
1412 ((glong *)mult_atoms)[2*i + 1]);
1418 info->num_conversions = length / (2*sizeof (GdkAtom));
1419 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1421 for (i=0; i<info->num_conversions; i++)
1423 info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
1424 info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
1428 else /* only a single conversion */
1430 info->conversions = g_new (GtkIncrConversion, 1);
1431 info->num_conversions = 1;
1432 info->conversions[0].target = event->target;
1433 info->conversions[0].property = event->property;
1436 /* Loop through conversions and determine which of these are big
1437 enough to require doing them via INCR */
1438 for (i=0; i<info->num_conversions; i++)
1440 GtkSelectionData data;
1443 data.selection = event->selection;
1444 data.target = info->conversions[i].target;
1447 data.display = gtk_widget_get_display (widget);
1449 #ifdef DEBUG_SELECTION
1450 g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
1452 info->conversions[i].target,
1453 gdk_atom_name (info->conversions[i].target),
1454 event->requestor, info->conversions[i].property);
1457 gtk_selection_invoke_handler (widget, &data, event->time);
1459 if (data.length < 0)
1461 info->conversions[i].property = GDK_NONE;
1465 g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
1467 items = data.length / gtk_selection_bytes_per_item (data.format);
1469 if (data.length > selection_max_size)
1471 /* Sending via INCR */
1472 #ifdef DEBUG_SELECTION
1473 g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n",
1474 data.length, selection_max_size);
1477 info->conversions[i].offset = 0;
1478 info->conversions[i].data = data;
1481 gdk_property_change (info->requestor,
1482 info->conversions[i].property,
1483 gtk_selection_atoms[INCR],
1485 GDK_PROP_MODE_REPLACE,
1486 (guchar *)&items, 1);
1490 info->conversions[i].offset = -1;
1492 gdk_property_change (info->requestor,
1493 info->conversions[i].property,
1496 GDK_PROP_MODE_REPLACE,
1503 /* If we have some INCR's, we need to send the rest of the data in
1506 if (info->num_incrs > 0)
1508 /* FIXME: this could be dangerous if window doesn't still
1511 #ifdef DEBUG_SELECTION
1512 g_message ("Starting INCR...");
1515 gdk_window_set_events (info->requestor,
1516 gdk_window_get_events (info->requestor) |
1517 GDK_PROPERTY_CHANGE_MASK);
1518 current_incrs = g_list_append (current_incrs, info);
1519 g_timeout_add (1000, (GSourceFunc) gtk_selection_incr_timeout, info);
1522 /* If it was a MULTIPLE request, set the property to indicate which
1523 conversions succeeded */
1524 if (event->target == gtk_selection_atoms[MULTIPLE])
1526 GdkAtom *mult_atoms = g_new (GdkAtom, 2 * info->num_conversions);
1527 for (i = 0; i < info->num_conversions; i++)
1529 mult_atoms[2*i] = info->conversions[i].target;
1530 mult_atoms[2*i+1] = info->conversions[i].property;
1533 gdk_property_change (info->requestor, event->property,
1534 gdk_atom_intern ("ATOM_PAIR", FALSE), 32,
1535 GDK_PROP_MODE_REPLACE,
1536 (guchar *)mult_atoms, 2*info->num_conversions);
1537 g_free (mult_atoms);
1540 if (info->num_conversions == 1 &&
1541 info->conversions[0].property == GDK_NONE)
1543 /* Reject the entire conversion */
1544 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1553 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1561 if (info->num_incrs == 0)
1563 g_free (info->conversions);
1567 g_object_unref (widget);
1572 /*************************************************************
1573 * _gtk_selection_incr_event:
1574 * Called whenever an PropertyNotify event occurs for an
1575 * GdkWindow with user_data == NULL. These will be notifications
1576 * that a window we are sending the selection to via the
1577 * INCR protocol has deleted a property and is ready for
1581 * window: the requestor window
1582 * event: the property event structure
1585 *************************************************************/
1588 _gtk_selection_incr_event (GdkWindow *window,
1589 GdkEventProperty *event)
1592 GtkIncrInfo *info = NULL;
1595 gulong selection_max_size;
1599 if (event->state != GDK_PROPERTY_DELETE)
1602 #ifdef DEBUG_SELECTION
1603 g_message ("PropertyDelete, property %ld", event->atom);
1606 selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window));
1608 /* Now find the appropriate ongoing INCR */
1609 tmp_list = current_incrs;
1612 info = (GtkIncrInfo *)tmp_list->data;
1613 if (info->requestor == event->window)
1616 tmp_list = tmp_list->next;
1619 if (tmp_list == NULL)
1622 /* Find out which target this is for */
1623 for (i=0; i<info->num_conversions; i++)
1625 if (info->conversions[i].property == event->atom &&
1626 info->conversions[i].offset != -1)
1630 info->idle_time = 0;
1632 if (info->conversions[i].offset == -2) /* only the last 0-length
1640 num_bytes = info->conversions[i].data.length -
1641 info->conversions[i].offset;
1642 buffer = info->conversions[i].data.data +
1643 info->conversions[i].offset;
1645 if (num_bytes > selection_max_size)
1647 num_bytes = selection_max_size;
1648 info->conversions[i].offset += selection_max_size;
1651 info->conversions[i].offset = -2;
1653 #ifdef DEBUG_SELECTION
1654 g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
1655 num_bytes, info->conversions[i].offset,
1656 GDK_WINDOW_XWINDOW(info->requestor), event->atom);
1659 bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
1660 gdk_property_change (info->requestor, event->atom,
1661 info->conversions[i].data.type,
1662 info->conversions[i].data.format,
1663 GDK_PROP_MODE_REPLACE,
1665 num_bytes / bytes_per_item);
1667 if (info->conversions[i].offset == -2)
1669 g_free (info->conversions[i].data.data);
1670 info->conversions[i].data.data = NULL;
1676 info->conversions[i].offset = -1;
1681 /* Check if we're finished with all the targets */
1683 if (info->num_incrs == 0)
1685 current_incrs = g_list_remove_link (current_incrs, tmp_list);
1686 g_list_free (tmp_list);
1687 /* Let the timeout free it */
1693 /*************************************************************
1694 * gtk_selection_incr_timeout:
1695 * Timeout callback for the sending portion of the INCR
1698 * info: Information about this incr
1700 *************************************************************/
1703 gtk_selection_incr_timeout (GtkIncrInfo *info)
1708 GDK_THREADS_ENTER ();
1710 /* Determine if retrieval has finished by checking if it still in
1711 list of pending retrievals */
1713 tmp_list = current_incrs;
1716 if (info == (GtkIncrInfo *)tmp_list->data)
1718 tmp_list = tmp_list->next;
1721 /* If retrieval is finished */
1722 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
1724 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
1726 current_incrs = g_list_remove_link (current_incrs, tmp_list);
1727 g_list_free (tmp_list);
1730 g_free (info->conversions);
1731 /* FIXME: we should check if requestor window is still in use,
1732 and if not, remove it? */
1736 retval = FALSE; /* remove timeout */
1742 retval = TRUE; /* timeout will happen again */
1745 GDK_THREADS_LEAVE ();
1750 /*************************************************************
1751 * _gtk_selection_notify:
1752 * Handler for "selection_notify_event" signals on windows
1753 * where a retrieval is currently in process. The selection
1754 * owner has responded to our conversion request.
1756 * widget: Widget getting signal
1757 * event: Selection event structure
1758 * info: Information about this retrieval
1760 * was event handled?
1761 *************************************************************/
1764 _gtk_selection_notify (GtkWidget *widget,
1765 GdkEventSelection *event)
1768 GtkRetrievalInfo *info = NULL;
1769 guchar *buffer = NULL;
1774 #ifdef DEBUG_SELECTION
1775 g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
1776 event->selection, event->target, event->property);
1779 tmp_list = current_retrievals;
1782 info = (GtkRetrievalInfo *)tmp_list->data;
1783 if (info->widget == widget && info->selection == event->selection)
1785 tmp_list = tmp_list->next;
1788 if (!tmp_list) /* no retrieval in progress */
1791 if (event->property != GDK_NONE)
1792 length = gdk_selection_property_get (widget->window, &buffer,
1795 length = 0; /* silence gcc */
1797 if (event->property == GDK_NONE || buffer == NULL)
1799 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1800 g_list_free (tmp_list);
1801 /* structure will be freed in timeout */
1802 gtk_selection_retrieval_report (info,
1803 GDK_NONE, 0, NULL, -1, event->time);
1808 if (type == gtk_selection_atoms[INCR])
1810 /* The remainder of the selection will come through PropertyNotify
1813 info->notify_time = event->time;
1814 info->idle_time = 0;
1815 info->offset = 0; /* Mark as OK to proceed */
1816 gdk_window_set_events (widget->window,
1817 gdk_window_get_events (widget->window)
1818 | GDK_PROPERTY_CHANGE_MASK);
1822 /* We don't delete the info structure - that will happen in timeout */
1823 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1824 g_list_free (tmp_list);
1826 info->offset = length;
1827 gtk_selection_retrieval_report (info,
1829 buffer, length, event->time);
1832 gdk_property_delete (widget->window, event->property);
1839 /*************************************************************
1840 * _gtk_selection_property_notify:
1841 * Handler for "property_notify_event" signals on windows
1842 * where a retrieval is currently in process. The selection
1843 * owner has added more data.
1845 * widget: Widget getting signal
1846 * event: Property event structure
1847 * info: Information about this retrieval
1849 * was event handled?
1850 *************************************************************/
1853 _gtk_selection_property_notify (GtkWidget *widget,
1854 GdkEventProperty *event)
1857 GtkRetrievalInfo *info = NULL;
1863 g_return_val_if_fail (widget != NULL, FALSE);
1864 g_return_val_if_fail (event != NULL, FALSE);
1866 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
1867 if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */
1868 (event->atom != gdk_atom_intern ("GDK_SELECTION", FALSE))) /* not the right property */
1872 #ifdef DEBUG_SELECTION
1873 g_message ("PropertyNewValue, property %ld",
1877 tmp_list = current_retrievals;
1880 info = (GtkRetrievalInfo *)tmp_list->data;
1881 if (info->widget == widget)
1883 tmp_list = tmp_list->next;
1886 if (!tmp_list) /* No retrieval in progress */
1889 if (info->offset < 0) /* We haven't got the SelectionNotify
1890 for this retrieval yet */
1893 info->idle_time = 0;
1895 length = gdk_selection_property_get (widget->window, &new_buffer,
1897 gdk_property_delete (widget->window, event->atom);
1899 /* We could do a lot better efficiency-wise by paying attention to
1900 what length was sent in the initial INCR transaction, instead of
1901 doing memory allocation at every step. But its only guaranteed to
1902 be a _lower bound_ (pretty useless!) */
1904 if (length == 0 || type == GDK_NONE) /* final zero length portion */
1906 /* Info structure will be freed in timeout */
1907 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1908 g_list_free (tmp_list);
1909 gtk_selection_retrieval_report (info,
1911 (type == GDK_NONE) ? NULL : info->buffer,
1912 (type == GDK_NONE) ? -1 : info->offset,
1915 else /* append on newly arrived data */
1919 #ifdef DEBUG_SELECTION
1920 g_message ("Start - Adding %d bytes at offset 0",
1923 info->buffer = new_buffer;
1924 info->offset = length;
1929 #ifdef DEBUG_SELECTION
1930 g_message ("Appending %d bytes at offset %d",
1931 length,info->offset);
1933 /* We copy length+1 bytes to preserve guaranteed null termination */
1934 info->buffer = g_realloc (info->buffer, info->offset+length+1);
1935 memcpy (info->buffer + info->offset, new_buffer, length+1);
1936 info->offset += length;
1937 g_free (new_buffer);
1944 /*************************************************************
1945 * gtk_selection_retrieval_timeout:
1946 * Timeout callback while receiving a selection.
1948 * info: Information about this retrieval
1950 *************************************************************/
1953 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
1958 GDK_THREADS_ENTER ();
1960 /* Determine if retrieval has finished by checking if it still in
1961 list of pending retrievals */
1963 tmp_list = current_retrievals;
1966 if (info == (GtkRetrievalInfo *)tmp_list->data)
1968 tmp_list = tmp_list->next;
1971 /* If retrieval is finished */
1972 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
1974 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
1976 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1977 g_list_free (tmp_list);
1978 gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
1981 g_free (info->buffer);
1984 retval = FALSE; /* remove timeout */
1990 retval = TRUE; /* timeout will happen again */
1993 GDK_THREADS_LEAVE ();
1998 /*************************************************************
1999 * gtk_selection_retrieval_report:
2000 * Emits a "selection_received" signal.
2002 * info: information about the retrieval that completed
2003 * buffer: buffer containing data (NULL => errror)
2004 * time: timestamp for data in buffer
2006 *************************************************************/
2009 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
2010 GdkAtom type, gint format,
2011 guchar *buffer, gint length,
2014 GtkSelectionData data;
2016 data.selection = info->selection;
2017 data.target = info->target;
2019 data.format = format;
2021 data.length = length;
2023 data.display = gtk_widget_get_display (info->widget);
2025 g_signal_emit_by_name (info->widget,
2026 "selection_received",
2030 /*************************************************************
2031 * gtk_selection_invoke_handler:
2032 * Finds and invokes handler for specified
2033 * widget/selection/target combination, calls
2034 * gtk_selection_default_handler if none exists.
2037 * widget: selection owner
2038 * data: selection data [INOUT]
2039 * time: time from requeset
2042 * Number of bytes written to buffer, -1 if error
2043 *************************************************************/
2046 gtk_selection_invoke_handler (GtkWidget *widget,
2047 GtkSelectionData *data,
2050 GtkTargetList *target_list;
2054 g_return_if_fail (widget != NULL);
2056 target_list = gtk_selection_target_list_get (widget, data->selection);
2058 gtk_target_list_find (target_list, data->target, &info))
2060 g_signal_emit_by_name (widget,
2066 gtk_selection_default_handler (widget, data);
2069 /*************************************************************
2070 * gtk_selection_default_handler:
2071 * Handles some default targets that exist for any widget
2072 * If it can't fit results into buffer, returns -1. This
2073 * won't happen in any conceivable case, since it would
2074 * require 1000 selection targets!
2077 * widget: selection owner
2078 * data: selection data [INOUT]
2080 *************************************************************/
2083 gtk_selection_default_handler (GtkWidget *widget,
2084 GtkSelectionData *data)
2086 if (data->target == gtk_selection_atoms[TIMESTAMP])
2088 /* Time which was used to obtain selection */
2090 GtkSelectionInfo *selection_info;
2092 tmp_list = current_selections;
2095 selection_info = (GtkSelectionInfo *)tmp_list->data;
2096 if ((selection_info->widget == widget) &&
2097 (selection_info->selection == data->selection))
2099 gulong time = selection_info->time;
2101 gtk_selection_data_set (data,
2102 GDK_SELECTION_TYPE_INTEGER,
2109 tmp_list = tmp_list->next;
2114 else if (data->target == gtk_selection_atoms[TARGETS])
2116 /* List of all targets supported for this widget/selection pair */
2120 GtkTargetList *target_list;
2121 GtkTargetPair *pair;
2123 target_list = gtk_selection_target_list_get (widget,
2125 count = g_list_length (target_list->list) + 3;
2127 data->type = GDK_SELECTION_TYPE_ATOM;
2129 data->length = count * sizeof (GdkAtom);
2131 /* selection data is always terminated by a trailing \0
2133 p = g_malloc (data->length + 1);
2134 data->data = (guchar *)p;
2135 data->data[data->length] = '\0';
2137 *p++ = gtk_selection_atoms[TIMESTAMP];
2138 *p++ = gtk_selection_atoms[TARGETS];
2139 *p++ = gtk_selection_atoms[MULTIPLE];
2141 tmp_list = target_list->list;
2144 pair = (GtkTargetPair *)tmp_list->data;
2145 *p++ = pair->target;
2147 tmp_list = tmp_list->next;
2158 gtk_selection_data_copy (GtkSelectionData *selection_data)
2160 GtkSelectionData *new_data;
2162 g_return_val_if_fail (selection_data != NULL, NULL);
2164 new_data = g_new (GtkSelectionData, 1);
2165 *new_data = *selection_data;
2167 if (selection_data->data)
2169 new_data->data = g_malloc (selection_data->length + 1);
2170 memcpy (new_data->data, selection_data->data, selection_data->length + 1);
2177 gtk_selection_data_free (GtkSelectionData *data)
2179 g_return_if_fail (data != NULL);
2182 g_free (data->data);
2188 gtk_selection_data_get_type (void)
2190 static GType our_type = 0;
2193 our_type = g_boxed_type_register_static ("GtkSelectionData",
2194 (GBoxedCopyFunc) gtk_selection_data_copy,
2195 (GBoxedFreeFunc) gtk_selection_data_free);
2201 gtk_selection_bytes_per_item (gint format)
2206 return sizeof (char);
2209 return sizeof (short);
2212 return sizeof (long);
2215 g_assert_not_reached();