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"
62 #include "gdk-pixbuf/gdk-pixbuf.h"
64 #ifdef GDK_WINDOWING_X11
68 #undef DEBUG_SELECTION
70 /* Maximum size of a sent chunk, in bytes. Also the default size of
72 #ifdef GDK_WINDOWING_X11
73 #define GTK_SELECTION_MAX_SIZE(display) \
75 XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0 \
76 ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100 \
77 : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
79 /* No chunks on Win32 */
80 #define GTK_SELECTION_MAX_SIZE(display) G_MAXINT
83 #define IDLE_ABORT_TIME 30
93 typedef struct _GtkSelectionInfo GtkSelectionInfo;
94 typedef struct _GtkIncrConversion GtkIncrConversion;
95 typedef struct _GtkIncrInfo GtkIncrInfo;
96 typedef struct _GtkRetrievalInfo GtkRetrievalInfo;
98 struct _GtkSelectionInfo
101 GtkWidget *widget; /* widget that owns selection */
102 guint32 time; /* time used to acquire selection */
103 GdkDisplay *display; /* needed in gtk_selection_remove_all */
106 struct _GtkIncrConversion
108 GdkAtom target; /* Requested target */
109 GdkAtom property; /* Property to store in */
110 GtkSelectionData data; /* The data being supplied */
111 gint offset; /* Current offset in sent selection.
113 * -2 => Only the final (empty) portion
119 GdkWindow *requestor; /* Requestor window - we create a GdkWindow
120 so we can receive events */
121 GdkAtom selection; /* Selection we're sending */
123 GtkIncrConversion *conversions; /* Information about requested conversions -
124 * With MULTIPLE requests (benighted 1980's
125 * hardware idea), there can be more than
127 gint num_conversions;
128 gint num_incrs; /* number of remaining INCR style transactions */
133 struct _GtkRetrievalInfo
136 GdkAtom selection; /* Selection being retrieved. */
137 GdkAtom target; /* Form of selection that we requested */
138 guint32 idle_time; /* Number of seconds since we last heard
139 from selection owner */
140 guchar *buffer; /* Buffer in which to accumulate results */
141 gint offset; /* Current offset in buffer, -1 indicates
143 guint32 notify_time; /* Timestamp from SelectionNotify */
146 /* Local Functions */
147 static void gtk_selection_init (void);
148 static gint gtk_selection_incr_timeout (GtkIncrInfo *info);
149 static gint gtk_selection_retrieval_timeout (GtkRetrievalInfo *info);
150 static void gtk_selection_retrieval_report (GtkRetrievalInfo *info,
156 static void gtk_selection_invoke_handler (GtkWidget *widget,
157 GtkSelectionData *data,
159 static void gtk_selection_default_handler (GtkWidget *widget,
160 GtkSelectionData *data);
161 static int gtk_selection_bytes_per_item (gint format);
164 static gint initialize = TRUE;
165 static GList *current_retrievals = NULL;
166 static GList *current_incrs = NULL;
167 static GList *current_selections = NULL;
169 static GdkAtom gtk_selection_atoms[LAST_ATOM];
170 static const char gtk_selection_handler_key[] = "gtk-selection-handlers";
181 gtk_target_list_new (const GtkTargetEntry *targets,
184 GtkTargetList *result = g_new (GtkTargetList, 1);
186 result->ref_count = 1;
189 gtk_target_list_add_table (result, targets, ntargets);
195 gtk_target_list_ref (GtkTargetList *list)
197 g_return_if_fail (list != NULL);
203 gtk_target_list_unref (GtkTargetList *list)
205 g_return_if_fail (list != NULL);
206 g_return_if_fail (list->ref_count > 0);
209 if (list->ref_count == 0)
211 GList *tmp_list = list->list;
214 GtkTargetPair *pair = tmp_list->data;
217 tmp_list = tmp_list->next;
220 g_list_free (list->list);
226 gtk_target_list_add (GtkTargetList *list,
233 g_return_if_fail (list != NULL);
235 pair = g_new (GtkTargetPair, 1);
236 pair->target = target;
240 list->list = g_list_append (list->list, pair);
243 static GdkAtom utf8_atom;
244 static GdkAtom text_atom;
245 static GdkAtom ctext_atom;
246 static GdkAtom text_plain_atom;
247 static GdkAtom text_plain_utf8_atom;
248 static GdkAtom text_plain_locale_atom;
249 static GdkAtom text_uri_list_atom;
255 const gchar *charset;
259 utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
260 text_atom = gdk_atom_intern ("TEXT", FALSE);
261 ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
262 text_plain_atom = gdk_atom_intern ("text/plain", FALSE);
263 text_plain_utf8_atom = gdk_atom_intern ("text/plain;charset=utf-8", FALSE);
264 g_get_charset (&charset);
265 tmp = g_strdup_printf ("text/plain;charset=%s", charset);
266 text_plain_locale_atom = gdk_atom_intern (tmp, FALSE);
269 text_uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE);
274 * gtk_target_list_add_text_targets:
275 * @list: a #GtkTargetList
276 * @info: an ID that will be passed back to the application
278 * Adds the text targets supported by #GtkSelection to
279 * the target list. All targets are added with the same @info.
284 gtk_target_list_add_text_targets (GtkTargetList *list,
287 g_return_if_fail (list != NULL);
291 /* Keep in sync with gtk_selection_data_targets_include_text()
293 gtk_target_list_add (list, utf8_atom, 0, info);
294 gtk_target_list_add (list, ctext_atom, 0, info);
295 gtk_target_list_add (list, text_atom, 0, info);
296 gtk_target_list_add (list, GDK_TARGET_STRING, 0, info);
297 gtk_target_list_add (list, text_plain_utf8_atom, 0, info);
298 gtk_target_list_add (list, text_plain_locale_atom, 0, info);
299 gtk_target_list_add (list, text_plain_atom, 0, info);
303 * gtk_target_list_add_image_targets:
304 * @list: a #GtkTargetList
305 * @info: an ID that will be passed back to the application
306 * @writable: whether to add only targets for which GTK+ knows
307 * how to convert a pixbuf into the format
309 * Adds the image targets supported by #GtkSelection to
310 * the target list. All targets are added with the same @info.
315 gtk_target_list_add_image_targets (GtkTargetList *list,
323 g_return_if_fail (list != NULL);
325 formats = gdk_pixbuf_get_formats ();
327 for (f = formats; f; f = f->next)
329 GdkPixbufFormat *fmt = f->data;
331 if (writable && !gdk_pixbuf_format_is_writable (fmt))
334 mimes = gdk_pixbuf_format_get_mime_types (fmt);
335 for (m = mimes; *m; m++)
337 atom = gdk_atom_intern (*m, FALSE);
338 gtk_target_list_add (list, atom, 0, info);
343 g_slist_free (formats);
347 * gtk_target_list_add_uri_targets:
348 * @list: a #GtkTargetList
349 * @info: an ID that will be passed back to the application
351 * Adds the URI targets supported by #GtkSelection to
352 * the target list. All targets are added with the same @info.
357 gtk_target_list_add_uri_targets (GtkTargetList *list,
360 g_return_if_fail (list != NULL);
364 gtk_target_list_add (list, text_uri_list_atom, 0, info);
368 gtk_target_list_add_table (GtkTargetList *list,
369 const GtkTargetEntry *targets,
374 for (i=ntargets-1; i >= 0; i--)
376 GtkTargetPair *pair = g_new (GtkTargetPair, 1);
377 pair->target = gdk_atom_intern (targets[i].target, FALSE);
378 pair->flags = targets[i].flags;
379 pair->info = targets[i].info;
381 list->list = g_list_prepend (list->list, pair);
386 gtk_target_list_remove (GtkTargetList *list,
391 g_return_if_fail (list != NULL);
393 tmp_list = list->list;
396 GtkTargetPair *pair = tmp_list->data;
398 if (pair->target == target)
402 list->list = g_list_remove_link (list->list, tmp_list);
403 g_list_free_1 (tmp_list);
408 tmp_list = tmp_list->next;
413 gtk_target_list_find (GtkTargetList *list,
417 GList *tmp_list = list->list;
420 GtkTargetPair *pair = tmp_list->data;
422 if (pair->target == target)
427 tmp_list = tmp_list->next;
434 * gtk_selection_owner_set_for_display:
435 * @display: the #Gdkdisplay where the selection is set
436 * @widget: new selection owner (a #GdkWidget), or %NULL.
437 * @selection: an interned atom representing the selection to claim.
438 * @time_: timestamp with which to claim the selection
440 * Claim ownership of a given selection for a particular widget, or,
441 * if @widget is %NULL, release ownership of the selection.
443 * Return value: TRUE if the operation succeeded
448 gtk_selection_owner_set_for_display (GdkDisplay *display,
454 GtkWidget *old_owner;
455 GtkSelectionInfo *selection_info = NULL;
458 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
459 g_return_val_if_fail (selection != GDK_NONE, FALSE);
460 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
461 g_return_val_if_fail (widget == NULL || gtk_widget_get_display (widget) == display, FALSE);
466 window = widget->window;
468 tmp_list = current_selections;
471 if (((GtkSelectionInfo *)tmp_list->data)->selection == selection)
473 selection_info = tmp_list->data;
477 tmp_list = tmp_list->next;
480 if (gdk_selection_owner_set_for_display (display, window, selection, time, TRUE))
488 old_owner = selection_info->widget;
489 current_selections = g_list_remove_link (current_selections,
491 g_list_free (tmp_list);
492 g_free (selection_info);
497 if (selection_info == NULL)
499 selection_info = g_new (GtkSelectionInfo, 1);
500 selection_info->selection = selection;
501 selection_info->widget = widget;
502 selection_info->time = time;
503 selection_info->display = display;
504 current_selections = g_list_prepend (current_selections,
509 old_owner = selection_info->widget;
510 selection_info->widget = widget;
511 selection_info->time = time;
512 selection_info->display = display;
515 /* If another widget in the application lost the selection,
516 * send it a GDK_SELECTION_CLEAR event.
518 if (old_owner && old_owner != widget)
520 GdkEvent *event = gdk_event_new (GDK_SELECTION_CLEAR);
522 event->selection.window = g_object_ref (old_owner->window);
523 event->selection.selection = selection;
524 event->selection.time = time;
526 gtk_widget_event (old_owner, event);
528 gdk_event_free (event);
537 * gtk_selection_owner_set:
538 * @widget: a #GtkWidget, or %NULL.
539 * @selection: an interned atom representing the selection to claim
540 * @time_: timestamp with which to claim the selection
542 * Claims ownership of a given selection for a particular widget,
543 * or, if @widget is %NULL, release ownership of the selection.
545 * Return value: %TRUE if the operation succeeded
548 gtk_selection_owner_set (GtkWidget *widget,
554 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
555 g_return_val_if_fail (selection != GDK_NONE, FALSE);
558 display = gtk_widget_get_display (widget);
562 g_warning ("gtk_selection_owner_set (NULL,...) is not multihead safe"));
564 display = gdk_display_get_default ();
567 return gtk_selection_owner_set_for_display (display, widget,
571 /*************************************************************
572 * gtk_selection_add_target
573 * Add specified target to list of supported targets
576 * widget: The widget for which this target applies
579 * info: guint to pass to to the selection_get signal
582 *************************************************************/
584 typedef struct _GtkSelectionTargetList GtkSelectionTargetList;
586 struct _GtkSelectionTargetList {
591 static GtkTargetList *
592 gtk_selection_target_list_get (GtkWidget *widget,
595 GtkSelectionTargetList *sellist;
599 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
604 sellist = tmp_list->data;
605 if (sellist->selection == selection)
606 return sellist->list;
607 tmp_list = tmp_list->next;
610 sellist = g_new (GtkSelectionTargetList, 1);
611 sellist->selection = selection;
612 sellist->list = gtk_target_list_new (NULL, 0);
614 lists = g_list_prepend (lists, sellist);
615 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
617 return sellist->list;
621 gtk_selection_target_list_remove (GtkWidget *widget)
623 GtkSelectionTargetList *sellist;
627 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
632 sellist = tmp_list->data;
634 gtk_target_list_unref (sellist->list);
637 tmp_list = tmp_list->next;
641 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, NULL);
645 * gtk_selection_clear_targets:
646 * @widget: a #GtkWidget
647 * @selection: an atom representing a selection
649 * Remove all targets registered for the given selection for the
653 gtk_selection_clear_targets (GtkWidget *widget,
656 GtkSelectionTargetList *sellist;
660 g_return_if_fail (GTK_IS_WIDGET (widget));
661 g_return_if_fail (selection != GDK_NONE);
663 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
668 sellist = tmp_list->data;
669 if (sellist->selection == selection)
671 lists = g_list_delete_link (lists, tmp_list);
672 gtk_target_list_unref (sellist->list);
678 tmp_list = tmp_list->next;
681 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
685 gtk_selection_add_target (GtkWidget *widget,
692 g_return_if_fail (GTK_IS_WIDGET (widget));
693 g_return_if_fail (selection != GDK_NONE);
695 list = gtk_selection_target_list_get (widget, selection);
696 gtk_target_list_add (list, target, 0, info);
700 gtk_selection_add_targets (GtkWidget *widget,
702 const GtkTargetEntry *targets,
707 g_return_if_fail (GTK_IS_WIDGET (widget));
708 g_return_if_fail (selection != GDK_NONE);
709 g_return_if_fail (targets != NULL);
711 list = gtk_selection_target_list_get (widget, selection);
712 gtk_target_list_add_table (list, targets, ntargets);
716 /*************************************************************
717 * gtk_selection_remove_all:
718 * Removes all handlers and unsets ownership of all
719 * selections for a widget. Called when widget is being
725 *************************************************************/
728 gtk_selection_remove_all (GtkWidget *widget)
732 GtkSelectionInfo *selection_info;
734 /* Remove pending requests/incrs for this widget */
736 tmp_list = current_retrievals;
739 next = tmp_list->next;
740 if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget)
742 current_retrievals = g_list_remove_link (current_retrievals,
744 /* structure will be freed in timeout */
745 g_list_free (tmp_list);
750 /* Disclaim ownership of any selections */
752 tmp_list = current_selections;
755 next = tmp_list->next;
756 selection_info = (GtkSelectionInfo *)tmp_list->data;
758 if (selection_info->widget == widget)
760 gdk_selection_owner_set_for_display (selection_info->display,
762 selection_info->selection,
763 GDK_CURRENT_TIME, FALSE);
764 current_selections = g_list_remove_link (current_selections,
766 g_list_free (tmp_list);
767 g_free (selection_info);
773 /* Remove all selection lists */
774 gtk_selection_target_list_remove (widget);
777 /*************************************************************
778 * gtk_selection_convert:
779 * Request the contents of a selection. When received,
780 * a "selection_received" signal will be generated.
783 * widget: The widget which acts as requestor
784 * selection: Which selection to get
785 * target: Form of information desired (e.g., STRING)
786 * time: Time of request (usually of triggering event)
787 * In emergency, you could use GDK_CURRENT_TIME
790 * TRUE if requested succeeded. FALSE if we could not process
791 * request. (e.g., there was already a request in process for
793 *************************************************************/
796 gtk_selection_convert (GtkWidget *widget,
801 GtkRetrievalInfo *info;
803 GdkWindow *owner_window;
806 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
807 g_return_val_if_fail (selection != GDK_NONE, FALSE);
810 gtk_selection_init ();
812 if (!GTK_WIDGET_REALIZED (widget))
813 gtk_widget_realize (widget);
815 /* Check to see if there are already any retrievals in progress for
816 this widget. If we changed GDK to use the selection for the
817 window property in which to store the retrieved information, then
818 we could support multiple retrievals for different selections.
819 This might be useful for DND. */
821 tmp_list = current_retrievals;
824 info = (GtkRetrievalInfo *)tmp_list->data;
825 if (info->widget == widget)
827 tmp_list = tmp_list->next;
830 info = g_new (GtkRetrievalInfo, 1);
832 info->widget = widget;
833 info->selection = selection;
834 info->target = target;
839 /* Check if this process has current owner. If so, call handler
840 procedure directly to avoid deadlocks with INCR. */
842 display = gtk_widget_get_display (widget);
843 owner_window = gdk_selection_owner_get_for_display (display, selection);
845 if (owner_window != NULL)
847 GtkWidget *owner_widget;
848 GtkSelectionData selection_data;
850 selection_data.selection = selection;
851 selection_data.target = target;
852 selection_data.data = NULL;
853 selection_data.length = -1;
854 selection_data.display = display;
856 gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget);
858 if (owner_widget != NULL)
860 gtk_selection_invoke_handler (owner_widget,
864 gtk_selection_retrieval_report (info,
866 selection_data.format,
868 selection_data.length,
871 g_free (selection_data.data);
878 /* Otherwise, we need to go through X */
880 current_retrievals = g_list_append (current_retrievals, info);
881 gdk_selection_convert (widget->window, selection, target, time);
882 g_timeout_add (1000, (GSourceFunc) gtk_selection_retrieval_timeout, info);
887 /*************************************************************
888 * gtk_selection_data_set:
889 * Store new data into a GtkSelectionData object. Should
890 * _only_ by called from a selection handler callback.
891 * Null terminates the stored data.
893 * type: the type of selection data
894 * format: format (number of bits in a unit)
895 * data: pointer to the data (will be copied)
896 * length: length of the data
898 *************************************************************/
901 gtk_selection_data_set (GtkSelectionData *selection_data,
907 if (selection_data->data)
908 g_free (selection_data->data);
910 selection_data->type = type;
911 selection_data->format = format;
915 selection_data->data = g_new (guchar, length+1);
916 memcpy (selection_data->data, data, length);
917 selection_data->data[length] = 0;
921 g_return_if_fail (length <= 0);
924 selection_data->data = NULL;
926 selection_data->data = g_strdup("");
929 selection_data->length = length;
933 selection_set_string (GtkSelectionData *selection_data,
937 gchar *tmp = g_strndup (str, len);
938 gchar *latin1 = gdk_utf8_to_string_target (tmp);
943 gtk_selection_data_set (selection_data,
944 GDK_SELECTION_TYPE_STRING,
945 8, latin1, strlen (latin1));
955 selection_set_compound_text (GtkSelectionData *selection_data,
964 gboolean result = FALSE;
966 tmp = g_strndup (str, len);
967 if (gdk_utf8_to_compound_text_for_display (selection_data->display, tmp,
968 &encoding, &format, &text, &new_length))
970 gtk_selection_data_set (selection_data, encoding, format, text, new_length);
971 gdk_free_compound_text (text);
981 /* Normalize \r and \n into \r\n
984 normalize_to_crlf (const gchar *str,
987 GString *result = g_string_sized_new (len);
988 const gchar *p = str;
993 g_string_append_c (result, '\r');
997 g_string_append_c (result, *p);
1000 g_string_append_c (result, '\n');
1006 g_string_append_c (result, *p);
1010 return g_string_free (result, FALSE);
1013 /* Normalize \r and \r\n into \n
1016 normalize_to_lf (gchar *str,
1019 GString *result = g_string_sized_new (len);
1020 const gchar *p = str;
1028 g_string_append_c (result, '\n');
1034 g_string_append_c (result, *p);
1038 return g_string_free (result, FALSE);
1042 selection_set_text_plain (GtkSelectionData *selection_data,
1046 const gchar *charset = NULL;
1048 GError *error = NULL;
1050 result = normalize_to_crlf (str, len);
1051 if (selection_data->target == text_plain_atom)
1053 else if (selection_data->target == text_plain_locale_atom)
1054 g_get_charset (&charset);
1058 gchar *tmp = result;
1059 result = g_convert_with_fallback (tmp, -1,
1061 NULL, NULL, NULL, &error);
1067 g_warning ("Error converting from UTF-8 to %s: %s",
1068 charset, error->message);
1069 g_error_free (error);
1074 gtk_selection_data_set (selection_data,
1075 selection_data->target,
1076 8, result, strlen (result));
1083 selection_get_text_plain (GtkSelectionData *selection_data)
1085 const gchar *charset = NULL;
1086 gchar *str, *result;
1088 GError *error = NULL;
1090 str = g_strdup (selection_data->data);
1091 len = selection_data->length;
1093 if (selection_data->type == text_plain_atom)
1094 charset = "ISO-8859-1";
1095 else if (selection_data->type == text_plain_locale_atom)
1096 g_get_charset (&charset);
1101 str = g_convert_with_fallback (tmp, len,
1103 NULL, NULL, &len, &error);
1108 g_warning ("Error converting from %s to UTF-8: %s",
1109 charset, error->message);
1110 g_error_free (error);
1115 else if (!g_utf8_validate (str, -1, NULL))
1117 g_warning ("Error converting from text/plain;charset=utf-8 to UTF-8");
1123 result = normalize_to_lf (str, len);
1130 * gtk_selection_data_set_text:
1131 * @selection_data: a #GtkSelectionData
1132 * @str: a UTF-8 string
1133 * @len: the length of @str, or -1 if @str is nul-terminated.
1135 * Sets the contents of the selection from a UTF-8 encoded string.
1136 * The string is converted to the form determined by
1137 * @selection_data->target.
1139 * Return value: %TRUE if the selection was successfully set,
1143 gtk_selection_data_set_text (GtkSelectionData *selection_data,
1152 if (selection_data->target == utf8_atom)
1154 gtk_selection_data_set (selection_data,
1156 8, (guchar *)str, len);
1159 else if (selection_data->target == GDK_TARGET_STRING)
1161 return selection_set_string (selection_data, str, len);
1163 else if (selection_data->target == ctext_atom ||
1164 selection_data->target == text_atom)
1166 if (selection_set_compound_text (selection_data, str, len))
1168 else if (selection_data->target == text_atom)
1169 return selection_set_string (selection_data, str, len);
1171 else if (selection_data->target == text_plain_atom ||
1172 selection_data->target == text_plain_utf8_atom ||
1173 selection_data->target == text_plain_locale_atom)
1175 return selection_set_text_plain (selection_data, str, len);
1182 * gtk_selection_data_get_text:
1183 * @selection_data: a #GtkSelectionData
1185 * Gets the contents of the selection data as a UTF-8 string.
1187 * Return value: if the selection data contained a recognized
1188 * text type and it could be converted to UTF-8, a newly allocated
1189 * string containing the converted text, otherwise %NULL.
1190 * If the result is non-%NULL it must be freed with g_free().
1193 gtk_selection_data_get_text (GtkSelectionData *selection_data)
1195 guchar *result = NULL;
1199 if (selection_data->length >= 0 &&
1200 (selection_data->type == GDK_TARGET_STRING ||
1201 selection_data->type == ctext_atom ||
1202 selection_data->type == utf8_atom))
1206 gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1207 selection_data->type,
1208 selection_data->format,
1209 selection_data->data,
1210 selection_data->length,
1215 for (i = 1; i < count; i++)
1219 else if (selection_data->length >= 0 &&
1220 (selection_data->type == text_plain_atom ||
1221 selection_data->type == text_plain_utf8_atom ||
1222 selection_data->type == text_plain_locale_atom))
1224 result = selection_get_text_plain (selection_data);
1231 * gtk_selection_data_set_pixbuf:
1232 * @selection_data: a #GtkSelectionData
1233 * @pixbuf: a #GdkPixbuf
1235 * Sets the contents of the selection from a #GdkPixbuf
1236 * The pixbuf is converted to the form determined by
1237 * @selection_data->target.
1239 * Return value: %TRUE if the selection was successfully set,
1245 gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data,
1248 GSList *formats, *f;
1255 formats = gdk_pixbuf_get_formats ();
1257 for (f = formats; f; f = f->next)
1259 GdkPixbufFormat *fmt = f->data;
1261 mimes = gdk_pixbuf_format_get_mime_types (fmt);
1262 for (m = mimes; *m; m++)
1264 atom = gdk_atom_intern (*m, FALSE);
1265 if (selection_data->target == atom)
1268 type = gdk_pixbuf_format_get_name (fmt),
1269 result = gdk_pixbuf_save_to_buffer (pixbuf,
1275 gtk_selection_data_set (selection_data,
1276 atom, 8, (guchar *)str, len);
1280 g_slist_free (formats);
1289 g_slist_free (formats);
1295 * gtk_selection_data_get_pixbuf:
1296 * @selection_data: a #GtkSelectionData
1298 * Gets the contents of the selection data as a #GdkPixbuf.
1300 * Return value: if the selection data contained a recognized
1301 * image type and it could be converted to a #GdkPixbuf, a
1302 * newly allocated pixbuf is returned, otherwise %NULL.
1303 * If the result is non-%NULL it must be freed with g_object_unref().
1308 gtk_selection_data_get_pixbuf (GtkSelectionData *selection_data)
1310 GdkPixbufLoader *loader;
1311 GdkPixbuf *result = NULL;
1313 loader = gdk_pixbuf_loader_new ();
1315 if (gdk_pixbuf_loader_write (loader,
1316 selection_data->data,
1317 selection_data->length,
1319 result = gdk_pixbuf_loader_get_pixbuf (loader);
1322 g_object_ref (result);
1324 gdk_pixbuf_loader_close (loader, NULL);
1325 g_object_unref (loader);
1331 * gtk_selection_data_set_uris:
1332 * @selection_data: a #GtkSelectionData
1333 * @uris: a %NULL-terminated array of strings hilding URIs
1335 * Sets the contents of the selection from a list of URIs.
1336 * The string is converted to the form determined by
1337 * @selection_data->target.
1339 * Return value: %TRUE if the selection was successfully set,
1345 gtk_selection_data_set_uris (GtkSelectionData *selection_data,
1350 if (selection_data->target == text_uri_list_atom)
1357 list = g_string_new (NULL);
1358 for (i = 0; uris[i]; i++)
1360 g_string_append (list, uris[i]);
1361 g_string_append (list, "\r\n");
1364 result = g_convert (list->str, list->len,
1366 NULL, &length, NULL);
1367 g_string_free (list, TRUE);
1371 gtk_selection_data_set (selection_data,
1373 8, (guchar *)result, length);
1383 * gtk_selection_data_get_uris:
1384 * @selection_data: a #GtkSelectionData
1386 * Gets the contents of the selection data as array of URIs.
1388 * Return value: if the selection data contains a list of
1389 * URIs, a newly allocated %NULL-terminated string array
1390 * containing the URIs, otherwise %NULL. If the result is
1391 * non-%NULL it must be freed with g_strfreev().
1396 gtk_selection_data_get_uris (GtkSelectionData *selection_data)
1398 gchar **result = NULL;
1402 if (selection_data->length >= 0 &&
1403 selection_data->type == text_uri_list_atom)
1407 gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1409 selection_data->format,
1410 selection_data->data,
1411 selection_data->length,
1414 result = g_uri_list_extract_uris (list[0]);
1416 for (i = 1; i < count; i++)
1426 * gtk_selection_data_get_targets:
1427 * @selection_data: a #GtkSelectionData object
1428 * @targets: location to store an array of targets. The result
1429 * stored here must be freed with g_free().
1430 * @n_atoms: location to store number of items in @targets.
1432 * Gets the contents of @selection_data as an array of targets.
1433 * This can be used to interpret the results of getting
1434 * the standard TARGETS target that is always supplied for
1437 * Return value: %TRUE if @selection_data contains a valid
1438 * array of targets, otherwise %FALSE.
1441 gtk_selection_data_get_targets (GtkSelectionData *selection_data,
1445 if (selection_data->length >= 0 &&
1446 selection_data->format == 32 &&
1447 selection_data->type == GDK_SELECTION_TYPE_ATOM)
1450 *targets = g_memdup (selection_data->data, selection_data->length);
1452 *n_atoms = selection_data->length / sizeof (GdkAtom);
1468 * gtk_selection_data_targets_include_text:
1469 * @selection_data: a #GtkSelectionData object
1471 * Given a #GtkSelectionData object holding a list of targets,
1472 * determines if any of the targets in @targets can be used to
1475 * Return value: %TRUE if @selection_data holds a list of targets,
1476 * and a suitable target for text is included, otherwise %FALSE.
1479 gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
1484 gboolean result = FALSE;
1488 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1490 for (i=0; i < n_targets; i++)
1492 if (targets[i] == utf8_atom ||
1493 targets[i] == text_atom ||
1494 targets[i] == GDK_TARGET_STRING ||
1495 targets[i] == ctext_atom ||
1496 targets[i] == text_plain_atom ||
1497 targets[i] == text_plain_utf8_atom ||
1498 targets[i] == text_plain_locale_atom)
1512 * gtk_selection_data_targets_include_image:
1513 * @selection_data: a #GtkSelectionData object
1514 * @writable: whether to accept only targets for which GTK+ knows
1515 * how to convert a pixbuf into the format
1517 * Given a #GtkSelectionData object holding a list of targets,
1518 * determines if any of the targets in @targets can be used to
1519 * provide a #GdkPixbuf.
1521 * Return value: %TRUE if @selection_data holds a list of targets,
1522 * and a suitable target for images is included, otherwise %FALSE.
1527 gtk_selection_data_targets_include_image (GtkSelectionData *selection_data,
1533 gboolean result = FALSE;
1534 GtkTargetList *list;
1539 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1541 list = gtk_target_list_new (NULL, 0);
1542 gtk_target_list_add_image_targets (list, 0, writable);
1543 for (i=0; i < n_targets && !result; i++)
1545 for (l = list->list; l && !result; l = l->next)
1547 GtkTargetPair *pair = (GtkTargetPair *)l->data;
1548 if (pair->target == targets[i])
1552 gtk_target_list_unref (list);
1559 /*************************************************************
1560 * gtk_selection_init:
1561 * Initialize local variables
1565 *************************************************************/
1568 gtk_selection_init (void)
1570 gtk_selection_atoms[INCR] = gdk_atom_intern ("INCR", FALSE);
1571 gtk_selection_atoms[MULTIPLE] = gdk_atom_intern ("MULTIPLE", FALSE);
1572 gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern ("TIMESTAMP", FALSE);
1573 gtk_selection_atoms[TARGETS] = gdk_atom_intern ("TARGETS", FALSE);
1579 * gtk_selection_clear:
1580 * @widget: a #GtkWidget
1583 * The default handler for the GtkWidget::selection_clear_event
1586 * Return value: %TRUE if the event was handled, otherwise false
1590 * Deprecated: Instead of calling this function, chain up from
1591 * your selection_clear_event handler. Calling this function
1592 * from any other context is illegal.
1595 gtk_selection_clear (GtkWidget *widget,
1596 GdkEventSelection *event)
1598 /* Note that we filter clear events in gdkselection-x11.c, so
1599 * that we only will get here if the clear event actually
1600 * represents a change that we didn't do ourself.
1603 GtkSelectionInfo *selection_info = NULL;
1605 tmp_list = current_selections;
1608 selection_info = (GtkSelectionInfo *)tmp_list->data;
1610 if ((selection_info->selection == event->selection) &&
1611 (selection_info->widget == widget))
1614 tmp_list = tmp_list->next;
1619 current_selections = g_list_remove_link (current_selections, tmp_list);
1620 g_list_free (tmp_list);
1621 g_free (selection_info);
1628 /*************************************************************
1629 * _gtk_selection_request:
1630 * Handler for "selection_request_event"
1635 *************************************************************/
1638 _gtk_selection_request (GtkWidget *widget,
1639 GdkEventSelection *event)
1641 GdkDisplay *display = gtk_widget_get_display (widget);
1645 gulong selection_max_size;
1648 gtk_selection_init ();
1650 selection_max_size = GTK_SELECTION_MAX_SIZE (display);
1652 /* Check if we own selection */
1654 tmp_list = current_selections;
1657 GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data;
1659 if ((selection_info->selection == event->selection) &&
1660 (selection_info->widget == widget))
1663 tmp_list = tmp_list->next;
1666 if (tmp_list == NULL)
1669 info = g_new (GtkIncrInfo, 1);
1671 g_object_ref (widget);
1673 info->selection = event->selection;
1674 info->num_incrs = 0;
1676 /* Create GdkWindow structure for the requestor */
1678 info->requestor = gdk_window_lookup_for_display (display,
1680 if (!info->requestor)
1681 info->requestor = gdk_window_foreign_new_for_display (display,
1684 /* Determine conversions we need to perform */
1686 if (event->target == gtk_selection_atoms[MULTIPLE])
1695 gdk_error_trap_push ();
1696 if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */
1697 0, selection_max_size, FALSE,
1698 &type, &format, &length, &mult_atoms))
1700 gdk_selection_send_notify_for_display (display,
1706 g_free (mult_atoms);
1710 gdk_error_trap_pop ();
1712 /* This is annoying; the ICCCM doesn't specify the property type
1713 * used for the property contents, so the autoconversion for
1714 * ATOM / ATOM_PAIR in GDK doesn't work properly.
1716 #ifdef GDK_WINDOWING_X11
1717 if (type != GDK_SELECTION_TYPE_ATOM &&
1718 type != gdk_atom_intern ("ATOM_PAIR", FALSE))
1720 info->num_conversions = length / (2*sizeof (glong));
1721 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1723 for (i=0; i<info->num_conversions; i++)
1725 info->conversions[i].target = gdk_x11_xatom_to_atom_for_display (display,
1726 ((glong *)mult_atoms)[2*i]);
1727 info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display,
1728 ((glong *)mult_atoms)[2*i + 1]);
1734 info->num_conversions = length / (2*sizeof (GdkAtom));
1735 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1737 for (i=0; i<info->num_conversions; i++)
1739 info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
1740 info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
1744 else /* only a single conversion */
1746 info->conversions = g_new (GtkIncrConversion, 1);
1747 info->num_conversions = 1;
1748 info->conversions[0].target = event->target;
1749 info->conversions[0].property = event->property;
1752 /* Loop through conversions and determine which of these are big
1753 enough to require doing them via INCR */
1754 for (i=0; i<info->num_conversions; i++)
1756 GtkSelectionData data;
1759 data.selection = event->selection;
1760 data.target = info->conversions[i].target;
1763 data.display = gtk_widget_get_display (widget);
1765 #ifdef DEBUG_SELECTION
1766 g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
1768 info->conversions[i].target,
1769 gdk_atom_name (info->conversions[i].target),
1770 event->requestor, info->conversions[i].property);
1773 gtk_selection_invoke_handler (widget, &data, event->time);
1775 if (data.length < 0)
1777 info->conversions[i].property = GDK_NONE;
1781 g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
1783 items = data.length / gtk_selection_bytes_per_item (data.format);
1785 if (data.length > selection_max_size)
1787 /* Sending via INCR */
1788 #ifdef DEBUG_SELECTION
1789 g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n",
1790 data.length, selection_max_size);
1793 info->conversions[i].offset = 0;
1794 info->conversions[i].data = data;
1797 gdk_property_change (info->requestor,
1798 info->conversions[i].property,
1799 gtk_selection_atoms[INCR],
1801 GDK_PROP_MODE_REPLACE,
1802 (guchar *)&items, 1);
1806 info->conversions[i].offset = -1;
1808 gdk_property_change (info->requestor,
1809 info->conversions[i].property,
1812 GDK_PROP_MODE_REPLACE,
1819 /* If we have some INCR's, we need to send the rest of the data in
1822 if (info->num_incrs > 0)
1824 /* FIXME: this could be dangerous if window doesn't still
1827 #ifdef DEBUG_SELECTION
1828 g_message ("Starting INCR...");
1831 gdk_window_set_events (info->requestor,
1832 gdk_window_get_events (info->requestor) |
1833 GDK_PROPERTY_CHANGE_MASK);
1834 current_incrs = g_list_append (current_incrs, info);
1835 g_timeout_add (1000, (GSourceFunc) gtk_selection_incr_timeout, info);
1838 /* If it was a MULTIPLE request, set the property to indicate which
1839 conversions succeeded */
1840 if (event->target == gtk_selection_atoms[MULTIPLE])
1842 GdkAtom *mult_atoms = g_new (GdkAtom, 2 * info->num_conversions);
1843 for (i = 0; i < info->num_conversions; i++)
1845 mult_atoms[2*i] = info->conversions[i].target;
1846 mult_atoms[2*i+1] = info->conversions[i].property;
1849 gdk_property_change (info->requestor, event->property,
1850 gdk_atom_intern ("ATOM_PAIR", FALSE), 32,
1851 GDK_PROP_MODE_REPLACE,
1852 (guchar *)mult_atoms, 2*info->num_conversions);
1853 g_free (mult_atoms);
1856 if (info->num_conversions == 1 &&
1857 info->conversions[0].property == GDK_NONE)
1859 /* Reject the entire conversion */
1860 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1869 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1877 if (info->num_incrs == 0)
1879 g_free (info->conversions);
1883 g_object_unref (widget);
1888 /*************************************************************
1889 * _gtk_selection_incr_event:
1890 * Called whenever an PropertyNotify event occurs for an
1891 * GdkWindow with user_data == NULL. These will be notifications
1892 * that a window we are sending the selection to via the
1893 * INCR protocol has deleted a property and is ready for
1897 * window: the requestor window
1898 * event: the property event structure
1901 *************************************************************/
1904 _gtk_selection_incr_event (GdkWindow *window,
1905 GdkEventProperty *event)
1908 GtkIncrInfo *info = NULL;
1911 gulong selection_max_size;
1915 if (event->state != GDK_PROPERTY_DELETE)
1918 #ifdef DEBUG_SELECTION
1919 g_message ("PropertyDelete, property %ld", event->atom);
1922 selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window));
1924 /* Now find the appropriate ongoing INCR */
1925 tmp_list = current_incrs;
1928 info = (GtkIncrInfo *)tmp_list->data;
1929 if (info->requestor == event->window)
1932 tmp_list = tmp_list->next;
1935 if (tmp_list == NULL)
1938 /* Find out which target this is for */
1939 for (i=0; i<info->num_conversions; i++)
1941 if (info->conversions[i].property == event->atom &&
1942 info->conversions[i].offset != -1)
1946 info->idle_time = 0;
1948 if (info->conversions[i].offset == -2) /* only the last 0-length
1956 num_bytes = info->conversions[i].data.length -
1957 info->conversions[i].offset;
1958 buffer = info->conversions[i].data.data +
1959 info->conversions[i].offset;
1961 if (num_bytes > selection_max_size)
1963 num_bytes = selection_max_size;
1964 info->conversions[i].offset += selection_max_size;
1967 info->conversions[i].offset = -2;
1969 #ifdef DEBUG_SELECTION
1970 g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
1971 num_bytes, info->conversions[i].offset,
1972 GDK_WINDOW_XWINDOW(info->requestor), event->atom);
1975 bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
1976 gdk_property_change (info->requestor, event->atom,
1977 info->conversions[i].data.type,
1978 info->conversions[i].data.format,
1979 GDK_PROP_MODE_REPLACE,
1981 num_bytes / bytes_per_item);
1983 if (info->conversions[i].offset == -2)
1985 g_free (info->conversions[i].data.data);
1986 info->conversions[i].data.data = NULL;
1992 info->conversions[i].offset = -1;
1997 /* Check if we're finished with all the targets */
1999 if (info->num_incrs == 0)
2001 current_incrs = g_list_remove_link (current_incrs, tmp_list);
2002 g_list_free (tmp_list);
2003 /* Let the timeout free it */
2009 /*************************************************************
2010 * gtk_selection_incr_timeout:
2011 * Timeout callback for the sending portion of the INCR
2014 * info: Information about this incr
2016 *************************************************************/
2019 gtk_selection_incr_timeout (GtkIncrInfo *info)
2024 GDK_THREADS_ENTER ();
2026 /* Determine if retrieval has finished by checking if it still in
2027 list of pending retrievals */
2029 tmp_list = current_incrs;
2032 if (info == (GtkIncrInfo *)tmp_list->data)
2034 tmp_list = tmp_list->next;
2037 /* If retrieval is finished */
2038 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2040 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2042 current_incrs = g_list_remove_link (current_incrs, tmp_list);
2043 g_list_free (tmp_list);
2046 g_free (info->conversions);
2047 /* FIXME: we should check if requestor window is still in use,
2048 and if not, remove it? */
2052 retval = FALSE; /* remove timeout */
2058 retval = TRUE; /* timeout will happen again */
2061 GDK_THREADS_LEAVE ();
2066 /*************************************************************
2067 * _gtk_selection_notify:
2068 * Handler for "selection_notify_event" signals on windows
2069 * where a retrieval is currently in process. The selection
2070 * owner has responded to our conversion request.
2072 * widget: Widget getting signal
2073 * event: Selection event structure
2074 * info: Information about this retrieval
2076 * was event handled?
2077 *************************************************************/
2080 _gtk_selection_notify (GtkWidget *widget,
2081 GdkEventSelection *event)
2084 GtkRetrievalInfo *info = NULL;
2085 guchar *buffer = NULL;
2090 #ifdef DEBUG_SELECTION
2091 g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
2092 event->selection, event->target, event->property);
2095 tmp_list = current_retrievals;
2098 info = (GtkRetrievalInfo *)tmp_list->data;
2099 if (info->widget == widget && info->selection == event->selection)
2101 tmp_list = tmp_list->next;
2104 if (!tmp_list) /* no retrieval in progress */
2107 if (event->property != GDK_NONE)
2108 length = gdk_selection_property_get (widget->window, &buffer,
2111 length = 0; /* silence gcc */
2113 if (event->property == GDK_NONE || buffer == NULL)
2115 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2116 g_list_free (tmp_list);
2117 /* structure will be freed in timeout */
2118 gtk_selection_retrieval_report (info,
2119 GDK_NONE, 0, NULL, -1, event->time);
2124 if (type == gtk_selection_atoms[INCR])
2126 /* The remainder of the selection will come through PropertyNotify
2129 info->notify_time = event->time;
2130 info->idle_time = 0;
2131 info->offset = 0; /* Mark as OK to proceed */
2132 gdk_window_set_events (widget->window,
2133 gdk_window_get_events (widget->window)
2134 | GDK_PROPERTY_CHANGE_MASK);
2138 /* We don't delete the info structure - that will happen in timeout */
2139 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2140 g_list_free (tmp_list);
2142 info->offset = length;
2143 gtk_selection_retrieval_report (info,
2145 buffer, length, event->time);
2148 gdk_property_delete (widget->window, event->property);
2155 /*************************************************************
2156 * _gtk_selection_property_notify:
2157 * Handler for "property_notify_event" signals on windows
2158 * where a retrieval is currently in process. The selection
2159 * owner has added more data.
2161 * widget: Widget getting signal
2162 * event: Property event structure
2163 * info: Information about this retrieval
2165 * was event handled?
2166 *************************************************************/
2169 _gtk_selection_property_notify (GtkWidget *widget,
2170 GdkEventProperty *event)
2173 GtkRetrievalInfo *info = NULL;
2179 g_return_val_if_fail (widget != NULL, FALSE);
2180 g_return_val_if_fail (event != NULL, FALSE);
2182 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
2183 if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */
2184 (event->atom != gdk_atom_intern ("GDK_SELECTION", FALSE))) /* not the right property */
2188 #ifdef DEBUG_SELECTION
2189 g_message ("PropertyNewValue, property %ld",
2193 tmp_list = current_retrievals;
2196 info = (GtkRetrievalInfo *)tmp_list->data;
2197 if (info->widget == widget)
2199 tmp_list = tmp_list->next;
2202 if (!tmp_list) /* No retrieval in progress */
2205 if (info->offset < 0) /* We haven't got the SelectionNotify
2206 for this retrieval yet */
2209 info->idle_time = 0;
2211 length = gdk_selection_property_get (widget->window, &new_buffer,
2213 gdk_property_delete (widget->window, event->atom);
2215 /* We could do a lot better efficiency-wise by paying attention to
2216 what length was sent in the initial INCR transaction, instead of
2217 doing memory allocation at every step. But its only guaranteed to
2218 be a _lower bound_ (pretty useless!) */
2220 if (length == 0 || type == GDK_NONE) /* final zero length portion */
2222 /* Info structure will be freed in timeout */
2223 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2224 g_list_free (tmp_list);
2225 gtk_selection_retrieval_report (info,
2227 (type == GDK_NONE) ? NULL : info->buffer,
2228 (type == GDK_NONE) ? -1 : info->offset,
2231 else /* append on newly arrived data */
2235 #ifdef DEBUG_SELECTION
2236 g_message ("Start - Adding %d bytes at offset 0",
2239 info->buffer = new_buffer;
2240 info->offset = length;
2245 #ifdef DEBUG_SELECTION
2246 g_message ("Appending %d bytes at offset %d",
2247 length,info->offset);
2249 /* We copy length+1 bytes to preserve guaranteed null termination */
2250 info->buffer = g_realloc (info->buffer, info->offset+length+1);
2251 memcpy (info->buffer + info->offset, new_buffer, length+1);
2252 info->offset += length;
2253 g_free (new_buffer);
2260 /*************************************************************
2261 * gtk_selection_retrieval_timeout:
2262 * Timeout callback while receiving a selection.
2264 * info: Information about this retrieval
2266 *************************************************************/
2269 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
2274 GDK_THREADS_ENTER ();
2276 /* Determine if retrieval has finished by checking if it still in
2277 list of pending retrievals */
2279 tmp_list = current_retrievals;
2282 if (info == (GtkRetrievalInfo *)tmp_list->data)
2284 tmp_list = tmp_list->next;
2287 /* If retrieval is finished */
2288 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2290 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2292 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2293 g_list_free (tmp_list);
2294 gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
2297 g_free (info->buffer);
2300 retval = FALSE; /* remove timeout */
2306 retval = TRUE; /* timeout will happen again */
2309 GDK_THREADS_LEAVE ();
2314 /*************************************************************
2315 * gtk_selection_retrieval_report:
2316 * Emits a "selection_received" signal.
2318 * info: information about the retrieval that completed
2319 * buffer: buffer containing data (NULL => errror)
2320 * time: timestamp for data in buffer
2322 *************************************************************/
2325 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
2326 GdkAtom type, gint format,
2327 guchar *buffer, gint length,
2330 GtkSelectionData data;
2332 data.selection = info->selection;
2333 data.target = info->target;
2335 data.format = format;
2337 data.length = length;
2339 data.display = gtk_widget_get_display (info->widget);
2341 g_signal_emit_by_name (info->widget,
2342 "selection_received",
2346 /*************************************************************
2347 * gtk_selection_invoke_handler:
2348 * Finds and invokes handler for specified
2349 * widget/selection/target combination, calls
2350 * gtk_selection_default_handler if none exists.
2353 * widget: selection owner
2354 * data: selection data [INOUT]
2355 * time: time from requeset
2358 * Number of bytes written to buffer, -1 if error
2359 *************************************************************/
2362 gtk_selection_invoke_handler (GtkWidget *widget,
2363 GtkSelectionData *data,
2366 GtkTargetList *target_list;
2370 g_return_if_fail (widget != NULL);
2372 target_list = gtk_selection_target_list_get (widget, data->selection);
2374 gtk_target_list_find (target_list, data->target, &info))
2376 g_signal_emit_by_name (widget,
2382 gtk_selection_default_handler (widget, data);
2385 /*************************************************************
2386 * gtk_selection_default_handler:
2387 * Handles some default targets that exist for any widget
2388 * If it can't fit results into buffer, returns -1. This
2389 * won't happen in any conceivable case, since it would
2390 * require 1000 selection targets!
2393 * widget: selection owner
2394 * data: selection data [INOUT]
2396 *************************************************************/
2399 gtk_selection_default_handler (GtkWidget *widget,
2400 GtkSelectionData *data)
2402 if (data->target == gtk_selection_atoms[TIMESTAMP])
2404 /* Time which was used to obtain selection */
2406 GtkSelectionInfo *selection_info;
2408 tmp_list = current_selections;
2411 selection_info = (GtkSelectionInfo *)tmp_list->data;
2412 if ((selection_info->widget == widget) &&
2413 (selection_info->selection == data->selection))
2415 gulong time = selection_info->time;
2417 gtk_selection_data_set (data,
2418 GDK_SELECTION_TYPE_INTEGER,
2425 tmp_list = tmp_list->next;
2430 else if (data->target == gtk_selection_atoms[TARGETS])
2432 /* List of all targets supported for this widget/selection pair */
2436 GtkTargetList *target_list;
2437 GtkTargetPair *pair;
2439 target_list = gtk_selection_target_list_get (widget,
2441 count = g_list_length (target_list->list) + 3;
2443 data->type = GDK_SELECTION_TYPE_ATOM;
2445 data->length = count * sizeof (GdkAtom);
2447 /* selection data is always terminated by a trailing \0
2449 p = g_malloc (data->length + 1);
2450 data->data = (guchar *)p;
2451 data->data[data->length] = '\0';
2453 *p++ = gtk_selection_atoms[TIMESTAMP];
2454 *p++ = gtk_selection_atoms[TARGETS];
2455 *p++ = gtk_selection_atoms[MULTIPLE];
2457 tmp_list = target_list->list;
2460 pair = (GtkTargetPair *)tmp_list->data;
2461 *p++ = pair->target;
2463 tmp_list = tmp_list->next;
2474 gtk_selection_data_copy (GtkSelectionData *selection_data)
2476 GtkSelectionData *new_data;
2478 g_return_val_if_fail (selection_data != NULL, NULL);
2480 new_data = g_new (GtkSelectionData, 1);
2481 *new_data = *selection_data;
2483 if (selection_data->data)
2485 new_data->data = g_malloc (selection_data->length + 1);
2486 memcpy (new_data->data, selection_data->data, selection_data->length + 1);
2493 gtk_selection_data_free (GtkSelectionData *data)
2495 g_return_if_fail (data != NULL);
2498 g_free (data->data);
2504 gtk_selection_data_get_type (void)
2506 static GType our_type = 0;
2509 our_type = g_boxed_type_register_static ("GtkSelectionData",
2510 (GBoxedCopyFunc) gtk_selection_data_copy,
2511 (GBoxedFreeFunc) gtk_selection_data_free);
2517 gtk_selection_bytes_per_item (gint format)
2522 return sizeof (char);
2525 return sizeof (short);
2528 return sizeof (long);
2531 g_assert_not_reached();