1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 /* This file implements most of the work of the ICCCM selection protocol.
21 * The code was written after an intensive study of the equivalent part
22 * of John Ousterhout's Tk toolkit, and does many things in much the
25 * The one thing in the ICCCM that isn't fully supported here (or in Tk)
26 * is side effects targets. For these to be handled properly, MULTIPLE
27 * targets need to be done in the order specified. This cannot be
28 * guaranteed with the way we do things, since if we are doing INCR
29 * transfers, the order will depend on the timing of the requestor.
31 * By Owen Taylor <owt1@cornell.edu> 8/16/97
34 /* Terminology note: when not otherwise specified, the term "incr" below
35 * refers to the _sending_ part of the INCR protocol. The receiving
36 * portion is referred to just as "retrieval". (Terminology borrowed
37 * from Tk, because there is no good opposite to "retrieval" in English.
38 * "send" can't be made into a noun gracefully and we're already using
39 * "emission" for something else ....)
42 /* The MOTIF entry widget seems to ask for the TARGETS target, then
43 (regardless of the reply) ask for the TEXT target. It's slightly
44 possible though that it somehow thinks we are responding negatively
45 to the TARGETS request, though I don't really think so ... */
48 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
49 * file for a list of people on the GTK+ Team. See the ChangeLog
50 * files for a list of changes. These files are distributed with
51 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
61 #include "gtkselection.h"
63 #ifdef GDK_WINDOWING_X11
67 #undef DEBUG_SELECTION
69 /* Maximum size of a sent chunk, in bytes. Also the default size of
71 #ifdef GDK_WINDOWING_X11
72 #define GTK_SELECTION_MAX_SIZE(display) \
74 XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0 \
75 ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100 \
76 : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
78 /* No chunks on Win32 */
79 #define GTK_SELECTION_MAX_SIZE(display) G_MAXINT
82 #define IDLE_ABORT_TIME 300
92 typedef struct _GtkSelectionInfo GtkSelectionInfo;
93 typedef struct _GtkIncrConversion GtkIncrConversion;
94 typedef struct _GtkIncrInfo GtkIncrInfo;
95 typedef struct _GtkRetrievalInfo GtkRetrievalInfo;
97 struct _GtkSelectionInfo
100 GtkWidget *widget; /* widget that owns selection */
101 guint32 time; /* time used to acquire selection */
102 GdkDisplay *display; /* needed in gtk_selection_remove_all */
105 struct _GtkIncrConversion
107 GdkAtom target; /* Requested target */
108 GdkAtom property; /* Property to store in */
109 GtkSelectionData data; /* The data being supplied */
110 gint offset; /* Current offset in sent selection.
112 * -2 => Only the final (empty) portion
118 GdkWindow *requestor; /* Requestor window - we create a GdkWindow
119 so we can receive events */
120 GdkAtom selection; /* Selection we're sending */
122 GtkIncrConversion *conversions; /* Information about requested conversions -
123 * With MULTIPLE requests (benighted 1980's
124 * hardware idea), there can be more than
126 gint num_conversions;
127 gint num_incrs; /* number of remaining INCR style transactions */
132 struct _GtkRetrievalInfo
135 GdkAtom selection; /* Selection being retrieved. */
136 GdkAtom target; /* Form of selection that we requested */
137 guint32 idle_time; /* Number of seconds since we last heard
138 from selection owner */
139 guchar *buffer; /* Buffer in which to accumulate results */
140 gint offset; /* Current offset in buffer, -1 indicates
142 guint32 notify_time; /* Timestamp from SelectionNotify */
145 /* Local Functions */
146 static void gtk_selection_init (void);
147 static gint gtk_selection_incr_timeout (GtkIncrInfo *info);
148 static gint gtk_selection_retrieval_timeout (GtkRetrievalInfo *info);
149 static void gtk_selection_retrieval_report (GtkRetrievalInfo *info,
155 static void gtk_selection_invoke_handler (GtkWidget *widget,
156 GtkSelectionData *data,
158 static void gtk_selection_default_handler (GtkWidget *widget,
159 GtkSelectionData *data);
160 static int gtk_selection_bytes_per_item (gint format);
163 static gint initialize = TRUE;
164 static GList *current_retrievals = NULL;
165 static GList *current_incrs = NULL;
166 static GList *current_selections = NULL;
168 static GdkAtom gtk_selection_atoms[LAST_ATOM];
169 static const char gtk_selection_handler_key[] = "gtk-selection-handlers";
180 gtk_target_list_new (const GtkTargetEntry *targets,
183 GtkTargetList *result = g_new (GtkTargetList, 1);
185 result->ref_count = 1;
188 gtk_target_list_add_table (result, targets, ntargets);
194 gtk_target_list_ref (GtkTargetList *list)
196 g_return_if_fail (list != NULL);
202 gtk_target_list_unref (GtkTargetList *list)
204 g_return_if_fail (list != NULL);
205 g_return_if_fail (list->ref_count > 0);
208 if (list->ref_count == 0)
210 GList *tmp_list = list->list;
213 GtkTargetPair *pair = tmp_list->data;
216 tmp_list = tmp_list->next;
219 g_list_free (list->list);
225 gtk_target_list_add (GtkTargetList *list,
232 g_return_if_fail (list != NULL);
234 pair = g_new (GtkTargetPair, 1);
235 pair->target = target;
239 list->list = g_list_append (list->list, pair);
242 static GdkAtom utf8_atom;
243 static GdkAtom text_atom;
244 static GdkAtom ctext_atom;
245 static GdkAtom text_plain_atom;
246 static GdkAtom text_plain_utf8_atom;
247 static GdkAtom text_plain_locale_atom;
253 const gchar *charset;
257 utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
258 text_atom = gdk_atom_intern ("TEXT", FALSE);
259 ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
260 text_plain_atom = gdk_atom_intern ("text/plain", FALSE);
261 text_plain_utf8_atom = gdk_atom_intern ("text/plain;charset=utf-8", FALSE);
262 g_get_charset (&charset);
263 tmp = g_strdup_printf ("text/plain;charset=%s", charset);
264 text_plain_locale_atom = gdk_atom_intern (tmp, FALSE);
270 * gtk_target_list_add_text_targets:
271 * @list: a #GtkTargetList
273 * Adds the text targets supported by #GtkSelection to
274 * the target list. The targets are added with both flags
275 * and info being zero.
280 gtk_target_list_add_text_targets (GtkTargetList *list)
282 g_return_if_fail (list != NULL);
286 /* Keep in sync with gtk_selection_data_targets_include_text()
288 gtk_target_list_add (list, utf8_atom, 0, 0);
289 gtk_target_list_add (list, ctext_atom, 0, 0);
290 gtk_target_list_add (list, text_atom, 0, 0);
291 gtk_target_list_add (list, GDK_TARGET_STRING, 0, 0);
292 gtk_target_list_add (list, text_plain_utf8_atom, 0, 0);
293 gtk_target_list_add (list, text_plain_locale_atom, 0, 0);
294 gtk_target_list_add (list, text_plain_atom, 0, 0);
298 gtk_target_list_add_table (GtkTargetList *list,
299 const GtkTargetEntry *targets,
304 for (i=ntargets-1; i >= 0; i--)
306 GtkTargetPair *pair = g_new (GtkTargetPair, 1);
307 pair->target = gdk_atom_intern (targets[i].target, FALSE);
308 pair->flags = targets[i].flags;
309 pair->info = targets[i].info;
311 list->list = g_list_prepend (list->list, pair);
316 gtk_target_list_remove (GtkTargetList *list,
321 g_return_if_fail (list != NULL);
323 tmp_list = list->list;
326 GtkTargetPair *pair = tmp_list->data;
328 if (pair->target == target)
332 list->list = g_list_remove_link (list->list, tmp_list);
333 g_list_free_1 (tmp_list);
338 tmp_list = tmp_list->next;
343 gtk_target_list_find (GtkTargetList *list,
347 GList *tmp_list = list->list;
350 GtkTargetPair *pair = tmp_list->data;
352 if (pair->target == target)
357 tmp_list = tmp_list->next;
364 * gtk_selection_owner_set_for_display:
365 * @display: the #Gdkdisplay where the selection is set
366 * @widget: new selection owner (a #GdkWidget), or %NULL.
367 * @selection: an interned atom representing the selection to claim.
368 * @time_: timestamp with which to claim the selection
370 * Claim ownership of a given selection for a particular widget, or,
371 * if @widget is %NULL, release ownership of the selection.
373 * Return value: TRUE if the operation succeeded
378 gtk_selection_owner_set_for_display (GdkDisplay *display,
384 GtkWidget *old_owner;
385 GtkSelectionInfo *selection_info = NULL;
388 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
389 g_return_val_if_fail (selection != GDK_NONE, FALSE);
390 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
391 g_return_val_if_fail (widget == NULL || gtk_widget_get_display (widget) == display, FALSE);
396 window = widget->window;
398 tmp_list = current_selections;
401 if (((GtkSelectionInfo *)tmp_list->data)->selection == selection)
403 selection_info = tmp_list->data;
407 tmp_list = tmp_list->next;
410 if (gdk_selection_owner_set_for_display (display, window, selection, time, TRUE))
418 old_owner = selection_info->widget;
419 current_selections = g_list_remove_link (current_selections,
421 g_list_free (tmp_list);
422 g_free (selection_info);
427 if (selection_info == NULL)
429 selection_info = g_new (GtkSelectionInfo, 1);
430 selection_info->selection = selection;
431 selection_info->widget = widget;
432 selection_info->time = time;
433 selection_info->display = display;
434 current_selections = g_list_prepend (current_selections,
439 old_owner = selection_info->widget;
440 selection_info->widget = widget;
441 selection_info->time = time;
442 selection_info->display = display;
445 /* If another widget in the application lost the selection,
446 * send it a GDK_SELECTION_CLEAR event.
448 if (old_owner && old_owner != widget)
450 GdkEvent *event = gdk_event_new (GDK_SELECTION_CLEAR);
452 event->selection.window = g_object_ref (old_owner->window);
453 event->selection.selection = selection;
454 event->selection.time = time;
456 gtk_widget_event (old_owner, event);
458 gdk_event_free (event);
467 * gtk_selection_owner_set:
468 * @widget: a #GtkWidget, or %NULL.
469 * @selection: an interned atom representing the selection to claim
470 * @time_: timestamp with which to claim the selection
472 * Claims ownership of a given selection for a particular widget,
473 * or, if @widget is %NULL, release ownership of the selection.
475 * Return value: %TRUE if the operation succeeded
478 gtk_selection_owner_set (GtkWidget *widget,
484 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
485 g_return_val_if_fail (selection != GDK_NONE, FALSE);
488 display = gtk_widget_get_display (widget);
492 g_warning ("gtk_selection_owner_set (NULL,...) is not multihead safe"));
494 display = gdk_display_get_default ();
497 return gtk_selection_owner_set_for_display (display, widget,
501 /*************************************************************
502 * gtk_selection_add_target
503 * Add specified target to list of supported targets
506 * widget: The widget for which this target applies
509 * info: guint to pass to to the selection_get signal
512 *************************************************************/
514 typedef struct _GtkSelectionTargetList GtkSelectionTargetList;
516 struct _GtkSelectionTargetList {
521 static GtkTargetList *
522 gtk_selection_target_list_get (GtkWidget *widget,
525 GtkSelectionTargetList *sellist;
529 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
534 sellist = tmp_list->data;
535 if (sellist->selection == selection)
536 return sellist->list;
537 tmp_list = tmp_list->next;
540 sellist = g_new (GtkSelectionTargetList, 1);
541 sellist->selection = selection;
542 sellist->list = gtk_target_list_new (NULL, 0);
544 lists = g_list_prepend (lists, sellist);
545 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
547 return sellist->list;
551 gtk_selection_target_list_remove (GtkWidget *widget)
553 GtkSelectionTargetList *sellist;
557 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
562 sellist = tmp_list->data;
564 gtk_target_list_unref (sellist->list);
567 tmp_list = tmp_list->next;
571 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, NULL);
575 * gtk_selection_clear_targets:
576 * @widget: a #GtkWidget
577 * @selection: an atom representing a selection
579 * Remove all targets registered for the given selection for the
583 gtk_selection_clear_targets (GtkWidget *widget,
586 GtkSelectionTargetList *sellist;
590 g_return_if_fail (GTK_IS_WIDGET (widget));
591 g_return_if_fail (selection != GDK_NONE);
593 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
598 sellist = tmp_list->data;
599 if (sellist->selection == selection)
601 lists = g_list_delete_link (lists, tmp_list);
602 gtk_target_list_unref (sellist->list);
608 tmp_list = tmp_list->next;
611 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
615 gtk_selection_add_target (GtkWidget *widget,
622 g_return_if_fail (GTK_IS_WIDGET (widget));
623 g_return_if_fail (selection != GDK_NONE);
625 list = gtk_selection_target_list_get (widget, selection);
626 gtk_target_list_add (list, target, 0, info);
630 gtk_selection_add_targets (GtkWidget *widget,
632 const GtkTargetEntry *targets,
637 g_return_if_fail (GTK_IS_WIDGET (widget));
638 g_return_if_fail (selection != GDK_NONE);
639 g_return_if_fail (targets != NULL);
641 list = gtk_selection_target_list_get (widget, selection);
642 gtk_target_list_add_table (list, targets, ntargets);
646 /*************************************************************
647 * gtk_selection_remove_all:
648 * Removes all handlers and unsets ownership of all
649 * selections for a widget. Called when widget is being
655 *************************************************************/
658 gtk_selection_remove_all (GtkWidget *widget)
662 GtkSelectionInfo *selection_info;
664 /* Remove pending requests/incrs for this widget */
666 tmp_list = current_retrievals;
669 next = tmp_list->next;
670 if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget)
672 current_retrievals = g_list_remove_link (current_retrievals,
674 /* structure will be freed in timeout */
675 g_list_free (tmp_list);
680 /* Disclaim ownership of any selections */
682 tmp_list = current_selections;
685 next = tmp_list->next;
686 selection_info = (GtkSelectionInfo *)tmp_list->data;
688 if (selection_info->widget == widget)
690 gdk_selection_owner_set_for_display (selection_info->display,
692 selection_info->selection,
693 GDK_CURRENT_TIME, FALSE);
694 current_selections = g_list_remove_link (current_selections,
696 g_list_free (tmp_list);
697 g_free (selection_info);
703 /* Remove all selection lists */
704 gtk_selection_target_list_remove (widget);
707 /*************************************************************
708 * gtk_selection_convert:
709 * Request the contents of a selection. When received,
710 * a "selection_received" signal will be generated.
713 * widget: The widget which acts as requestor
714 * selection: Which selection to get
715 * target: Form of information desired (e.g., STRING)
716 * time: Time of request (usually of triggering event)
717 * In emergency, you could use GDK_CURRENT_TIME
720 * TRUE if requested succeeded. FALSE if we could not process
721 * request. (e.g., there was already a request in process for
723 *************************************************************/
726 gtk_selection_convert (GtkWidget *widget,
731 GtkRetrievalInfo *info;
733 GdkWindow *owner_window;
736 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
737 g_return_val_if_fail (selection != GDK_NONE, FALSE);
740 gtk_selection_init ();
742 if (!GTK_WIDGET_REALIZED (widget))
743 gtk_widget_realize (widget);
745 /* Check to see if there are already any retrievals in progress for
746 this widget. If we changed GDK to use the selection for the
747 window property in which to store the retrieved information, then
748 we could support multiple retrievals for different selections.
749 This might be useful for DND. */
751 tmp_list = current_retrievals;
754 info = (GtkRetrievalInfo *)tmp_list->data;
755 if (info->widget == widget)
757 tmp_list = tmp_list->next;
760 info = g_new (GtkRetrievalInfo, 1);
762 info->widget = widget;
763 info->selection = selection;
764 info->target = target;
769 /* Check if this process has current owner. If so, call handler
770 procedure directly to avoid deadlocks with INCR. */
772 display = gtk_widget_get_display (widget);
773 owner_window = gdk_selection_owner_get_for_display (display, selection);
775 if (owner_window != NULL)
777 GtkWidget *owner_widget;
778 GtkSelectionData selection_data;
780 selection_data.selection = selection;
781 selection_data.target = target;
782 selection_data.data = NULL;
783 selection_data.length = -1;
784 selection_data.display = display;
786 gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget);
788 if (owner_widget != NULL)
790 gtk_selection_invoke_handler (owner_widget,
794 gtk_selection_retrieval_report (info,
796 selection_data.format,
798 selection_data.length,
801 g_free (selection_data.data);
808 /* Otherwise, we need to go through X */
810 current_retrievals = g_list_append (current_retrievals, info);
811 gdk_selection_convert (widget->window, selection, target, time);
812 g_timeout_add (1000, (GSourceFunc) gtk_selection_retrieval_timeout, info);
817 /*************************************************************
818 * gtk_selection_data_set:
819 * Store new data into a GtkSelectionData object. Should
820 * _only_ by called from a selection handler callback.
821 * Null terminates the stored data.
823 * type: the type of selection data
824 * format: format (number of bits in a unit)
825 * data: pointer to the data (will be copied)
826 * length: length of the data
828 *************************************************************/
831 gtk_selection_data_set (GtkSelectionData *selection_data,
837 if (selection_data->data)
838 g_free (selection_data->data);
840 selection_data->type = type;
841 selection_data->format = format;
845 selection_data->data = g_new (guchar, length+1);
846 memcpy (selection_data->data, data, length);
847 selection_data->data[length] = 0;
851 g_return_if_fail (length <= 0);
854 selection_data->data = NULL;
856 selection_data->data = g_strdup("");
859 selection_data->length = length;
863 selection_set_string (GtkSelectionData *selection_data,
867 gchar *tmp = g_strndup (str, len);
868 gchar *latin1 = gdk_utf8_to_string_target (tmp);
873 gtk_selection_data_set (selection_data,
874 GDK_SELECTION_TYPE_STRING,
875 8, latin1, strlen (latin1));
885 selection_set_compound_text (GtkSelectionData *selection_data,
894 gboolean result = FALSE;
896 tmp = g_strndup (str, len);
897 if (gdk_utf8_to_compound_text_for_display (selection_data->display, tmp,
898 &encoding, &format, &text, &new_length))
900 gtk_selection_data_set (selection_data, encoding, format, text, new_length);
901 gdk_free_compound_text (text);
911 /* Normalize \r and \n into \r\n
914 normalize_to_crlf (const gchar *str,
917 GString *result = g_string_sized_new (len);
918 const gchar *p = str;
923 g_string_append_c (result, '\r');
927 g_string_append_c (result, *p);
930 g_string_append_c (result, '\n');
936 g_string_append_c (result, *p);
940 return g_string_free (result, FALSE);
943 /* Normalize \r and \r\n into \n
946 normalize_to_lf (gchar *str,
949 GString *result = g_string_sized_new (len);
950 const gchar *p = str;
958 g_string_append_c (result, '\n');
964 g_string_append_c (result, *p);
968 return g_string_free (result, FALSE);
972 selection_set_text_plain (GtkSelectionData *selection_data,
976 const gchar *charset = NULL;
978 GError *error = NULL;
980 result = normalize_to_crlf (str, len);
981 if (selection_data->target == text_plain_atom)
983 else if (selection_data->target == text_plain_locale_atom)
984 g_get_charset (&charset);
989 result = g_convert_with_fallback (tmp, -1,
991 NULL, NULL, NULL, &error);
997 g_warning ("Error converting from UTF-8 to %s: %s",
998 charset, error->message);
999 g_error_free (error);
1004 gtk_selection_data_set (selection_data,
1005 selection_data->target,
1006 8, result, strlen (result));
1013 selection_get_text_plain (GtkSelectionData *selection_data)
1015 const gchar *charset = NULL;
1016 gchar *str, *result;
1018 GError *error = NULL;
1020 str = g_strdup (selection_data->data);
1021 len = selection_data->length;
1023 if (selection_data->type == text_plain_atom)
1024 charset = "ISO-8859-1";
1025 else if (selection_data->type == text_plain_locale_atom)
1026 g_get_charset (&charset);
1031 str = g_convert_with_fallback (tmp, len,
1033 NULL, NULL, &len, &error);
1039 g_warning ("Error converting from %s to UTF-8: %s",
1040 charset, error->message);
1041 g_error_free (error);
1047 result = normalize_to_lf (str, len);
1055 * gtk_selection_data_set_text:
1056 * @selection_data: a #GtkSelectionData
1057 * @str: a UTF-8 string
1058 * @len: the length of @str, or -1 if @str is nul-terminated.
1060 * Sets the contents of the selection from a UTF-8 encoded string.
1061 * The string is converted to the form determined by
1062 * @selection_data->target.
1064 * Return value: %TRUE if the selection was successfully set,
1068 gtk_selection_data_set_text (GtkSelectionData *selection_data,
1077 if (selection_data->target == utf8_atom)
1079 gtk_selection_data_set (selection_data,
1081 8, (guchar *)str, len);
1084 else if (selection_data->target == GDK_TARGET_STRING)
1086 return selection_set_string (selection_data, str, len);
1088 else if (selection_data->target == ctext_atom ||
1089 selection_data->target == text_atom)
1091 if (selection_set_compound_text (selection_data, str, len))
1093 else if (selection_data->target == text_atom)
1094 return selection_set_string (selection_data, str, len);
1096 else if (selection_data->target == text_plain_atom ||
1097 selection_data->target == text_plain_utf8_atom ||
1098 selection_data->target == text_plain_locale_atom)
1100 return selection_set_text_plain (selection_data, str, len);
1107 * gtk_selection_data_get_text:
1108 * @selection_data: a #GtkSelectionData
1110 * Gets the contents of the selection data as a UTF-8 string.
1112 * Return value: if the selection data contained a recognized
1113 * text type and it could be converted to UTF-8, a newly allocated
1114 * string containing the converted text, otherwise %NULL.
1115 * If the result is non-%NULL it must be freed with g_free().
1118 gtk_selection_data_get_text (GtkSelectionData *selection_data)
1120 guchar *result = NULL;
1124 if (selection_data->length >= 0 &&
1125 (selection_data->type == GDK_TARGET_STRING ||
1126 selection_data->type == ctext_atom ||
1127 selection_data->type == utf8_atom))
1131 gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1132 selection_data->type,
1133 selection_data->format,
1134 selection_data->data,
1135 selection_data->length,
1140 for (i = 1; i < count; i++)
1144 else if (selection_data->length >= 0 &&
1145 (selection_data->type == text_plain_atom ||
1146 selection_data->type == text_plain_utf8_atom ||
1147 selection_data->type == text_plain_locale_atom))
1149 result = selection_get_text_plain (selection_data);
1156 * gtk_selection_data_get_targets:
1157 * @selection_data: a #GtkSelectionData object
1158 * @targets: location to store an array of targets. The result
1159 * stored here must be freed with g_free().
1160 * @n_atoms: location to store number of items in @targets.
1162 * Gets the contents of @selection_data as an array of targets.
1163 * This can be used to interpret the results of getting
1164 * the standard TARGETS target that is always supplied for
1167 * Return value: %TRUE if @selection_data contains a valid
1168 * array of targets, otherwise %FALSE.
1171 gtk_selection_data_get_targets (GtkSelectionData *selection_data,
1175 if (selection_data->length >= 0 &&
1176 selection_data->format == 32 &&
1177 selection_data->type == GDK_SELECTION_TYPE_ATOM)
1180 *targets = g_memdup (selection_data->data, selection_data->length);
1182 *n_atoms = selection_data->length / sizeof (GdkAtom);
1198 * gtk_selection_data_targets_include_text:
1199 * @selection_data: a #GtkSelectionData object
1201 * Given a #GtkSelectionData object holding a list of targets,
1202 * determines if any of the targets in @targets can be used to
1205 * Return value: %TRUE if @selection_data holds a list of targets,
1206 * and a suitable target for text is included, otherwise %FALSE.
1209 gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
1214 gboolean result = FALSE;
1218 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1220 for (i=0; i < n_targets; i++)
1222 if (targets[i] == utf8_atom ||
1223 targets[i] == text_atom ||
1224 targets[i] == GDK_TARGET_STRING ||
1225 targets[i] == ctext_atom ||
1226 targets[i] == text_plain_atom ||
1227 targets[i] == text_plain_utf8_atom ||
1228 targets[i] == text_plain_locale_atom)
1238 /*************************************************************
1239 * gtk_selection_init:
1240 * Initialize local variables
1244 *************************************************************/
1247 gtk_selection_init (void)
1249 gtk_selection_atoms[INCR] = gdk_atom_intern ("INCR", FALSE);
1250 gtk_selection_atoms[MULTIPLE] = gdk_atom_intern ("MULTIPLE", FALSE);
1251 gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern ("TIMESTAMP", FALSE);
1252 gtk_selection_atoms[TARGETS] = gdk_atom_intern ("TARGETS", FALSE);
1258 * gtk_selection_clear:
1259 * @widget: a #GtkWidget
1262 * The default handler for the GtkWidget::selection_clear_event
1265 * Return value: %TRUE if the event was handled, otherwise false
1269 * Deprecated: Instead of calling this function, chain up from
1270 * your selection_clear_event handler. Calling this function
1271 * from any other context is illegal.
1274 gtk_selection_clear (GtkWidget *widget,
1275 GdkEventSelection *event)
1277 /* Note that we filter clear events in gdkselection-x11.c, so
1278 * that we only will get here if the clear event actually
1279 * represents a change that we didn't do ourself.
1282 GtkSelectionInfo *selection_info = NULL;
1284 tmp_list = current_selections;
1287 selection_info = (GtkSelectionInfo *)tmp_list->data;
1289 if ((selection_info->selection == event->selection) &&
1290 (selection_info->widget == widget))
1293 tmp_list = tmp_list->next;
1298 current_selections = g_list_remove_link (current_selections, tmp_list);
1299 g_list_free (tmp_list);
1300 g_free (selection_info);
1307 /*************************************************************
1308 * _gtk_selection_request:
1309 * Handler for "selection_request_event"
1314 *************************************************************/
1317 _gtk_selection_request (GtkWidget *widget,
1318 GdkEventSelection *event)
1320 GdkDisplay *display = gtk_widget_get_display (widget);
1324 gulong selection_max_size;
1327 gtk_selection_init ();
1329 selection_max_size = GTK_SELECTION_MAX_SIZE (display);
1331 /* Check if we own selection */
1333 tmp_list = current_selections;
1336 GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data;
1338 if ((selection_info->selection == event->selection) &&
1339 (selection_info->widget == widget))
1342 tmp_list = tmp_list->next;
1345 if (tmp_list == NULL)
1348 info = g_new (GtkIncrInfo, 1);
1350 g_object_ref (widget);
1352 info->selection = event->selection;
1353 info->num_incrs = 0;
1355 /* Create GdkWindow structure for the requestor */
1357 info->requestor = gdk_window_lookup_for_display (display,
1359 if (!info->requestor)
1360 info->requestor = gdk_window_foreign_new_for_display (display,
1363 /* Determine conversions we need to perform */
1365 if (event->target == gtk_selection_atoms[MULTIPLE])
1374 gdk_error_trap_push ();
1375 if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */
1376 0, selection_max_size, FALSE,
1377 &type, &format, &length, &mult_atoms))
1379 gdk_selection_send_notify_for_display (display,
1385 g_free (mult_atoms);
1389 gdk_error_trap_pop ();
1391 /* This is annoying; the ICCCM doesn't specify the property type
1392 * used for the property contents, so the autoconversion for
1393 * ATOM / ATOM_PAIR in GDK doesn't work properly.
1395 #ifdef GDK_WINDOWING_X11
1396 if (type != GDK_SELECTION_TYPE_ATOM &&
1397 type != gdk_atom_intern ("ATOM_PAIR", FALSE))
1399 info->num_conversions = length / (2*sizeof (glong));
1400 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1402 for (i=0; i<info->num_conversions; i++)
1404 info->conversions[i].target = gdk_x11_xatom_to_atom_for_display (display,
1405 ((glong *)mult_atoms)[2*i]);
1406 info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display,
1407 ((glong *)mult_atoms)[2*i + 1]);
1413 info->num_conversions = length / (2*sizeof (GdkAtom));
1414 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1416 for (i=0; i<info->num_conversions; i++)
1418 info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
1419 info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
1423 else /* only a single conversion */
1425 info->conversions = g_new (GtkIncrConversion, 1);
1426 info->num_conversions = 1;
1427 info->conversions[0].target = event->target;
1428 info->conversions[0].property = event->property;
1431 /* Loop through conversions and determine which of these are big
1432 enough to require doing them via INCR */
1433 for (i=0; i<info->num_conversions; i++)
1435 GtkSelectionData data;
1438 data.selection = event->selection;
1439 data.target = info->conversions[i].target;
1442 data.display = gtk_widget_get_display (widget);
1444 #ifdef DEBUG_SELECTION
1445 g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
1447 info->conversions[i].target,
1448 gdk_atom_name (info->conversions[i].target),
1449 event->requestor, info->conversions[i].property);
1452 gtk_selection_invoke_handler (widget, &data, event->time);
1454 if (data.length < 0)
1456 info->conversions[i].property = GDK_NONE;
1460 g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
1462 items = data.length / gtk_selection_bytes_per_item (data.format);
1464 if (data.length > selection_max_size)
1466 /* Sending via INCR */
1467 #ifdef DEBUG_SELECTION
1468 g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n",
1469 data.length, selection_max_size);
1472 info->conversions[i].offset = 0;
1473 info->conversions[i].data = data;
1476 gdk_property_change (info->requestor,
1477 info->conversions[i].property,
1478 gtk_selection_atoms[INCR],
1480 GDK_PROP_MODE_REPLACE,
1481 (guchar *)&items, 1);
1485 info->conversions[i].offset = -1;
1487 gdk_property_change (info->requestor,
1488 info->conversions[i].property,
1491 GDK_PROP_MODE_REPLACE,
1498 /* If we have some INCR's, we need to send the rest of the data in
1501 if (info->num_incrs > 0)
1503 /* FIXME: this could be dangerous if window doesn't still
1506 #ifdef DEBUG_SELECTION
1507 g_message ("Starting INCR...");
1510 gdk_window_set_events (info->requestor,
1511 gdk_window_get_events (info->requestor) |
1512 GDK_PROPERTY_CHANGE_MASK);
1513 current_incrs = g_list_append (current_incrs, info);
1514 g_timeout_add (1000, (GSourceFunc) gtk_selection_incr_timeout, info);
1517 /* If it was a MULTIPLE request, set the property to indicate which
1518 conversions succeeded */
1519 if (event->target == gtk_selection_atoms[MULTIPLE])
1521 GdkAtom *mult_atoms = g_new (GdkAtom, 2 * info->num_conversions);
1522 for (i = 0; i < info->num_conversions; i++)
1524 mult_atoms[2*i] = info->conversions[i].target;
1525 mult_atoms[2*i+1] = info->conversions[i].property;
1528 gdk_property_change (info->requestor, event->property,
1529 gdk_atom_intern ("ATOM_PAIR", FALSE), 32,
1530 GDK_PROP_MODE_REPLACE,
1531 (guchar *)mult_atoms, 2*info->num_conversions);
1532 g_free (mult_atoms);
1535 if (info->num_conversions == 1 &&
1536 info->conversions[0].property == GDK_NONE)
1538 /* Reject the entire conversion */
1539 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1548 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1556 if (info->num_incrs == 0)
1558 g_free (info->conversions);
1562 g_object_unref (widget);
1567 /*************************************************************
1568 * _gtk_selection_incr_event:
1569 * Called whenever an PropertyNotify event occurs for an
1570 * GdkWindow with user_data == NULL. These will be notifications
1571 * that a window we are sending the selection to via the
1572 * INCR protocol has deleted a property and is ready for
1576 * window: the requestor window
1577 * event: the property event structure
1580 *************************************************************/
1583 _gtk_selection_incr_event (GdkWindow *window,
1584 GdkEventProperty *event)
1587 GtkIncrInfo *info = NULL;
1590 gulong selection_max_size;
1594 if (event->state != GDK_PROPERTY_DELETE)
1597 #ifdef DEBUG_SELECTION
1598 g_message ("PropertyDelete, property %ld", event->atom);
1601 selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window));
1603 /* Now find the appropriate ongoing INCR */
1604 tmp_list = current_incrs;
1607 info = (GtkIncrInfo *)tmp_list->data;
1608 if (info->requestor == event->window)
1611 tmp_list = tmp_list->next;
1614 if (tmp_list == NULL)
1617 /* Find out which target this is for */
1618 for (i=0; i<info->num_conversions; i++)
1620 if (info->conversions[i].property == event->atom &&
1621 info->conversions[i].offset != -1)
1625 info->idle_time = 0;
1627 if (info->conversions[i].offset == -2) /* only the last 0-length
1635 num_bytes = info->conversions[i].data.length -
1636 info->conversions[i].offset;
1637 buffer = info->conversions[i].data.data +
1638 info->conversions[i].offset;
1640 if (num_bytes > selection_max_size)
1642 num_bytes = selection_max_size;
1643 info->conversions[i].offset += selection_max_size;
1646 info->conversions[i].offset = -2;
1648 #ifdef DEBUG_SELECTION
1649 g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
1650 num_bytes, info->conversions[i].offset,
1651 GDK_WINDOW_XWINDOW(info->requestor), event->atom);
1654 bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
1655 gdk_property_change (info->requestor, event->atom,
1656 info->conversions[i].data.type,
1657 info->conversions[i].data.format,
1658 GDK_PROP_MODE_REPLACE,
1660 num_bytes / bytes_per_item);
1662 if (info->conversions[i].offset == -2)
1664 g_free (info->conversions[i].data.data);
1665 info->conversions[i].data.data = NULL;
1671 info->conversions[i].offset = -1;
1676 /* Check if we're finished with all the targets */
1678 if (info->num_incrs == 0)
1680 current_incrs = g_list_remove_link (current_incrs, tmp_list);
1681 g_list_free (tmp_list);
1682 /* Let the timeout free it */
1688 /*************************************************************
1689 * gtk_selection_incr_timeout:
1690 * Timeout callback for the sending portion of the INCR
1693 * info: Information about this incr
1695 *************************************************************/
1698 gtk_selection_incr_timeout (GtkIncrInfo *info)
1703 GDK_THREADS_ENTER ();
1705 /* Determine if retrieval has finished by checking if it still in
1706 list of pending retrievals */
1708 tmp_list = current_incrs;
1711 if (info == (GtkIncrInfo *)tmp_list->data)
1713 tmp_list = tmp_list->next;
1716 /* If retrieval is finished */
1717 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
1719 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
1721 current_incrs = g_list_remove_link (current_incrs, tmp_list);
1722 g_list_free (tmp_list);
1725 g_free (info->conversions);
1726 /* FIXME: we should check if requestor window is still in use,
1727 and if not, remove it? */
1731 retval = FALSE; /* remove timeout */
1737 retval = TRUE; /* timeout will happen again */
1740 GDK_THREADS_LEAVE ();
1745 /*************************************************************
1746 * _gtk_selection_notify:
1747 * Handler for "selection_notify_event" signals on windows
1748 * where a retrieval is currently in process. The selection
1749 * owner has responded to our conversion request.
1751 * widget: Widget getting signal
1752 * event: Selection event structure
1753 * info: Information about this retrieval
1755 * was event handled?
1756 *************************************************************/
1759 _gtk_selection_notify (GtkWidget *widget,
1760 GdkEventSelection *event)
1763 GtkRetrievalInfo *info = NULL;
1764 guchar *buffer = NULL;
1769 #ifdef DEBUG_SELECTION
1770 g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
1771 event->selection, event->target, event->property);
1774 tmp_list = current_retrievals;
1777 info = (GtkRetrievalInfo *)tmp_list->data;
1778 if (info->widget == widget && info->selection == event->selection)
1780 tmp_list = tmp_list->next;
1783 if (!tmp_list) /* no retrieval in progress */
1786 if (event->property != GDK_NONE)
1787 length = gdk_selection_property_get (widget->window, &buffer,
1790 length = 0; /* silence gcc */
1792 if (event->property == GDK_NONE || buffer == NULL)
1794 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1795 g_list_free (tmp_list);
1796 /* structure will be freed in timeout */
1797 gtk_selection_retrieval_report (info,
1798 GDK_NONE, 0, NULL, -1, event->time);
1803 if (type == gtk_selection_atoms[INCR])
1805 /* The remainder of the selection will come through PropertyNotify
1808 info->notify_time = event->time;
1809 info->idle_time = 0;
1810 info->offset = 0; /* Mark as OK to proceed */
1811 gdk_window_set_events (widget->window,
1812 gdk_window_get_events (widget->window)
1813 | GDK_PROPERTY_CHANGE_MASK);
1817 /* We don't delete the info structure - that will happen in timeout */
1818 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1819 g_list_free (tmp_list);
1821 info->offset = length;
1822 gtk_selection_retrieval_report (info,
1824 buffer, length, event->time);
1827 gdk_property_delete (widget->window, event->property);
1834 /*************************************************************
1835 * _gtk_selection_property_notify:
1836 * Handler for "property_notify_event" signals on windows
1837 * where a retrieval is currently in process. The selection
1838 * owner has added more data.
1840 * widget: Widget getting signal
1841 * event: Property event structure
1842 * info: Information about this retrieval
1844 * was event handled?
1845 *************************************************************/
1848 _gtk_selection_property_notify (GtkWidget *widget,
1849 GdkEventProperty *event)
1852 GtkRetrievalInfo *info = NULL;
1858 g_return_val_if_fail (widget != NULL, FALSE);
1859 g_return_val_if_fail (event != NULL, FALSE);
1861 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
1862 if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */
1863 (event->atom != gdk_atom_intern ("GDK_SELECTION", FALSE))) /* not the right property */
1867 #ifdef DEBUG_SELECTION
1868 g_message ("PropertyNewValue, property %ld",
1872 tmp_list = current_retrievals;
1875 info = (GtkRetrievalInfo *)tmp_list->data;
1876 if (info->widget == widget)
1878 tmp_list = tmp_list->next;
1881 if (!tmp_list) /* No retrieval in progress */
1884 if (info->offset < 0) /* We haven't got the SelectionNotify
1885 for this retrieval yet */
1888 info->idle_time = 0;
1890 length = gdk_selection_property_get (widget->window, &new_buffer,
1892 gdk_property_delete (widget->window, event->atom);
1894 /* We could do a lot better efficiency-wise by paying attention to
1895 what length was sent in the initial INCR transaction, instead of
1896 doing memory allocation at every step. But its only guaranteed to
1897 be a _lower bound_ (pretty useless!) */
1899 if (length == 0 || type == GDK_NONE) /* final zero length portion */
1901 /* Info structure will be freed in timeout */
1902 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1903 g_list_free (tmp_list);
1904 gtk_selection_retrieval_report (info,
1906 (type == GDK_NONE) ? NULL : info->buffer,
1907 (type == GDK_NONE) ? -1 : info->offset,
1910 else /* append on newly arrived data */
1914 #ifdef DEBUG_SELECTION
1915 g_message ("Start - Adding %d bytes at offset 0",
1918 info->buffer = new_buffer;
1919 info->offset = length;
1924 #ifdef DEBUG_SELECTION
1925 g_message ("Appending %d bytes at offset %d",
1926 length,info->offset);
1928 /* We copy length+1 bytes to preserve guaranteed null termination */
1929 info->buffer = g_realloc (info->buffer, info->offset+length+1);
1930 memcpy (info->buffer + info->offset, new_buffer, length+1);
1931 info->offset += length;
1932 g_free (new_buffer);
1939 /*************************************************************
1940 * gtk_selection_retrieval_timeout:
1941 * Timeout callback while receiving a selection.
1943 * info: Information about this retrieval
1945 *************************************************************/
1948 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
1953 GDK_THREADS_ENTER ();
1955 /* Determine if retrieval has finished by checking if it still in
1956 list of pending retrievals */
1958 tmp_list = current_retrievals;
1961 if (info == (GtkRetrievalInfo *)tmp_list->data)
1963 tmp_list = tmp_list->next;
1966 /* If retrieval is finished */
1967 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
1969 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
1971 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1972 g_list_free (tmp_list);
1973 gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
1976 g_free (info->buffer);
1979 retval = FALSE; /* remove timeout */
1985 retval = TRUE; /* timeout will happen again */
1988 GDK_THREADS_LEAVE ();
1993 /*************************************************************
1994 * gtk_selection_retrieval_report:
1995 * Emits a "selection_received" signal.
1997 * info: information about the retrieval that completed
1998 * buffer: buffer containing data (NULL => errror)
1999 * time: timestamp for data in buffer
2001 *************************************************************/
2004 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
2005 GdkAtom type, gint format,
2006 guchar *buffer, gint length,
2009 GtkSelectionData data;
2011 data.selection = info->selection;
2012 data.target = info->target;
2014 data.format = format;
2016 data.length = length;
2018 data.display = gtk_widget_get_display (info->widget);
2020 g_signal_emit_by_name (info->widget,
2021 "selection_received",
2025 /*************************************************************
2026 * gtk_selection_invoke_handler:
2027 * Finds and invokes handler for specified
2028 * widget/selection/target combination, calls
2029 * gtk_selection_default_handler if none exists.
2032 * widget: selection owner
2033 * data: selection data [INOUT]
2034 * time: time from requeset
2037 * Number of bytes written to buffer, -1 if error
2038 *************************************************************/
2041 gtk_selection_invoke_handler (GtkWidget *widget,
2042 GtkSelectionData *data,
2045 GtkTargetList *target_list;
2049 g_return_if_fail (widget != NULL);
2051 target_list = gtk_selection_target_list_get (widget, data->selection);
2053 gtk_target_list_find (target_list, data->target, &info))
2055 g_signal_emit_by_name (widget,
2061 gtk_selection_default_handler (widget, data);
2064 /*************************************************************
2065 * gtk_selection_default_handler:
2066 * Handles some default targets that exist for any widget
2067 * If it can't fit results into buffer, returns -1. This
2068 * won't happen in any conceivable case, since it would
2069 * require 1000 selection targets!
2072 * widget: selection owner
2073 * data: selection data [INOUT]
2075 *************************************************************/
2078 gtk_selection_default_handler (GtkWidget *widget,
2079 GtkSelectionData *data)
2081 if (data->target == gtk_selection_atoms[TIMESTAMP])
2083 /* Time which was used to obtain selection */
2085 GtkSelectionInfo *selection_info;
2087 tmp_list = current_selections;
2090 selection_info = (GtkSelectionInfo *)tmp_list->data;
2091 if ((selection_info->widget == widget) &&
2092 (selection_info->selection == data->selection))
2094 gulong time = selection_info->time;
2096 gtk_selection_data_set (data,
2097 GDK_SELECTION_TYPE_INTEGER,
2104 tmp_list = tmp_list->next;
2109 else if (data->target == gtk_selection_atoms[TARGETS])
2111 /* List of all targets supported for this widget/selection pair */
2115 GtkTargetList *target_list;
2116 GtkTargetPair *pair;
2118 target_list = gtk_selection_target_list_get (widget,
2120 count = g_list_length (target_list->list) + 3;
2122 data->type = GDK_SELECTION_TYPE_ATOM;
2124 data->length = count * sizeof (GdkAtom);
2126 /* selection data is always terminated by a trailing \0
2128 p = g_malloc (data->length + 1);
2129 data->data = (guchar *)p;
2130 data->data[data->length] = '\0';
2132 *p++ = gtk_selection_atoms[TIMESTAMP];
2133 *p++ = gtk_selection_atoms[TARGETS];
2134 *p++ = gtk_selection_atoms[MULTIPLE];
2136 tmp_list = target_list->list;
2139 pair = (GtkTargetPair *)tmp_list->data;
2140 *p++ = pair->target;
2142 tmp_list = tmp_list->next;
2153 gtk_selection_data_copy (GtkSelectionData *selection_data)
2155 GtkSelectionData *new_data;
2157 g_return_val_if_fail (selection_data != NULL, NULL);
2159 new_data = g_new (GtkSelectionData, 1);
2160 *new_data = *selection_data;
2162 if (selection_data->data)
2164 new_data->data = g_malloc (selection_data->length + 1);
2165 memcpy (new_data->data, selection_data->data, selection_data->length + 1);
2172 gtk_selection_data_free (GtkSelectionData *data)
2174 g_return_if_fail (data != NULL);
2177 g_free (data->data);
2183 gtk_selection_data_get_type (void)
2185 static GType our_type = 0;
2188 our_type = g_boxed_type_register_static ("GtkSelectionData",
2189 (GBoxedCopyFunc) gtk_selection_data_copy,
2190 (GBoxedFreeFunc) gtk_selection_data_free);
2196 gtk_selection_bytes_per_item (gint format)
2201 return sizeof (char);
2204 return sizeof (short);
2207 return sizeof (long);
2210 g_assert_not_reached();