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 ICCM 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 ICCM 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/.
59 #include "gtkselection.h"
61 /* #define DEBUG_SELECTION */
63 /* Maximum size of a sent chunk, in bytes. Also the default size of
65 #ifdef GDK_WINDOWING_WIN32
66 /* No chunks on Win32 */
67 #define GTK_SELECTION_MAX_SIZE G_MAXINT
69 #define GTK_SELECTION_MAX_SIZE 4000
72 #define IDLE_ABORT_TIME 300
82 typedef struct _GtkSelectionInfo GtkSelectionInfo;
83 typedef struct _GtkIncrConversion GtkIncrConversion;
84 typedef struct _GtkIncrInfo GtkIncrInfo;
85 typedef struct _GtkRetrievalInfo GtkRetrievalInfo;
87 struct _GtkSelectionInfo
90 GtkWidget *widget; /* widget that owns selection */
91 guint32 time; /* time used to acquire selection */
92 GdkDisplay *display; /* needed in gtk_selection_remove_all */
95 struct _GtkIncrConversion
97 GdkAtom target; /* Requested target */
98 GdkAtom property; /* Property to store in */
99 GtkSelectionData data; /* The data being supplied */
100 gint offset; /* Current offset in sent selection.
102 * -2 => Only the final (empty) portion
108 GdkWindow *requestor; /* Requestor window - we create a GdkWindow
109 so we can receive events */
110 GdkAtom selection; /* Selection we're sending */
112 GtkIncrConversion *conversions; /* Information about requested conversions -
113 * With MULTIPLE requests (benighted 1980's
114 * hardware idea), there can be more than
116 gint num_conversions;
117 gint num_incrs; /* number of remaining INCR style transactions */
122 struct _GtkRetrievalInfo
125 GdkAtom selection; /* Selection being retrieved. */
126 GdkAtom target; /* Form of selection that we requested */
127 guint32 idle_time; /* Number of seconds since we last heard
128 from selection owner */
129 guchar *buffer; /* Buffer in which to accumulate results */
130 gint offset; /* Current offset in buffer, -1 indicates
132 guint32 notify_time; /* Timestamp from SelectionNotify */
135 /* Local Functions */
136 static void gtk_selection_init (void);
137 static gint gtk_selection_incr_timeout (GtkIncrInfo *info);
138 static gint gtk_selection_retrieval_timeout (GtkRetrievalInfo *info);
139 static void gtk_selection_retrieval_report (GtkRetrievalInfo *info,
145 static void gtk_selection_invoke_handler (GtkWidget *widget,
146 GtkSelectionData *data,
148 static void gtk_selection_default_handler (GtkWidget *widget,
149 GtkSelectionData *data);
150 static int gtk_selection_bytes_per_item (gint format);
153 static gint initialize = TRUE;
154 static GList *current_retrievals = NULL;
155 static GList *current_incrs = NULL;
156 static GList *current_selections = NULL;
158 static GdkAtom gtk_selection_atoms[LAST_ATOM];
159 static const char gtk_selection_handler_key[] = "gtk-selection-handlers";
170 gtk_target_list_new (const GtkTargetEntry *targets,
173 GtkTargetList *result = g_new (GtkTargetList, 1);
175 result->ref_count = 1;
178 gtk_target_list_add_table (result, targets, ntargets);
184 gtk_target_list_ref (GtkTargetList *list)
186 g_return_if_fail (list != NULL);
192 gtk_target_list_unref (GtkTargetList *list)
194 g_return_if_fail (list != NULL);
195 g_return_if_fail (list->ref_count > 0);
198 if (list->ref_count == 0)
200 GList *tmp_list = list->list;
203 GtkTargetPair *pair = tmp_list->data;
206 tmp_list = tmp_list->next;
209 g_list_free (list->list);
215 gtk_target_list_add (GtkTargetList *list,
222 g_return_if_fail (list != NULL);
224 pair = g_new (GtkTargetPair, 1);
225 pair->target = target;
229 list->list = g_list_append (list->list, pair);
233 gtk_target_list_add_table (GtkTargetList *list,
234 const GtkTargetEntry *targets,
239 for (i=ntargets-1; i >= 0; i--)
241 GtkTargetPair *pair = g_new (GtkTargetPair, 1);
242 pair->target = gdk_atom_intern (targets[i].target, FALSE);
243 pair->flags = targets[i].flags;
244 pair->info = targets[i].info;
246 list->list = g_list_prepend (list->list, pair);
251 gtk_target_list_remove (GtkTargetList *list,
256 g_return_if_fail (list != NULL);
258 tmp_list = list->list;
261 GtkTargetPair *pair = tmp_list->data;
263 if (pair->target == target)
267 list->list = g_list_remove_link (list->list, tmp_list);
268 g_list_free_1 (tmp_list);
273 tmp_list = tmp_list->next;
278 gtk_target_list_find (GtkTargetList *list,
282 GList *tmp_list = list->list;
285 GtkTargetPair *pair = tmp_list->data;
287 if (pair->target == target)
292 tmp_list = tmp_list->next;
299 * gtk_selection_owner_set_for_display:
300 * @display: the #Gdkdisplay where the selection is set
301 * @widget: new selection owner (a #GdkWidget), or %NULL.
302 * @selection: an interned atom representing the selection to claim.
303 * @time_: timestamp with which to claim the selection
305 * Claim ownership of a given selection for a particular widget, or,
306 * if @widget is %NULL, release ownership of the selection.
308 * Return value: TRUE if the operation succeeded
313 gtk_selection_owner_set_for_display (GdkDisplay *display,
319 GtkWidget *old_owner;
320 GtkSelectionInfo *selection_info = NULL;
323 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
324 g_return_val_if_fail (selection != GDK_NONE, FALSE);
325 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
326 g_return_val_if_fail (widget == NULL || gtk_widget_get_display (widget) == display, FALSE);
331 window = widget->window;
333 tmp_list = current_selections;
336 if (((GtkSelectionInfo *)tmp_list->data)->selection == selection)
338 selection_info = tmp_list->data;
342 tmp_list = tmp_list->next;
345 if (gdk_selection_owner_set_for_display (display, window, selection, time, TRUE))
353 old_owner = selection_info->widget;
354 current_selections = g_list_remove_link (current_selections,
356 g_list_free (tmp_list);
357 g_free (selection_info);
362 if (selection_info == NULL)
364 selection_info = g_new (GtkSelectionInfo, 1);
365 selection_info->selection = selection;
366 selection_info->widget = widget;
367 selection_info->time = time;
368 selection_info->display = display;
369 current_selections = g_list_prepend (current_selections,
374 old_owner = selection_info->widget;
375 selection_info->widget = widget;
376 selection_info->time = time;
377 selection_info->display = display;
380 /* If another widget in the application lost the selection,
381 * send it a GDK_SELECTION_CLEAR event.
383 if (old_owner && old_owner != widget)
385 GdkEvent *event = gdk_event_new (GDK_SELECTION_CLEAR);
387 event->selection.window = g_object_ref (old_owner->window);
388 event->selection.selection = selection;
389 event->selection.time = time;
391 gtk_widget_event (old_owner, event);
393 gdk_event_free (event);
402 * gtk_selection_owner_set:
403 * @widget: a #GtkWidget, or %NULL.
404 * @selection: an interned atom representing the selection to claim
405 * @time_: timestamp with which to claim the selection
407 * Claims ownership of a given selection for a particular widget,
408 * or, if @widget is %NULL, release ownership of the selection.
410 * Return value: %TRUE if the operation succeeded
413 gtk_selection_owner_set (GtkWidget *widget,
419 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
420 g_return_val_if_fail (selection != GDK_NONE, FALSE);
423 display = gtk_widget_get_display (widget);
427 g_warning ("gtk_selection_owner_set (NULL,...) is not multihead safe"));
429 display = gdk_display_get_default ();
432 return gtk_selection_owner_set_for_display (display, widget,
436 /*************************************************************
437 * gtk_selection_add_target
438 * Add specified target to list of supported targets
441 * widget: The widget for which this target applies
444 * info: guint to pass to to the selection_get signal
447 *************************************************************/
449 typedef struct _GtkSelectionTargetList GtkSelectionTargetList;
451 struct _GtkSelectionTargetList {
456 static GtkTargetList *
457 gtk_selection_target_list_get (GtkWidget *widget,
460 GtkSelectionTargetList *sellist;
464 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
469 sellist = tmp_list->data;
470 if (sellist->selection == selection)
471 return sellist->list;
472 tmp_list = tmp_list->next;
475 sellist = g_new (GtkSelectionTargetList, 1);
476 sellist->selection = selection;
477 sellist->list = gtk_target_list_new (NULL, 0);
479 lists = g_list_prepend (lists, sellist);
480 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
482 return sellist->list;
486 gtk_selection_target_list_remove (GtkWidget *widget)
488 GtkSelectionTargetList *sellist;
492 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
497 sellist = tmp_list->data;
499 gtk_target_list_unref (sellist->list);
502 tmp_list = tmp_list->next;
506 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, NULL);
510 * gtk_selection_clear_targets:
511 * @widget: a #GtkWidget
512 * @selection: an atom representing a selection
514 * Remove all targets registered for the given selection for the
518 gtk_selection_clear_targets (GtkWidget *widget,
521 GtkSelectionTargetList *sellist;
525 g_return_if_fail (GTK_IS_WIDGET (widget));
526 g_return_if_fail (selection != GDK_NONE);
528 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
533 sellist = tmp_list->data;
534 if (sellist->selection == selection)
536 lists = g_list_delete_link (lists, tmp_list);
537 gtk_target_list_unref (sellist->list);
543 tmp_list = tmp_list->next;
546 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
550 gtk_selection_add_target (GtkWidget *widget,
557 g_return_if_fail (GTK_IS_WIDGET (widget));
558 g_return_if_fail (selection != GDK_NONE);
560 list = gtk_selection_target_list_get (widget, selection);
561 gtk_target_list_add (list, target, 0, info);
565 gtk_selection_add_targets (GtkWidget *widget,
567 const GtkTargetEntry *targets,
572 g_return_if_fail (GTK_IS_WIDGET (widget));
573 g_return_if_fail (selection != GDK_NONE);
574 g_return_if_fail (targets != NULL);
576 list = gtk_selection_target_list_get (widget, selection);
577 gtk_target_list_add_table (list, targets, ntargets);
581 /*************************************************************
582 * gtk_selection_remove_all:
583 * Removes all handlers and unsets ownership of all
584 * selections for a widget. Called when widget is being
590 *************************************************************/
593 gtk_selection_remove_all (GtkWidget *widget)
597 GtkSelectionInfo *selection_info;
599 /* Remove pending requests/incrs for this widget */
601 tmp_list = current_retrievals;
604 next = tmp_list->next;
605 if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget)
607 current_retrievals = g_list_remove_link (current_retrievals,
609 /* structure will be freed in timeout */
610 g_list_free (tmp_list);
615 /* Disclaim ownership of any selections */
617 tmp_list = current_selections;
620 next = tmp_list->next;
621 selection_info = (GtkSelectionInfo *)tmp_list->data;
623 if (selection_info->widget == widget)
625 gdk_selection_owner_set_for_display (selection_info->display,
627 selection_info->selection,
628 GDK_CURRENT_TIME, FALSE);
629 current_selections = g_list_remove_link (current_selections,
631 g_list_free (tmp_list);
632 g_free (selection_info);
638 /* Remove all selection lists */
639 gtk_selection_target_list_remove (widget);
642 /*************************************************************
643 * gtk_selection_convert:
644 * Request the contents of a selection. When received,
645 * a "selection_received" signal will be generated.
648 * widget: The widget which acts as requestor
649 * selection: Which selection to get
650 * target: Form of information desired (e.g., STRING)
651 * time: Time of request (usually of triggering event)
652 * In emergency, you could use GDK_CURRENT_TIME
655 * TRUE if requested succeeded. FALSE if we could not process
656 * request. (e.g., there was already a request in process for
658 *************************************************************/
661 gtk_selection_convert (GtkWidget *widget,
666 GtkRetrievalInfo *info;
668 GdkWindow *owner_window;
671 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
672 g_return_val_if_fail (selection != GDK_NONE, FALSE);
675 gtk_selection_init ();
677 if (!GTK_WIDGET_REALIZED (widget))
678 gtk_widget_realize (widget);
680 /* Check to see if there are already any retrievals in progress for
681 this widget. If we changed GDK to use the selection for the
682 window property in which to store the retrieved information, then
683 we could support multiple retrievals for different selections.
684 This might be useful for DND. */
686 tmp_list = current_retrievals;
689 info = (GtkRetrievalInfo *)tmp_list->data;
690 if (info->widget == widget)
692 tmp_list = tmp_list->next;
695 info = g_new (GtkRetrievalInfo, 1);
697 info->widget = widget;
698 info->selection = selection;
699 info->target = target;
704 /* Check if this process has current owner. If so, call handler
705 procedure directly to avoid deadlocks with INCR. */
707 display = gtk_widget_get_display (widget);
708 owner_window = gdk_selection_owner_get_for_display (display, selection);
710 if (owner_window != NULL)
712 GtkWidget *owner_widget;
713 GtkSelectionData selection_data;
715 selection_data.selection = selection;
716 selection_data.target = target;
717 selection_data.data = NULL;
718 selection_data.length = -1;
719 selection_data.display = display;
721 gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget);
723 if (owner_widget != NULL)
725 gtk_selection_invoke_handler (owner_widget,
729 gtk_selection_retrieval_report (info,
731 selection_data.format,
733 selection_data.length,
736 g_free (selection_data.data);
743 /* Otherwise, we need to go through X */
745 current_retrievals = g_list_append (current_retrievals, info);
746 gdk_selection_convert (widget->window, selection, target, time);
747 gtk_timeout_add (1000, (GtkFunction) gtk_selection_retrieval_timeout, info);
752 /*************************************************************
753 * gtk_selection_data_set:
754 * Store new data into a GtkSelectionData object. Should
755 * _only_ by called from a selection handler callback.
756 * Null terminates the stored data.
758 * type: the type of selection data
759 * format: format (number of bits in a unit)
760 * data: pointer to the data (will be copied)
761 * length: length of the data
763 *************************************************************/
766 gtk_selection_data_set (GtkSelectionData *selection_data,
772 if (selection_data->data)
773 g_free (selection_data->data);
775 selection_data->type = type;
776 selection_data->format = format;
780 selection_data->data = g_new (guchar, length+1);
781 memcpy (selection_data->data, data, length);
782 selection_data->data[length] = 0;
786 g_return_if_fail (length <= 0);
789 selection_data->data = NULL;
791 selection_data->data = g_strdup("");
794 selection_data->length = length;
797 static GdkAtom utf8_atom;
798 static GdkAtom text_atom;
799 static GdkAtom ctext_atom;
806 utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
807 text_atom = gdk_atom_intern ("TEXT", FALSE);
808 ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
813 * gtk_selection_data_set_text:
814 * @selection_data: a #GtkSelectionData
815 * @str: a UTF-8 string
816 * @len: the length of @str, or -1 if @str is nul-terminated.
818 * Sets the contents of the selection from a UTF-8 encoded string.
819 * The string is converted to the form determined by
820 * @selection_data->target.
822 * Return value: %TRUE if the selection was successfully set,
826 gtk_selection_data_set_text (GtkSelectionData *selection_data,
830 gboolean result = FALSE;
837 if (selection_data->target == utf8_atom)
839 gtk_selection_data_set (selection_data,
841 8, (guchar *)str, len);
844 else if (selection_data->target == GDK_TARGET_STRING)
846 gchar *tmp = g_strndup (str, len);
847 gchar *latin1 = gdk_utf8_to_string_target (tmp);
852 gtk_selection_data_set (selection_data,
853 GDK_SELECTION_TYPE_STRING,
854 8, latin1, strlen (latin1));
861 else if (selection_data->target == ctext_atom ||
862 selection_data->target == text_atom)
870 tmp = g_strndup (str, len);
871 if (gdk_utf8_to_compound_text_for_display (selection_data->display, tmp,
872 &encoding, &format, &text, &new_length))
874 gtk_selection_data_set (selection_data, encoding, format, text, new_length);
875 gdk_free_compound_text (text);
887 * gtk_selection_data_get_text:
888 * @selection_data: a #GtkSelectionData
890 * Gets the contents of the selection data as a UTF-8 string.
892 * Return value: if the selection data contained a recognized
893 * text type and it could be converted to UTF-8, a newly allocated
894 * string containing the converted text, otherwise %NULL.
895 * If the result is non-%NULL it must be freed with g_free().
898 gtk_selection_data_get_text (GtkSelectionData *selection_data)
900 guchar *result = NULL;
904 if (selection_data->length >= 0 &&
905 (selection_data->type == GDK_TARGET_STRING ||
906 selection_data->type == ctext_atom ||
907 selection_data->type == utf8_atom))
911 gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
912 selection_data->type,
913 selection_data->format,
914 selection_data->data,
915 selection_data->length,
920 for (i = 1; i < count; i++)
929 * gtk_selection_data_get_targets:
930 * @selection_data: a #GtkSelectionData object
931 * @targets: location to store an array of targets. The result
932 * stored here must be freed with g_free().
933 * @n_atoms: location to store number of items in @targets.
935 * Gets the contents of @selection_data as an array of targets.
936 * This can be used to interpret the results of getting
937 * the standard TARGETS target that is always supplied for
940 * Return value: %TRUE if @selection_data contains a valid
941 * array of targets, otherwise %FALSE.
944 gtk_selection_data_get_targets (GtkSelectionData *selection_data,
948 if (selection_data->length >= 0 &&
949 selection_data->format == 32 &&
950 selection_data->type == GDK_SELECTION_TYPE_ATOM)
953 *targets = g_memdup (selection_data->data, selection_data->length);
955 *n_atoms = selection_data->length / sizeof (GdkAtom);
971 * gtk_selection_data_targets_include_text:
972 * @selection_data: a #GtkSelectionData object
974 * Given a #GtkSelectionData object holding a list of targets,
975 * determines if any of the targets in @targets can be used to
978 * Return value: %TRUE if @selection_data holds a list of targets,
979 * and a suitable target for text is included, otherwise %FALSE.
982 gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
987 gboolean result = FALSE;
989 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
991 for (i=0; i < n_targets; i++)
993 if (targets[i] == gdk_atom_intern ("STRING", FALSE) ||
994 targets[i] == gdk_atom_intern ("TEXT", FALSE) ||
995 targets[i] == gdk_atom_intern ("COMPOUND_TEXT", FALSE) ||
996 targets[i] == gdk_atom_intern ("UTF8_STRING", FALSE))
1006 /*************************************************************
1007 * gtk_selection_init:
1008 * Initialize local variables
1012 *************************************************************/
1015 gtk_selection_init (void)
1017 gtk_selection_atoms[INCR] = gdk_atom_intern ("INCR", FALSE);
1018 gtk_selection_atoms[MULTIPLE] = gdk_atom_intern ("MULTIPLE", FALSE);
1019 gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern ("TIMESTAMP", FALSE);
1020 gtk_selection_atoms[TARGETS] = gdk_atom_intern ("TARGETS", FALSE);
1026 * gtk_selection_clear:
1027 * @widget: a #GtkWidget
1030 * The default handler for the GtkWidget::selection_clear_event
1031 * signal. Instead of calling this function, chain up from
1032 * your selection_clear_event handler. Calling this function
1033 * from any other context is illegal. This function will
1034 * be deprecated in future versions of GTK+.
1036 * Return value: %TRUE if the event was handled, otherwise false
1041 gtk_selection_clear (GtkWidget *widget,
1042 GdkEventSelection *event)
1044 /* Note that we filter clear events in gdkselection-x11.c, so
1045 * that we only will get here if the clear event actually
1046 * represents a change that we didn't do ourself.
1049 GtkSelectionInfo *selection_info = NULL;
1051 tmp_list = current_selections;
1054 selection_info = (GtkSelectionInfo *)tmp_list->data;
1056 if ((selection_info->selection == event->selection) &&
1057 (selection_info->widget == widget))
1060 tmp_list = tmp_list->next;
1065 current_selections = g_list_remove_link (current_selections, tmp_list);
1066 g_list_free (tmp_list);
1067 g_free (selection_info);
1074 /*************************************************************
1075 * _gtk_selection_request:
1076 * Handler for "selection_request_event"
1081 *************************************************************/
1084 _gtk_selection_request (GtkWidget *widget,
1085 GdkEventSelection *event)
1093 gtk_selection_init ();
1095 /* Check if we own selection */
1097 tmp_list = current_selections;
1100 GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data;
1102 if ((selection_info->selection == event->selection) &&
1103 (selection_info->widget == widget))
1106 tmp_list = tmp_list->next;
1109 if (tmp_list == NULL)
1112 info = g_new (GtkIncrInfo, 1);
1114 g_object_ref (widget);
1116 info->selection = event->selection;
1117 info->num_incrs = 0;
1119 /* Create GdkWindow structure for the requestor */
1121 info->requestor = gdk_window_lookup_for_display (gtk_widget_get_display (widget),
1123 if (!info->requestor)
1124 info->requestor = gdk_window_foreign_new_for_display (gtk_widget_get_display (widget),
1127 /* Determine conversions we need to perform */
1129 if (event->target == gtk_selection_atoms[MULTIPLE])
1137 gdk_error_trap_push ();
1138 if (!gdk_property_get (info->requestor, event->property, 0, /* AnyPropertyType */
1139 0, GTK_SELECTION_MAX_SIZE, FALSE,
1140 &type, &format, &length, &mult_atoms))
1142 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1148 g_free (mult_atoms);
1152 gdk_error_trap_pop ();
1154 info->num_conversions = length / (2*sizeof (GdkAtom));
1155 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1157 for (i=0; i<info->num_conversions; i++)
1159 info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
1160 info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
1163 else /* only a single conversion */
1165 info->conversions = g_new (GtkIncrConversion, 1);
1166 info->num_conversions = 1;
1167 info->conversions[0].target = event->target;
1168 info->conversions[0].property = event->property;
1169 mult_atoms = (guchar *)info->conversions;
1172 /* Loop through conversions and determine which of these are big
1173 enough to require doing them via INCR */
1174 for (i=0; i<info->num_conversions; i++)
1176 GtkSelectionData data;
1179 data.selection = event->selection;
1180 data.target = info->conversions[i].target;
1183 data.display = gtk_widget_get_display (widget);
1185 #ifdef DEBUG_SELECTION
1186 g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
1187 event->selection, info->conversions[i].target,
1188 gdk_atom_name (info->conversions[i].target),
1189 event->requestor, event->property);
1192 gtk_selection_invoke_handler (widget, &data, event->time);
1194 if (data.length < 0)
1196 ((GdkAtom *)mult_atoms)[2*i+1] = GDK_NONE;
1197 info->conversions[i].property = GDK_NONE;
1201 g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
1203 items = data.length / gtk_selection_bytes_per_item (data.format);
1205 if (data.length > GTK_SELECTION_MAX_SIZE)
1207 /* Sending via INCR */
1209 info->conversions[i].offset = 0;
1210 info->conversions[i].data = data;
1213 gdk_property_change (info->requestor,
1214 info->conversions[i].property,
1215 gtk_selection_atoms[INCR],
1217 GDK_PROP_MODE_REPLACE,
1218 (guchar *)&items, 1);
1222 info->conversions[i].offset = -1;
1224 gdk_property_change (info->requestor,
1225 info->conversions[i].property,
1228 GDK_PROP_MODE_REPLACE,
1235 /* If we have some INCR's, we need to send the rest of the data in
1238 if (info->num_incrs > 0)
1240 /* FIXME: this could be dangerous if window doesn't still
1243 #ifdef DEBUG_SELECTION
1244 g_message ("Starting INCR...");
1247 gdk_window_set_events (info->requestor,
1248 gdk_window_get_events (info->requestor) |
1249 GDK_PROPERTY_CHANGE_MASK);
1250 current_incrs = g_list_append (current_incrs, info);
1251 gtk_timeout_add (1000, (GtkFunction)gtk_selection_incr_timeout, info);
1254 /* If it was a MULTIPLE request, set the property to indicate which
1255 conversions succeeded */
1256 if (event->target == gtk_selection_atoms[MULTIPLE])
1258 gdk_property_change (info->requestor, event->property,
1259 gdk_atom_intern ("ATOM_PAIR", FALSE), 32,
1260 GDK_PROP_MODE_REPLACE,
1261 mult_atoms, 2*info->num_conversions);
1262 g_free (mult_atoms);
1265 if (info->num_conversions == 1 &&
1266 info->conversions[0].property == GDK_NONE)
1268 /* Reject the entire conversion */
1269 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1278 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1286 if (info->num_incrs == 0)
1288 g_free (info->conversions);
1292 g_object_unref (widget);
1297 /*************************************************************
1298 * _gtk_selection_incr_event:
1299 * Called whenever an PropertyNotify event occurs for an
1300 * GdkWindow with user_data == NULL. These will be notifications
1301 * that a window we are sending the selection to via the
1302 * INCR protocol has deleted a property and is ready for
1306 * window: the requestor window
1307 * event: the property event structure
1310 *************************************************************/
1313 _gtk_selection_incr_event (GdkWindow *window,
1314 GdkEventProperty *event)
1317 GtkIncrInfo *info = NULL;
1323 if (event->state != GDK_PROPERTY_DELETE)
1326 #ifdef DEBUG_SELECTION
1327 g_message ("PropertyDelete, property %ld", event->atom);
1330 /* Now find the appropriate ongoing INCR */
1331 tmp_list = current_incrs;
1334 info = (GtkIncrInfo *)tmp_list->data;
1335 if (info->requestor == event->window)
1338 tmp_list = tmp_list->next;
1341 if (tmp_list == NULL)
1344 /* Find out which target this is for */
1345 for (i=0; i<info->num_conversions; i++)
1347 if (info->conversions[i].property == event->atom &&
1348 info->conversions[i].offset != -1)
1352 info->idle_time = 0;
1354 if (info->conversions[i].offset == -2) /* only the last 0-length
1362 num_bytes = info->conversions[i].data.length -
1363 info->conversions[i].offset;
1364 buffer = info->conversions[i].data.data +
1365 info->conversions[i].offset;
1367 if (num_bytes > GTK_SELECTION_MAX_SIZE)
1369 num_bytes = GTK_SELECTION_MAX_SIZE;
1370 info->conversions[i].offset += GTK_SELECTION_MAX_SIZE;
1373 info->conversions[i].offset = -2;
1375 #ifdef DEBUG_SELECTION
1376 g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
1377 num_bytes, info->conversions[i].offset,
1378 GDK_WINDOW_XWINDOW(info->requestor), event->atom);
1381 bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
1382 gdk_property_change (info->requestor, event->atom,
1383 info->conversions[i].data.type,
1384 info->conversions[i].data.format,
1385 GDK_PROP_MODE_REPLACE,
1387 num_bytes / bytes_per_item);
1389 if (info->conversions[i].offset == -2)
1391 g_free (info->conversions[i].data.data);
1392 info->conversions[i].data.data = NULL;
1398 info->conversions[i].offset = -1;
1404 /* Check if we're finished with all the targets */
1406 if (info->num_incrs == 0)
1408 current_incrs = g_list_remove_link (current_incrs, tmp_list);
1409 g_list_free (tmp_list);
1410 /* Let the timeout free it */
1416 /*************************************************************
1417 * gtk_selection_incr_timeout:
1418 * Timeout callback for the sending portion of the INCR
1421 * info: Information about this incr
1423 *************************************************************/
1426 gtk_selection_incr_timeout (GtkIncrInfo *info)
1431 GDK_THREADS_ENTER ();
1433 /* Determine if retrieval has finished by checking if it still in
1434 list of pending retrievals */
1436 tmp_list = current_incrs;
1439 if (info == (GtkIncrInfo *)tmp_list->data)
1441 tmp_list = tmp_list->next;
1444 /* If retrieval is finished */
1445 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
1447 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
1449 current_incrs = g_list_remove_link (current_incrs, tmp_list);
1450 g_list_free (tmp_list);
1453 g_free (info->conversions);
1454 /* FIXME: we should check if requestor window is still in use,
1455 and if not, remove it? */
1459 retval = FALSE; /* remove timeout */
1465 retval = TRUE; /* timeout will happen again */
1468 GDK_THREADS_LEAVE ();
1473 /*************************************************************
1474 * _gtk_selection_notify:
1475 * Handler for "selection_notify_event" signals on windows
1476 * where a retrieval is currently in process. The selection
1477 * owner has responded to our conversion request.
1479 * widget: Widget getting signal
1480 * event: Selection event structure
1481 * info: Information about this retrieval
1483 * was event handled?
1484 *************************************************************/
1487 _gtk_selection_notify (GtkWidget *widget,
1488 GdkEventSelection *event)
1491 GtkRetrievalInfo *info = NULL;
1492 guchar *buffer = NULL;
1497 #ifdef DEBUG_SELECTION
1498 g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
1499 event->selection, event->target, event->property);
1502 tmp_list = current_retrievals;
1505 info = (GtkRetrievalInfo *)tmp_list->data;
1506 if (info->widget == widget && info->selection == event->selection)
1508 tmp_list = tmp_list->next;
1511 if (!tmp_list) /* no retrieval in progress */
1514 if (event->property != GDK_NONE)
1515 length = gdk_selection_property_get (widget->window, &buffer,
1518 length = 0; /* silence gcc */
1520 if (event->property == GDK_NONE || buffer == NULL)
1522 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1523 g_list_free (tmp_list);
1524 /* structure will be freed in timeout */
1525 gtk_selection_retrieval_report (info,
1526 GDK_NONE, 0, NULL, -1, event->time);
1531 if (type == gtk_selection_atoms[INCR])
1533 /* The remainder of the selection will come through PropertyNotify
1536 info->notify_time = event->time;
1537 info->idle_time = 0;
1538 info->offset = 0; /* Mark as OK to proceed */
1539 gdk_window_set_events (widget->window,
1540 gdk_window_get_events (widget->window)
1541 | GDK_PROPERTY_CHANGE_MASK);
1545 /* We don't delete the info structure - that will happen in timeout */
1546 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1547 g_list_free (tmp_list);
1549 info->offset = length;
1550 gtk_selection_retrieval_report (info,
1552 buffer, length, event->time);
1555 gdk_property_delete (widget->window, event->property);
1562 /*************************************************************
1563 * _gtk_selection_property_notify:
1564 * Handler for "property_notify_event" signals on windows
1565 * where a retrieval is currently in process. The selection
1566 * owner has added more data.
1568 * widget: Widget getting signal
1569 * event: Property event structure
1570 * info: Information about this retrieval
1572 * was event handled?
1573 *************************************************************/
1576 _gtk_selection_property_notify (GtkWidget *widget,
1577 GdkEventProperty *event)
1580 GtkRetrievalInfo *info = NULL;
1586 g_return_val_if_fail (widget != NULL, FALSE);
1587 g_return_val_if_fail (event != NULL, FALSE);
1589 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
1590 if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */
1591 (event->atom != gdk_atom_intern ("GDK_SELECTION", FALSE))) /* not the right property */
1595 #ifdef DEBUG_SELECTION
1596 g_message ("PropertyNewValue, property %ld",
1600 tmp_list = current_retrievals;
1603 info = (GtkRetrievalInfo *)tmp_list->data;
1604 if (info->widget == widget)
1606 tmp_list = tmp_list->next;
1609 if (!tmp_list) /* No retrieval in progress */
1612 if (info->offset < 0) /* We haven't got the SelectionNotify
1613 for this retrieval yet */
1616 info->idle_time = 0;
1618 length = gdk_selection_property_get (widget->window, &new_buffer,
1620 gdk_property_delete (widget->window, event->atom);
1622 /* We could do a lot better efficiency-wise by paying attention to
1623 what length was sent in the initial INCR transaction, instead of
1624 doing memory allocation at every step. But its only guaranteed to
1625 be a _lower bound_ (pretty useless!) */
1627 if (length == 0 || type == GDK_NONE) /* final zero length portion */
1629 /* Info structure will be freed in timeout */
1630 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1631 g_list_free (tmp_list);
1632 gtk_selection_retrieval_report (info,
1634 (type == GDK_NONE) ? NULL : info->buffer,
1635 (type == GDK_NONE) ? -1 : info->offset,
1638 else /* append on newly arrived data */
1642 #ifdef DEBUG_SELECTION
1643 g_message ("Start - Adding %d bytes at offset 0",
1646 info->buffer = new_buffer;
1647 info->offset = length;
1652 #ifdef DEBUG_SELECTION
1653 g_message ("Appending %d bytes at offset %d",
1654 length,info->offset);
1656 /* We copy length+1 bytes to preserve guaranteed null termination */
1657 info->buffer = g_realloc (info->buffer, info->offset+length+1);
1658 memcpy (info->buffer + info->offset, new_buffer, length+1);
1659 info->offset += length;
1660 g_free (new_buffer);
1667 /*************************************************************
1668 * gtk_selection_retrieval_timeout:
1669 * Timeout callback while receiving a selection.
1671 * info: Information about this retrieval
1673 *************************************************************/
1676 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
1681 GDK_THREADS_ENTER ();
1683 /* Determine if retrieval has finished by checking if it still in
1684 list of pending retrievals */
1686 tmp_list = current_retrievals;
1689 if (info == (GtkRetrievalInfo *)tmp_list->data)
1691 tmp_list = tmp_list->next;
1694 /* If retrieval is finished */
1695 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
1697 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
1699 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1700 g_list_free (tmp_list);
1701 gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
1704 g_free (info->buffer);
1707 retval = FALSE; /* remove timeout */
1713 retval = TRUE; /* timeout will happen again */
1716 GDK_THREADS_LEAVE ();
1721 /*************************************************************
1722 * gtk_selection_retrieval_report:
1723 * Emits a "selection_received" signal.
1725 * info: information about the retrieval that completed
1726 * buffer: buffer containing data (NULL => errror)
1727 * time: timestamp for data in buffer
1729 *************************************************************/
1732 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
1733 GdkAtom type, gint format,
1734 guchar *buffer, gint length,
1737 GtkSelectionData data;
1739 data.selection = info->selection;
1740 data.target = info->target;
1742 data.format = format;
1744 data.length = length;
1746 data.display = gtk_widget_get_display (info->widget);
1748 g_signal_emit_by_name (info->widget,
1749 "selection_received",
1753 /*************************************************************
1754 * gtk_selection_invoke_handler:
1755 * Finds and invokes handler for specified
1756 * widget/selection/target combination, calls
1757 * gtk_selection_default_handler if none exists.
1760 * widget: selection owner
1761 * data: selection data [INOUT]
1762 * time: time from requeset
1765 * Number of bytes written to buffer, -1 if error
1766 *************************************************************/
1769 gtk_selection_invoke_handler (GtkWidget *widget,
1770 GtkSelectionData *data,
1773 GtkTargetList *target_list;
1777 g_return_if_fail (widget != NULL);
1779 target_list = gtk_selection_target_list_get (widget, data->selection);
1781 gtk_target_list_find (target_list, data->target, &info))
1783 g_signal_emit_by_name (widget,
1789 gtk_selection_default_handler (widget, data);
1792 /*************************************************************
1793 * gtk_selection_default_handler:
1794 * Handles some default targets that exist for any widget
1795 * If it can't fit results into buffer, returns -1. This
1796 * won't happen in any conceivable case, since it would
1797 * require 1000 selection targets!
1800 * widget: selection owner
1801 * data: selection data [INOUT]
1803 *************************************************************/
1806 gtk_selection_default_handler (GtkWidget *widget,
1807 GtkSelectionData *data)
1809 if (data->target == gtk_selection_atoms[TIMESTAMP])
1811 /* Time which was used to obtain selection */
1813 GtkSelectionInfo *selection_info;
1815 tmp_list = current_selections;
1818 selection_info = (GtkSelectionInfo *)tmp_list->data;
1819 if ((selection_info->widget == widget) &&
1820 (selection_info->selection == data->selection))
1822 gulong time = selection_info->time;
1824 gtk_selection_data_set (data,
1825 GDK_SELECTION_TYPE_INTEGER,
1832 tmp_list = tmp_list->next;
1837 else if (data->target == gtk_selection_atoms[TARGETS])
1839 /* List of all targets supported for this widget/selection pair */
1843 GtkTargetList *target_list;
1844 GtkTargetPair *pair;
1846 target_list = gtk_selection_target_list_get (widget,
1848 count = g_list_length (target_list->list) + 3;
1850 data->type = GDK_SELECTION_TYPE_ATOM;
1852 data->length = count * sizeof (GdkAtom);
1854 p = g_new (GdkAtom, count);
1855 data->data = (guchar *)p;
1857 *p++ = gtk_selection_atoms[TIMESTAMP];
1858 *p++ = gtk_selection_atoms[TARGETS];
1859 *p++ = gtk_selection_atoms[MULTIPLE];
1861 tmp_list = target_list->list;
1864 pair = (GtkTargetPair *)tmp_list->data;
1865 *p++ = pair->target;
1867 tmp_list = tmp_list->next;
1878 gtk_selection_data_copy (GtkSelectionData *selection_data)
1880 GtkSelectionData *new_data;
1882 g_return_val_if_fail (selection_data != NULL, NULL);
1884 new_data = g_new (GtkSelectionData, 1);
1885 *new_data = *selection_data;
1887 if (selection_data->data)
1889 new_data->data = g_malloc (selection_data->length + 1);
1890 memcpy (new_data->data, selection_data->data, selection_data->length + 1);
1897 gtk_selection_data_free (GtkSelectionData *data)
1899 g_return_if_fail (data != NULL);
1902 g_free (data->data);
1908 gtk_selection_data_get_type (void)
1910 static GType our_type = 0;
1913 our_type = g_boxed_type_register_static ("GtkSelectionData",
1914 (GBoxedCopyFunc) gtk_selection_data_copy,
1915 (GBoxedFreeFunc) gtk_selection_data_free);
1921 gtk_selection_bytes_per_item (gint format)
1926 return sizeof (char);
1929 return sizeof (short);
1932 return sizeof (long);
1935 g_assert_not_reached();