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/.
60 #include "gtkselection.h"
61 #include "gdk-pixbuf/gdk-pixbuf.h"
63 #ifdef GDK_WINDOWING_X11
67 #ifdef GDK_WINDOWING_WIN32
68 #include "win32/gdkwin32.h"
73 #undef DEBUG_SELECTION
75 /* Maximum size of a sent chunk, in bytes. Also the default size of
77 #ifdef GDK_WINDOWING_X11
78 #define GTK_SELECTION_MAX_SIZE(display) \
80 XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0 \
81 ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100 \
82 : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
84 /* No chunks on Win32 */
85 #define GTK_SELECTION_MAX_SIZE(display) G_MAXINT
88 #define IDLE_ABORT_TIME 30
98 typedef struct _GtkSelectionInfo GtkSelectionInfo;
99 typedef struct _GtkIncrConversion GtkIncrConversion;
100 typedef struct _GtkIncrInfo GtkIncrInfo;
101 typedef struct _GtkRetrievalInfo GtkRetrievalInfo;
103 struct _GtkSelectionInfo
106 GtkWidget *widget; /* widget that owns selection */
107 guint32 time; /* time used to acquire selection */
108 GdkDisplay *display; /* needed in gtk_selection_remove_all */
111 struct _GtkIncrConversion
113 GdkAtom target; /* Requested target */
114 GdkAtom property; /* Property to store in */
115 GtkSelectionData data; /* The data being supplied */
116 gint offset; /* Current offset in sent selection.
118 * -2 => Only the final (empty) portion
124 GdkWindow *requestor; /* Requestor window - we create a GdkWindow
125 so we can receive events */
126 GdkAtom selection; /* Selection we're sending */
128 GtkIncrConversion *conversions; /* Information about requested conversions -
129 * With MULTIPLE requests (benighted 1980's
130 * hardware idea), there can be more than
132 gint num_conversions;
133 gint num_incrs; /* number of remaining INCR style transactions */
138 struct _GtkRetrievalInfo
141 GdkAtom selection; /* Selection being retrieved. */
142 GdkAtom target; /* Form of selection that we requested */
143 guint32 idle_time; /* Number of seconds since we last heard
144 from selection owner */
145 guchar *buffer; /* Buffer in which to accumulate results */
146 gint offset; /* Current offset in buffer, -1 indicates
148 guint32 notify_time; /* Timestamp from SelectionNotify */
151 /* Local Functions */
152 static void gtk_selection_init (void);
153 static gint gtk_selection_incr_timeout (GtkIncrInfo *info);
154 static gint gtk_selection_retrieval_timeout (GtkRetrievalInfo *info);
155 static void gtk_selection_retrieval_report (GtkRetrievalInfo *info,
161 static void gtk_selection_invoke_handler (GtkWidget *widget,
162 GtkSelectionData *data,
164 static void gtk_selection_default_handler (GtkWidget *widget,
165 GtkSelectionData *data);
166 static int gtk_selection_bytes_per_item (gint format);
169 static gint initialize = TRUE;
170 static GList *current_retrievals = NULL;
171 static GList *current_incrs = NULL;
172 static GList *current_selections = NULL;
174 static GdkAtom gtk_selection_atoms[LAST_ATOM];
175 static const char gtk_selection_handler_key[] = "gtk-selection-handlers";
187 * gtk_target_list_new:
188 * @targets: Pointer to an array of #GtkTargetEntry
189 * @ntargets: number of entries in @targets.
191 * Creates a new #GtkTargetList from an array of #GtkTargetEntry.
193 * Return value: the new #GtkTargetList.
196 gtk_target_list_new (const GtkTargetEntry *targets,
199 GtkTargetList *result = g_new (GtkTargetList, 1);
201 result->ref_count = 1;
204 gtk_target_list_add_table (result, targets, ntargets);
210 * gtk_target_list_ref:
211 * @list: a #GtkTargetList
213 * Increases the reference count of a #GtkTargetList by one.
217 gtk_target_list_ref (GtkTargetList *list)
219 g_return_if_fail (list != NULL);
225 * gtk_target_list_unref:
226 * @list: a #GtkTargetList
228 * Decreases the reference count of a #GtkTargetList by one.
229 * If the resulting reference count is zero, frees the list.
232 gtk_target_list_unref (GtkTargetList *list)
234 g_return_if_fail (list != NULL);
235 g_return_if_fail (list->ref_count > 0);
238 if (list->ref_count == 0)
240 GList *tmp_list = list->list;
243 GtkTargetPair *pair = tmp_list->data;
246 tmp_list = tmp_list->next;
249 g_list_free (list->list);
255 * gtk_target_list_add:
256 * @list: a #GtkTargetList
257 * @target: the interned atom representing the target
258 * @flags: the flags for this target
259 * @info: an ID that will be passed back to the application
261 * Appends another target to a #GtkTargetList.
264 gtk_target_list_add (GtkTargetList *list,
271 g_return_if_fail (list != NULL);
273 pair = g_new (GtkTargetPair, 1);
274 pair->target = target;
278 list->list = g_list_append (list->list, pair);
281 static GdkAtom utf8_atom;
282 static GdkAtom text_atom;
283 static GdkAtom ctext_atom;
284 static GdkAtom text_plain_atom;
285 static GdkAtom text_plain_utf8_atom;
286 static GdkAtom text_plain_locale_atom;
287 static GdkAtom text_uri_list_atom;
293 const gchar *charset;
297 utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
298 text_atom = gdk_atom_intern ("TEXT", FALSE);
299 ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
300 text_plain_atom = gdk_atom_intern ("text/plain", FALSE);
301 text_plain_utf8_atom = gdk_atom_intern ("text/plain;charset=utf-8", FALSE);
302 g_get_charset (&charset);
303 tmp = g_strdup_printf ("text/plain;charset=%s", charset);
304 text_plain_locale_atom = gdk_atom_intern (tmp, FALSE);
307 text_uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE);
312 * gtk_target_list_add_text_targets:
313 * @list: a #GtkTargetList
314 * @info: an ID that will be passed back to the application
316 * Appends the text targets supported by #GtkSelection to
317 * the target list. All targets are added with the same @info.
322 gtk_target_list_add_text_targets (GtkTargetList *list,
325 g_return_if_fail (list != NULL);
329 /* Keep in sync with gtk_selection_data_targets_include_text()
331 gtk_target_list_add (list, utf8_atom, 0, info);
332 gtk_target_list_add (list, ctext_atom, 0, info);
333 gtk_target_list_add (list, text_atom, 0, info);
334 gtk_target_list_add (list, GDK_TARGET_STRING, 0, info);
335 gtk_target_list_add (list, text_plain_utf8_atom, 0, info);
336 gtk_target_list_add (list, text_plain_locale_atom, 0, info);
337 gtk_target_list_add (list, text_plain_atom, 0, info);
341 * gtk_target_list_add_image_targets:
342 * @list: a #GtkTargetList
343 * @info: an ID that will be passed back to the application
344 * @writable: whether to add only targets for which GTK+ knows
345 * how to convert a pixbuf into the format
347 * Appends the image targets supported by #GtkSelection to
348 * the target list. All targets are added with the same @info.
353 gtk_target_list_add_image_targets (GtkTargetList *list,
361 g_return_if_fail (list != NULL);
363 formats = gdk_pixbuf_get_formats ();
365 /* Make sure png comes first */
366 for (f = formats; f; f = f->next)
368 GdkPixbufFormat *fmt = f->data;
370 if (strcmp (gdk_pixbuf_format_get_name (fmt), "png") == 0)
372 formats = g_slist_delete_link (formats, f);
373 formats = g_slist_prepend (formats, fmt);
380 for (f = formats; f; f = f->next)
382 GdkPixbufFormat *fmt = f->data;
384 if (writable && !gdk_pixbuf_format_is_writable (fmt))
387 mimes = gdk_pixbuf_format_get_mime_types (fmt);
388 for (m = mimes; *m; m++)
390 atom = gdk_atom_intern (*m, FALSE);
391 gtk_target_list_add (list, atom, 0, info);
396 g_slist_free (formats);
400 * gtk_target_list_add_uri_targets:
401 * @list: a #GtkTargetList
402 * @info: an ID that will be passed back to the application
404 * Appends the URI targets supported by #GtkSelection to
405 * the target list. All targets are added with the same @info.
410 gtk_target_list_add_uri_targets (GtkTargetList *list,
413 g_return_if_fail (list != NULL);
417 gtk_target_list_add (list, text_uri_list_atom, 0, info);
421 * gtk_target_list_add_table:
422 * @list: a #GtkTargetList
423 * @targets: the table of #GtkTargetEntry
424 * @ntargets: number of targets in the table
426 * Prepends a table of #GtkTargetEntry to a target list.
429 gtk_target_list_add_table (GtkTargetList *list,
430 const GtkTargetEntry *targets,
435 for (i=ntargets-1; i >= 0; i--)
437 GtkTargetPair *pair = g_new (GtkTargetPair, 1);
438 pair->target = gdk_atom_intern (targets[i].target, FALSE);
439 pair->flags = targets[i].flags;
440 pair->info = targets[i].info;
442 list->list = g_list_prepend (list->list, pair);
447 * gtk_target_list_remove:
448 * @list: a #GtkTargetList
449 * @target: the interned atom representing the target
451 * Removes a target from a target list.
454 gtk_target_list_remove (GtkTargetList *list,
459 g_return_if_fail (list != NULL);
461 tmp_list = list->list;
464 GtkTargetPair *pair = tmp_list->data;
466 if (pair->target == target)
470 list->list = g_list_remove_link (list->list, tmp_list);
471 g_list_free_1 (tmp_list);
476 tmp_list = tmp_list->next;
481 * gtk_target_list_find:
482 * @list: a #GtkTargetList
483 * @target: an interned atom representing the target to search for
484 * @info: a pointer to the location to store application info for target
486 * Looks up a given target in a #GtkTargetList.
488 * Return value: %TRUE if the target was found, otherwise %FALSE
491 gtk_target_list_find (GtkTargetList *list,
495 GList *tmp_list = list->list;
498 GtkTargetPair *pair = tmp_list->data;
500 if (pair->target == target)
505 tmp_list = tmp_list->next;
512 * gtk_selection_owner_set_for_display:
513 * @display: the #Gdkdisplay where the selection is set
514 * @widget: new selection owner (a #GdkWidget), or %NULL.
515 * @selection: an interned atom representing the selection to claim.
516 * @time_: timestamp with which to claim the selection
518 * Claim ownership of a given selection for a particular widget, or,
519 * if @widget is %NULL, release ownership of the selection.
521 * Return value: TRUE if the operation succeeded
526 gtk_selection_owner_set_for_display (GdkDisplay *display,
532 GtkWidget *old_owner;
533 GtkSelectionInfo *selection_info = NULL;
536 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
537 g_return_val_if_fail (selection != GDK_NONE, FALSE);
538 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
539 g_return_val_if_fail (widget == NULL || gtk_widget_get_display (widget) == display, FALSE);
544 window = widget->window;
546 tmp_list = current_selections;
549 if (((GtkSelectionInfo *)tmp_list->data)->selection == selection)
551 selection_info = tmp_list->data;
555 tmp_list = tmp_list->next;
558 if (gdk_selection_owner_set_for_display (display, window, selection, time, TRUE))
566 old_owner = selection_info->widget;
567 current_selections = g_list_remove_link (current_selections,
569 g_list_free (tmp_list);
570 g_free (selection_info);
575 if (selection_info == NULL)
577 selection_info = g_new (GtkSelectionInfo, 1);
578 selection_info->selection = selection;
579 selection_info->widget = widget;
580 selection_info->time = time;
581 selection_info->display = display;
582 current_selections = g_list_prepend (current_selections,
587 old_owner = selection_info->widget;
588 selection_info->widget = widget;
589 selection_info->time = time;
590 selection_info->display = display;
593 /* If another widget in the application lost the selection,
594 * send it a GDK_SELECTION_CLEAR event.
596 if (old_owner && old_owner != widget)
598 GdkEvent *event = gdk_event_new (GDK_SELECTION_CLEAR);
600 event->selection.window = g_object_ref (old_owner->window);
601 event->selection.selection = selection;
602 event->selection.time = time;
604 gtk_widget_event (old_owner, event);
606 gdk_event_free (event);
615 * gtk_selection_owner_set:
616 * @widget: a #GtkWidget, or %NULL.
617 * @selection: an interned atom representing the selection to claim
618 * @time_: timestamp with which to claim the selection
620 * Claims ownership of a given selection for a particular widget,
621 * or, if @widget is %NULL, release ownership of the selection.
623 * Return value: %TRUE if the operation succeeded
626 gtk_selection_owner_set (GtkWidget *widget,
632 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
633 g_return_val_if_fail (selection != GDK_NONE, FALSE);
636 display = gtk_widget_get_display (widget);
640 g_warning ("gtk_selection_owner_set (NULL,...) is not multihead safe"));
642 display = gdk_display_get_default ();
645 return gtk_selection_owner_set_for_display (display, widget,
649 typedef struct _GtkSelectionTargetList GtkSelectionTargetList;
651 struct _GtkSelectionTargetList {
656 static GtkTargetList *
657 gtk_selection_target_list_get (GtkWidget *widget,
660 GtkSelectionTargetList *sellist;
664 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
669 sellist = tmp_list->data;
670 if (sellist->selection == selection)
671 return sellist->list;
672 tmp_list = tmp_list->next;
675 sellist = g_new (GtkSelectionTargetList, 1);
676 sellist->selection = selection;
677 sellist->list = gtk_target_list_new (NULL, 0);
679 lists = g_list_prepend (lists, sellist);
680 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
682 return sellist->list;
686 gtk_selection_target_list_remove (GtkWidget *widget)
688 GtkSelectionTargetList *sellist;
692 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
697 sellist = tmp_list->data;
699 gtk_target_list_unref (sellist->list);
702 tmp_list = tmp_list->next;
706 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, NULL);
710 * gtk_selection_clear_targets:
711 * @widget: a #GtkWidget
712 * @selection: an atom representing a selection
714 * Remove all targets registered for the given selection for the
718 gtk_selection_clear_targets (GtkWidget *widget,
721 GtkSelectionTargetList *sellist;
725 g_return_if_fail (GTK_IS_WIDGET (widget));
726 g_return_if_fail (selection != GDK_NONE);
728 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
733 sellist = tmp_list->data;
734 if (sellist->selection == selection)
736 lists = g_list_delete_link (lists, tmp_list);
737 gtk_target_list_unref (sellist->list);
743 tmp_list = tmp_list->next;
746 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
750 * gtk_selection_add_target:
751 * @widget: a #GtkTarget
752 * @selection: the selection
753 * @target: target to add.
754 * @info: A unsigned integer which will be passed back to the application.
756 * Appends a specified target to the list of supported targets for a
757 * given widget and selection.
760 gtk_selection_add_target (GtkWidget *widget,
767 g_return_if_fail (GTK_IS_WIDGET (widget));
768 g_return_if_fail (selection != GDK_NONE);
770 list = gtk_selection_target_list_get (widget, selection);
771 gtk_target_list_add (list, target, 0, info);
772 #ifdef GDK_WINDOWING_WIN32
773 gdk_win32_selection_add_targets (widget->window, selection, 1, &target);
778 * gtk_selection_add_targets:
779 * @widget: a #GtkWidget
780 * @selection: the selection
781 * @targets: a table of targets to add
782 * @ntargets: number of entries in @targets
784 * Prepends a table of targets to the list of supported targets
785 * for a given widget and selection.
788 gtk_selection_add_targets (GtkWidget *widget,
790 const GtkTargetEntry *targets,
795 g_return_if_fail (GTK_IS_WIDGET (widget));
796 g_return_if_fail (selection != GDK_NONE);
797 g_return_if_fail (targets != NULL);
799 list = gtk_selection_target_list_get (widget, selection);
800 gtk_target_list_add_table (list, targets, ntargets);
802 #ifdef GDK_WINDOWING_WIN32
805 GdkAtom *atoms = g_new (GdkAtom, ntargets);
807 for (i = 0; i < ntargets; ++i)
808 atoms[i] = gdk_atom_intern (targets[i].target, FALSE);
809 gdk_win32_selection_add_targets (widget->window, selection, ntargets, atoms);
817 * gtk_selection_remove_all:
818 * @widget: a #GtkWidget
820 * Removes all handlers and unsets ownership of all
821 * selections for a widget. Called when widget is being
822 * destroyed. This function will not generally be
823 * called by applications.
826 gtk_selection_remove_all (GtkWidget *widget)
830 GtkSelectionInfo *selection_info;
832 /* Remove pending requests/incrs for this widget */
834 tmp_list = current_retrievals;
837 next = tmp_list->next;
838 if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget)
840 current_retrievals = g_list_remove_link (current_retrievals,
842 /* structure will be freed in timeout */
843 g_list_free (tmp_list);
848 /* Disclaim ownership of any selections */
850 tmp_list = current_selections;
853 next = tmp_list->next;
854 selection_info = (GtkSelectionInfo *)tmp_list->data;
856 if (selection_info->widget == widget)
858 gdk_selection_owner_set_for_display (selection_info->display,
860 selection_info->selection,
861 GDK_CURRENT_TIME, FALSE);
862 current_selections = g_list_remove_link (current_selections,
864 g_list_free (tmp_list);
865 g_free (selection_info);
871 /* Remove all selection lists */
872 gtk_selection_target_list_remove (widget);
877 * gtk_selection_convert:
878 * @widget: The widget which acts as requestor
879 * @selection: Which selection to get
880 * @target: Form of information desired (e.g., STRING)
881 * @time_: Time of request (usually of triggering event)
882 In emergency, you could use #GDK_CURRENT_TIME
884 * Requests the contents of a selection. When received,
885 * a "selection_received" signal will be generated.
887 * Return value: %TRUE if requested succeeded. %FALSE if we could not process
888 * request. (e.g., there was already a request in process for
892 gtk_selection_convert (GtkWidget *widget,
897 GtkRetrievalInfo *info;
899 GdkWindow *owner_window;
902 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
903 g_return_val_if_fail (selection != GDK_NONE, FALSE);
906 gtk_selection_init ();
908 if (!GTK_WIDGET_REALIZED (widget))
909 gtk_widget_realize (widget);
911 /* Check to see if there are already any retrievals in progress for
912 this widget. If we changed GDK to use the selection for the
913 window property in which to store the retrieved information, then
914 we could support multiple retrievals for different selections.
915 This might be useful for DND. */
917 tmp_list = current_retrievals;
920 info = (GtkRetrievalInfo *)tmp_list->data;
921 if (info->widget == widget)
923 tmp_list = tmp_list->next;
926 info = g_new (GtkRetrievalInfo, 1);
928 info->widget = widget;
929 info->selection = selection;
930 info->target = target;
935 /* Check if this process has current owner. If so, call handler
936 procedure directly to avoid deadlocks with INCR. */
938 display = gtk_widget_get_display (widget);
939 owner_window = gdk_selection_owner_get_for_display (display, selection);
941 if (owner_window != NULL)
943 GtkWidget *owner_widget;
944 GtkSelectionData selection_data;
946 selection_data.selection = selection;
947 selection_data.target = target;
948 selection_data.data = NULL;
949 selection_data.length = -1;
950 selection_data.display = display;
952 gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget);
954 if (owner_widget != NULL)
956 gtk_selection_invoke_handler (owner_widget,
960 gtk_selection_retrieval_report (info,
962 selection_data.format,
964 selection_data.length,
967 g_free (selection_data.data);
974 /* Otherwise, we need to go through X */
976 current_retrievals = g_list_append (current_retrievals, info);
977 gdk_selection_convert (widget->window, selection, target, time_);
978 g_timeout_add (1000, (GSourceFunc) gtk_selection_retrieval_timeout, info);
985 * gtk_selection_data_set:
986 * @selection_data: a pointer to a #GtkSelectionData structure.
987 * @type: the type of selection data
988 * @format: format (number of bits in a unit)
989 * @data: pointer to the data (will be copied)
990 * @length: length of the data
992 * Stores new data into a #GtkSelectionData object. Should
993 * <emphasis>only</emphasis> be called from a selection handler callback.
994 * Zero-terminates the stored data.
997 gtk_selection_data_set (GtkSelectionData *selection_data,
1003 if (selection_data->data)
1004 g_free (selection_data->data);
1006 selection_data->type = type;
1007 selection_data->format = format;
1011 selection_data->data = g_new (guchar, length+1);
1012 memcpy (selection_data->data, data, length);
1013 selection_data->data[length] = 0;
1017 g_return_if_fail (length <= 0);
1020 selection_data->data = NULL;
1022 selection_data->data = g_strdup("");
1025 selection_data->length = length;
1029 selection_set_string (GtkSelectionData *selection_data,
1033 gchar *tmp = g_strndup (str, len);
1034 gchar *latin1 = gdk_utf8_to_string_target (tmp);
1039 gtk_selection_data_set (selection_data,
1040 GDK_SELECTION_TYPE_STRING,
1041 8, latin1, strlen (latin1));
1051 selection_set_compound_text (GtkSelectionData *selection_data,
1060 gboolean result = FALSE;
1062 tmp = g_strndup (str, len);
1063 if (gdk_utf8_to_compound_text_for_display (selection_data->display, tmp,
1064 &encoding, &format, &text, &new_length))
1066 gtk_selection_data_set (selection_data, encoding, format, text, new_length);
1067 gdk_free_compound_text (text);
1077 /* Normalize \r and \n into \r\n
1080 normalize_to_crlf (const gchar *str,
1083 GString *result = g_string_sized_new (len);
1084 const gchar *p = str;
1089 g_string_append_c (result, '\r');
1093 g_string_append_c (result, *p);
1096 g_string_append_c (result, '\n');
1102 g_string_append_c (result, *p);
1106 return g_string_free (result, FALSE);
1109 /* Normalize \r and \r\n into \n
1112 normalize_to_lf (gchar *str,
1115 GString *result = g_string_sized_new (len);
1116 const gchar *p = str;
1124 g_string_append_c (result, '\n');
1130 g_string_append_c (result, *p);
1134 return g_string_free (result, FALSE);
1138 selection_set_text_plain (GtkSelectionData *selection_data,
1142 const gchar *charset = NULL;
1144 GError *error = NULL;
1146 result = normalize_to_crlf (str, len);
1147 if (selection_data->target == text_plain_atom)
1149 else if (selection_data->target == text_plain_locale_atom)
1150 g_get_charset (&charset);
1154 gchar *tmp = result;
1155 result = g_convert_with_fallback (tmp, -1,
1157 NULL, NULL, NULL, &error);
1163 g_warning ("Error converting from UTF-8 to %s: %s",
1164 charset, error->message);
1165 g_error_free (error);
1170 gtk_selection_data_set (selection_data,
1171 selection_data->target,
1172 8, result, strlen (result));
1179 selection_get_text_plain (GtkSelectionData *selection_data)
1181 const gchar *charset = NULL;
1182 gchar *str, *result;
1184 GError *error = NULL;
1186 str = g_strdup (selection_data->data);
1187 len = selection_data->length;
1189 if (selection_data->type == text_plain_atom)
1190 charset = "ISO-8859-1";
1191 else if (selection_data->type == text_plain_locale_atom)
1192 g_get_charset (&charset);
1197 str = g_convert_with_fallback (tmp, len,
1199 NULL, NULL, &len, &error);
1204 g_warning ("Error converting from %s to UTF-8: %s",
1205 charset, error->message);
1206 g_error_free (error);
1211 else if (!g_utf8_validate (str, -1, NULL))
1213 g_warning ("Error converting from text/plain;charset=utf-8 to UTF-8");
1219 result = normalize_to_lf (str, len);
1226 * gtk_selection_data_set_text:
1227 * @selection_data: a #GtkSelectionData
1228 * @str: a UTF-8 string
1229 * @len: the length of @str, or -1 if @str is nul-terminated.
1231 * Sets the contents of the selection from a UTF-8 encoded string.
1232 * The string is converted to the form determined by
1233 * @selection_data->target.
1235 * Return value: %TRUE if the selection was successfully set,
1239 gtk_selection_data_set_text (GtkSelectionData *selection_data,
1248 if (selection_data->target == utf8_atom)
1250 gtk_selection_data_set (selection_data,
1252 8, (guchar *)str, len);
1255 else if (selection_data->target == GDK_TARGET_STRING)
1257 return selection_set_string (selection_data, str, len);
1259 else if (selection_data->target == ctext_atom ||
1260 selection_data->target == text_atom)
1262 if (selection_set_compound_text (selection_data, str, len))
1264 else if (selection_data->target == text_atom)
1265 return selection_set_string (selection_data, str, len);
1267 else if (selection_data->target == text_plain_atom ||
1268 selection_data->target == text_plain_utf8_atom ||
1269 selection_data->target == text_plain_locale_atom)
1271 return selection_set_text_plain (selection_data, str, len);
1278 * gtk_selection_data_get_text:
1279 * @selection_data: a #GtkSelectionData
1281 * Gets the contents of the selection data as a UTF-8 string.
1283 * Return value: if the selection data contained a recognized
1284 * text type and it could be converted to UTF-8, a newly allocated
1285 * string containing the converted text, otherwise %NULL.
1286 * If the result is non-%NULL it must be freed with g_free().
1289 gtk_selection_data_get_text (GtkSelectionData *selection_data)
1291 guchar *result = NULL;
1295 if (selection_data->length >= 0 &&
1296 (selection_data->type == GDK_TARGET_STRING ||
1297 selection_data->type == ctext_atom ||
1298 selection_data->type == utf8_atom))
1302 gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1303 selection_data->type,
1304 selection_data->format,
1305 selection_data->data,
1306 selection_data->length,
1311 for (i = 1; i < count; i++)
1315 else if (selection_data->length >= 0 &&
1316 (selection_data->type == text_plain_atom ||
1317 selection_data->type == text_plain_utf8_atom ||
1318 selection_data->type == text_plain_locale_atom))
1320 result = selection_get_text_plain (selection_data);
1327 * gtk_selection_data_set_pixbuf:
1328 * @selection_data: a #GtkSelectionData
1329 * @pixbuf: a #GdkPixbuf
1331 * Sets the contents of the selection from a #GdkPixbuf
1332 * The pixbuf is converted to the form determined by
1333 * @selection_data->target.
1335 * Return value: %TRUE if the selection was successfully set,
1341 gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data,
1344 GSList *formats, *f;
1351 formats = gdk_pixbuf_get_formats ();
1353 for (f = formats; f; f = f->next)
1355 GdkPixbufFormat *fmt = f->data;
1357 mimes = gdk_pixbuf_format_get_mime_types (fmt);
1358 for (m = mimes; *m; m++)
1360 atom = gdk_atom_intern (*m, FALSE);
1361 if (selection_data->target == atom)
1364 type = gdk_pixbuf_format_get_name (fmt);
1365 result = gdk_pixbuf_save_to_buffer (pixbuf, &str, &len,
1367 ((strcmp (type, "png") == 0) ?
1368 "compression" : NULL), "2",
1371 gtk_selection_data_set (selection_data,
1372 atom, 8, (guchar *)str, len);
1376 g_slist_free (formats);
1385 g_slist_free (formats);
1391 * gtk_selection_data_get_pixbuf:
1392 * @selection_data: a #GtkSelectionData
1394 * Gets the contents of the selection data as a #GdkPixbuf.
1396 * Return value: if the selection data contained a recognized
1397 * image type and it could be converted to a #GdkPixbuf, a
1398 * newly allocated pixbuf is returned, otherwise %NULL.
1399 * If the result is non-%NULL it must be freed with g_object_unref().
1404 gtk_selection_data_get_pixbuf (GtkSelectionData *selection_data)
1406 GdkPixbufLoader *loader;
1407 GdkPixbuf *result = NULL;
1409 if (selection_data->length > 0)
1411 loader = gdk_pixbuf_loader_new ();
1413 if (gdk_pixbuf_loader_write (loader,
1414 selection_data->data,
1415 selection_data->length,
1417 result = gdk_pixbuf_loader_get_pixbuf (loader);
1420 g_object_ref (result);
1422 gdk_pixbuf_loader_close (loader, NULL);
1423 g_object_unref (loader);
1430 * gtk_selection_data_set_uris:
1431 * @selection_data: a #GtkSelectionData
1432 * @uris: a %NULL-terminated array of strings hilding URIs
1434 * Sets the contents of the selection from a list of URIs.
1435 * The string is converted to the form determined by
1436 * @selection_data->target.
1438 * Return value: %TRUE if the selection was successfully set,
1444 gtk_selection_data_set_uris (GtkSelectionData *selection_data,
1449 if (selection_data->target == text_uri_list_atom)
1456 list = g_string_new (NULL);
1457 for (i = 0; uris[i]; i++)
1459 g_string_append (list, uris[i]);
1460 g_string_append (list, "\r\n");
1463 result = g_convert (list->str, list->len,
1465 NULL, &length, NULL);
1466 g_string_free (list, TRUE);
1470 gtk_selection_data_set (selection_data,
1472 8, (guchar *)result, length);
1482 * gtk_selection_data_get_uris:
1483 * @selection_data: a #GtkSelectionData
1485 * Gets the contents of the selection data as array of URIs.
1487 * Return value: if the selection data contains a list of
1488 * URIs, a newly allocated %NULL-terminated string array
1489 * containing the URIs, otherwise %NULL. If the result is
1490 * non-%NULL it must be freed with g_strfreev().
1495 gtk_selection_data_get_uris (GtkSelectionData *selection_data)
1497 gchar **result = NULL;
1501 if (selection_data->length >= 0 &&
1502 selection_data->type == text_uri_list_atom)
1506 gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1508 selection_data->format,
1509 selection_data->data,
1510 selection_data->length,
1513 result = g_uri_list_extract_uris (list[0]);
1515 for (i = 1; i < count; i++)
1525 * gtk_selection_data_get_targets:
1526 * @selection_data: a #GtkSelectionData object
1527 * @targets: location to store an array of targets. The result
1528 * stored here must be freed with g_free().
1529 * @n_atoms: location to store number of items in @targets.
1531 * Gets the contents of @selection_data as an array of targets.
1532 * This can be used to interpret the results of getting
1533 * the standard TARGETS target that is always supplied for
1536 * Return value: %TRUE if @selection_data contains a valid
1537 * array of targets, otherwise %FALSE.
1540 gtk_selection_data_get_targets (GtkSelectionData *selection_data,
1544 if (selection_data->length >= 0 &&
1545 selection_data->format == 32 &&
1546 selection_data->type == GDK_SELECTION_TYPE_ATOM)
1549 *targets = g_memdup (selection_data->data, selection_data->length);
1551 *n_atoms = selection_data->length / sizeof (GdkAtom);
1567 * gtk_selection_data_targets_include_text:
1568 * @selection_data: a #GtkSelectionData object
1570 * Given a #GtkSelectionData object holding a list of targets,
1571 * determines if any of the targets in @targets can be used to
1574 * Return value: %TRUE if @selection_data holds a list of targets,
1575 * and a suitable target for text is included, otherwise %FALSE.
1578 gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
1583 gboolean result = FALSE;
1587 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1589 for (i=0; i < n_targets; i++)
1591 if (targets[i] == utf8_atom ||
1592 targets[i] == text_atom ||
1593 targets[i] == GDK_TARGET_STRING ||
1594 targets[i] == ctext_atom ||
1595 targets[i] == text_plain_atom ||
1596 targets[i] == text_plain_utf8_atom ||
1597 targets[i] == text_plain_locale_atom)
1611 * gtk_selection_data_targets_include_image:
1612 * @selection_data: a #GtkSelectionData object
1613 * @writable: whether to accept only targets for which GTK+ knows
1614 * how to convert a pixbuf into the format
1616 * Given a #GtkSelectionData object holding a list of targets,
1617 * determines if any of the targets in @targets can be used to
1618 * provide a #GdkPixbuf.
1620 * Return value: %TRUE if @selection_data holds a list of targets,
1621 * and a suitable target for images is included, otherwise %FALSE.
1626 gtk_selection_data_targets_include_image (GtkSelectionData *selection_data,
1632 gboolean result = FALSE;
1633 GtkTargetList *list;
1638 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1640 list = gtk_target_list_new (NULL, 0);
1641 gtk_target_list_add_image_targets (list, 0, writable);
1642 for (i=0; i < n_targets && !result; i++)
1644 for (l = list->list; l && !result; l = l->next)
1646 GtkTargetPair *pair = (GtkTargetPair *)l->data;
1647 if (pair->target == targets[i])
1651 gtk_target_list_unref (list);
1658 /*************************************************************
1659 * gtk_selection_init:
1660 * Initialize local variables
1664 *************************************************************/
1667 gtk_selection_init (void)
1669 gtk_selection_atoms[INCR] = gdk_atom_intern ("INCR", FALSE);
1670 gtk_selection_atoms[MULTIPLE] = gdk_atom_intern ("MULTIPLE", FALSE);
1671 gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern ("TIMESTAMP", FALSE);
1672 gtk_selection_atoms[TARGETS] = gdk_atom_intern ("TARGETS", FALSE);
1678 * gtk_selection_clear:
1679 * @widget: a #GtkWidget
1682 * The default handler for the GtkWidget::selection_clear_event
1685 * Return value: %TRUE if the event was handled, otherwise false
1689 * Deprecated: Instead of calling this function, chain up from
1690 * your selection_clear_event handler. Calling this function
1691 * from any other context is illegal.
1694 gtk_selection_clear (GtkWidget *widget,
1695 GdkEventSelection *event)
1697 /* Note that we filter clear events in gdkselection-x11.c, so
1698 * that we only will get here if the clear event actually
1699 * represents a change that we didn't do ourself.
1702 GtkSelectionInfo *selection_info = NULL;
1704 tmp_list = current_selections;
1707 selection_info = (GtkSelectionInfo *)tmp_list->data;
1709 if ((selection_info->selection == event->selection) &&
1710 (selection_info->widget == widget))
1713 tmp_list = tmp_list->next;
1718 current_selections = g_list_remove_link (current_selections, tmp_list);
1719 g_list_free (tmp_list);
1720 g_free (selection_info);
1727 /*************************************************************
1728 * _gtk_selection_request:
1729 * Handler for "selection_request_event"
1734 *************************************************************/
1737 _gtk_selection_request (GtkWidget *widget,
1738 GdkEventSelection *event)
1740 GdkDisplay *display = gtk_widget_get_display (widget);
1744 gulong selection_max_size;
1747 gtk_selection_init ();
1749 selection_max_size = GTK_SELECTION_MAX_SIZE (display);
1751 /* Check if we own selection */
1753 tmp_list = current_selections;
1756 GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data;
1758 if ((selection_info->selection == event->selection) &&
1759 (selection_info->widget == widget))
1762 tmp_list = tmp_list->next;
1765 if (tmp_list == NULL)
1768 info = g_new (GtkIncrInfo, 1);
1770 g_object_ref (widget);
1772 info->selection = event->selection;
1773 info->num_incrs = 0;
1775 /* Create GdkWindow structure for the requestor */
1777 info->requestor = gdk_window_lookup_for_display (display,
1779 if (!info->requestor)
1780 info->requestor = gdk_window_foreign_new_for_display (display,
1783 /* Determine conversions we need to perform */
1785 if (event->target == gtk_selection_atoms[MULTIPLE])
1794 gdk_error_trap_push ();
1795 if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */
1796 0, selection_max_size, FALSE,
1797 &type, &format, &length, &mult_atoms))
1799 gdk_selection_send_notify_for_display (display,
1805 g_free (mult_atoms);
1809 gdk_error_trap_pop ();
1811 /* This is annoying; the ICCCM doesn't specify the property type
1812 * used for the property contents, so the autoconversion for
1813 * ATOM / ATOM_PAIR in GDK doesn't work properly.
1815 #ifdef GDK_WINDOWING_X11
1816 if (type != GDK_SELECTION_TYPE_ATOM &&
1817 type != gdk_atom_intern ("ATOM_PAIR", FALSE))
1819 info->num_conversions = length / (2*sizeof (glong));
1820 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1822 for (i=0; i<info->num_conversions; i++)
1824 info->conversions[i].target = gdk_x11_xatom_to_atom_for_display (display,
1825 ((glong *)mult_atoms)[2*i]);
1826 info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display,
1827 ((glong *)mult_atoms)[2*i + 1]);
1833 info->num_conversions = length / (2*sizeof (GdkAtom));
1834 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1836 for (i=0; i<info->num_conversions; i++)
1838 info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
1839 info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
1843 else /* only a single conversion */
1845 info->conversions = g_new (GtkIncrConversion, 1);
1846 info->num_conversions = 1;
1847 info->conversions[0].target = event->target;
1848 info->conversions[0].property = event->property;
1851 /* Loop through conversions and determine which of these are big
1852 enough to require doing them via INCR */
1853 for (i=0; i<info->num_conversions; i++)
1855 GtkSelectionData data;
1858 data.selection = event->selection;
1859 data.target = info->conversions[i].target;
1862 data.display = gtk_widget_get_display (widget);
1864 #ifdef DEBUG_SELECTION
1865 g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
1867 info->conversions[i].target,
1868 gdk_atom_name (info->conversions[i].target),
1869 event->requestor, info->conversions[i].property);
1872 gtk_selection_invoke_handler (widget, &data, event->time);
1874 if (data.length < 0)
1876 info->conversions[i].property = GDK_NONE;
1880 g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
1882 items = data.length / gtk_selection_bytes_per_item (data.format);
1884 if (data.length > selection_max_size)
1886 /* Sending via INCR */
1887 #ifdef DEBUG_SELECTION
1888 g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n",
1889 data.length, selection_max_size);
1892 info->conversions[i].offset = 0;
1893 info->conversions[i].data = data;
1896 gdk_property_change (info->requestor,
1897 info->conversions[i].property,
1898 gtk_selection_atoms[INCR],
1900 GDK_PROP_MODE_REPLACE,
1901 (guchar *)&items, 1);
1905 info->conversions[i].offset = -1;
1907 gdk_property_change (info->requestor,
1908 info->conversions[i].property,
1911 GDK_PROP_MODE_REPLACE,
1918 /* If we have some INCR's, we need to send the rest of the data in
1921 if (info->num_incrs > 0)
1923 /* FIXME: this could be dangerous if window doesn't still
1926 #ifdef DEBUG_SELECTION
1927 g_message ("Starting INCR...");
1930 gdk_window_set_events (info->requestor,
1931 gdk_window_get_events (info->requestor) |
1932 GDK_PROPERTY_CHANGE_MASK);
1933 current_incrs = g_list_append (current_incrs, info);
1934 g_timeout_add (1000, (GSourceFunc) gtk_selection_incr_timeout, info);
1937 /* If it was a MULTIPLE request, set the property to indicate which
1938 conversions succeeded */
1939 if (event->target == gtk_selection_atoms[MULTIPLE])
1941 GdkAtom *mult_atoms = g_new (GdkAtom, 2 * info->num_conversions);
1942 for (i = 0; i < info->num_conversions; i++)
1944 mult_atoms[2*i] = info->conversions[i].target;
1945 mult_atoms[2*i+1] = info->conversions[i].property;
1948 gdk_property_change (info->requestor, event->property,
1949 gdk_atom_intern ("ATOM_PAIR", FALSE), 32,
1950 GDK_PROP_MODE_REPLACE,
1951 (guchar *)mult_atoms, 2*info->num_conversions);
1952 g_free (mult_atoms);
1955 if (info->num_conversions == 1 &&
1956 info->conversions[0].property == GDK_NONE)
1958 /* Reject the entire conversion */
1959 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1968 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1976 if (info->num_incrs == 0)
1978 g_free (info->conversions);
1982 g_object_unref (widget);
1987 /*************************************************************
1988 * _gtk_selection_incr_event:
1989 * Called whenever an PropertyNotify event occurs for an
1990 * GdkWindow with user_data == NULL. These will be notifications
1991 * that a window we are sending the selection to via the
1992 * INCR protocol has deleted a property and is ready for
1996 * window: the requestor window
1997 * event: the property event structure
2000 *************************************************************/
2003 _gtk_selection_incr_event (GdkWindow *window,
2004 GdkEventProperty *event)
2007 GtkIncrInfo *info = NULL;
2010 gulong selection_max_size;
2014 if (event->state != GDK_PROPERTY_DELETE)
2017 #ifdef DEBUG_SELECTION
2018 g_message ("PropertyDelete, property %ld", event->atom);
2021 selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window));
2023 /* Now find the appropriate ongoing INCR */
2024 tmp_list = current_incrs;
2027 info = (GtkIncrInfo *)tmp_list->data;
2028 if (info->requestor == event->window)
2031 tmp_list = tmp_list->next;
2034 if (tmp_list == NULL)
2037 /* Find out which target this is for */
2038 for (i=0; i<info->num_conversions; i++)
2040 if (info->conversions[i].property == event->atom &&
2041 info->conversions[i].offset != -1)
2045 info->idle_time = 0;
2047 if (info->conversions[i].offset == -2) /* only the last 0-length
2055 num_bytes = info->conversions[i].data.length -
2056 info->conversions[i].offset;
2057 buffer = info->conversions[i].data.data +
2058 info->conversions[i].offset;
2060 if (num_bytes > selection_max_size)
2062 num_bytes = selection_max_size;
2063 info->conversions[i].offset += selection_max_size;
2066 info->conversions[i].offset = -2;
2068 #ifdef DEBUG_SELECTION
2069 g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
2070 num_bytes, info->conversions[i].offset,
2071 GDK_WINDOW_XWINDOW(info->requestor), event->atom);
2074 bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
2075 gdk_property_change (info->requestor, event->atom,
2076 info->conversions[i].data.type,
2077 info->conversions[i].data.format,
2078 GDK_PROP_MODE_REPLACE,
2080 num_bytes / bytes_per_item);
2082 if (info->conversions[i].offset == -2)
2084 g_free (info->conversions[i].data.data);
2085 info->conversions[i].data.data = NULL;
2091 info->conversions[i].offset = -1;
2096 /* Check if we're finished with all the targets */
2098 if (info->num_incrs == 0)
2100 current_incrs = g_list_remove_link (current_incrs, tmp_list);
2101 g_list_free (tmp_list);
2102 /* Let the timeout free it */
2108 /*************************************************************
2109 * gtk_selection_incr_timeout:
2110 * Timeout callback for the sending portion of the INCR
2113 * info: Information about this incr
2115 *************************************************************/
2118 gtk_selection_incr_timeout (GtkIncrInfo *info)
2123 GDK_THREADS_ENTER ();
2125 /* Determine if retrieval has finished by checking if it still in
2126 list of pending retrievals */
2128 tmp_list = current_incrs;
2131 if (info == (GtkIncrInfo *)tmp_list->data)
2133 tmp_list = tmp_list->next;
2136 /* If retrieval is finished */
2137 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2139 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2141 current_incrs = g_list_remove_link (current_incrs, tmp_list);
2142 g_list_free (tmp_list);
2145 g_free (info->conversions);
2146 /* FIXME: we should check if requestor window is still in use,
2147 and if not, remove it? */
2151 retval = FALSE; /* remove timeout */
2157 retval = TRUE; /* timeout will happen again */
2160 GDK_THREADS_LEAVE ();
2165 /*************************************************************
2166 * _gtk_selection_notify:
2167 * Handler for "selection_notify_event" signals on windows
2168 * where a retrieval is currently in process. The selection
2169 * owner has responded to our conversion request.
2171 * widget: Widget getting signal
2172 * event: Selection event structure
2173 * info: Information about this retrieval
2175 * was event handled?
2176 *************************************************************/
2179 _gtk_selection_notify (GtkWidget *widget,
2180 GdkEventSelection *event)
2183 GtkRetrievalInfo *info = NULL;
2184 guchar *buffer = NULL;
2189 #ifdef DEBUG_SELECTION
2190 g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
2191 event->selection, event->target, event->property);
2194 tmp_list = current_retrievals;
2197 info = (GtkRetrievalInfo *)tmp_list->data;
2198 if (info->widget == widget && info->selection == event->selection)
2200 tmp_list = tmp_list->next;
2203 if (!tmp_list) /* no retrieval in progress */
2206 if (event->property != GDK_NONE)
2207 length = gdk_selection_property_get (widget->window, &buffer,
2210 length = 0; /* silence gcc */
2212 if (event->property == GDK_NONE || buffer == NULL)
2214 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2215 g_list_free (tmp_list);
2216 /* structure will be freed in timeout */
2217 gtk_selection_retrieval_report (info,
2218 GDK_NONE, 0, NULL, -1, event->time);
2223 if (type == gtk_selection_atoms[INCR])
2225 /* The remainder of the selection will come through PropertyNotify
2228 info->notify_time = event->time;
2229 info->idle_time = 0;
2230 info->offset = 0; /* Mark as OK to proceed */
2231 gdk_window_set_events (widget->window,
2232 gdk_window_get_events (widget->window)
2233 | GDK_PROPERTY_CHANGE_MASK);
2237 /* We don't delete the info structure - that will happen in timeout */
2238 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2239 g_list_free (tmp_list);
2241 info->offset = length;
2242 gtk_selection_retrieval_report (info,
2244 buffer, length, event->time);
2247 gdk_property_delete (widget->window, event->property);
2254 /*************************************************************
2255 * _gtk_selection_property_notify:
2256 * Handler for "property_notify_event" signals on windows
2257 * where a retrieval is currently in process. The selection
2258 * owner has added more data.
2260 * widget: Widget getting signal
2261 * event: Property event structure
2262 * info: Information about this retrieval
2264 * was event handled?
2265 *************************************************************/
2268 _gtk_selection_property_notify (GtkWidget *widget,
2269 GdkEventProperty *event)
2272 GtkRetrievalInfo *info = NULL;
2278 g_return_val_if_fail (widget != NULL, FALSE);
2279 g_return_val_if_fail (event != NULL, FALSE);
2281 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
2282 if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */
2283 (event->atom != gdk_atom_intern ("GDK_SELECTION", FALSE))) /* not the right property */
2287 #ifdef DEBUG_SELECTION
2288 g_message ("PropertyNewValue, property %ld",
2292 tmp_list = current_retrievals;
2295 info = (GtkRetrievalInfo *)tmp_list->data;
2296 if (info->widget == widget)
2298 tmp_list = tmp_list->next;
2301 if (!tmp_list) /* No retrieval in progress */
2304 if (info->offset < 0) /* We haven't got the SelectionNotify
2305 for this retrieval yet */
2308 info->idle_time = 0;
2310 length = gdk_selection_property_get (widget->window, &new_buffer,
2312 gdk_property_delete (widget->window, event->atom);
2314 /* We could do a lot better efficiency-wise by paying attention to
2315 what length was sent in the initial INCR transaction, instead of
2316 doing memory allocation at every step. But its only guaranteed to
2317 be a _lower bound_ (pretty useless!) */
2319 if (length == 0 || type == GDK_NONE) /* final zero length portion */
2321 /* Info structure will be freed in timeout */
2322 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2323 g_list_free (tmp_list);
2324 gtk_selection_retrieval_report (info,
2326 (type == GDK_NONE) ? NULL : info->buffer,
2327 (type == GDK_NONE) ? -1 : info->offset,
2330 else /* append on newly arrived data */
2334 #ifdef DEBUG_SELECTION
2335 g_message ("Start - Adding %d bytes at offset 0",
2338 info->buffer = new_buffer;
2339 info->offset = length;
2344 #ifdef DEBUG_SELECTION
2345 g_message ("Appending %d bytes at offset %d",
2346 length,info->offset);
2348 /* We copy length+1 bytes to preserve guaranteed null termination */
2349 info->buffer = g_realloc (info->buffer, info->offset+length+1);
2350 memcpy (info->buffer + info->offset, new_buffer, length+1);
2351 info->offset += length;
2352 g_free (new_buffer);
2359 /*************************************************************
2360 * gtk_selection_retrieval_timeout:
2361 * Timeout callback while receiving a selection.
2363 * info: Information about this retrieval
2365 *************************************************************/
2368 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
2373 GDK_THREADS_ENTER ();
2375 /* Determine if retrieval has finished by checking if it still in
2376 list of pending retrievals */
2378 tmp_list = current_retrievals;
2381 if (info == (GtkRetrievalInfo *)tmp_list->data)
2383 tmp_list = tmp_list->next;
2386 /* If retrieval is finished */
2387 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2389 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2391 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2392 g_list_free (tmp_list);
2393 gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
2396 g_free (info->buffer);
2399 retval = FALSE; /* remove timeout */
2405 retval = TRUE; /* timeout will happen again */
2408 GDK_THREADS_LEAVE ();
2413 /*************************************************************
2414 * gtk_selection_retrieval_report:
2415 * Emits a "selection_received" signal.
2417 * info: information about the retrieval that completed
2418 * buffer: buffer containing data (NULL => errror)
2419 * time: timestamp for data in buffer
2421 *************************************************************/
2424 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
2425 GdkAtom type, gint format,
2426 guchar *buffer, gint length,
2429 GtkSelectionData data;
2431 data.selection = info->selection;
2432 data.target = info->target;
2434 data.format = format;
2436 data.length = length;
2438 data.display = gtk_widget_get_display (info->widget);
2440 g_signal_emit_by_name (info->widget,
2441 "selection_received",
2445 /*************************************************************
2446 * gtk_selection_invoke_handler:
2447 * Finds and invokes handler for specified
2448 * widget/selection/target combination, calls
2449 * gtk_selection_default_handler if none exists.
2452 * widget: selection owner
2453 * data: selection data [INOUT]
2454 * time: time from requeset
2457 * Number of bytes written to buffer, -1 if error
2458 *************************************************************/
2461 gtk_selection_invoke_handler (GtkWidget *widget,
2462 GtkSelectionData *data,
2465 GtkTargetList *target_list;
2469 g_return_if_fail (widget != NULL);
2471 target_list = gtk_selection_target_list_get (widget, data->selection);
2473 gtk_target_list_find (target_list, data->target, &info))
2475 g_signal_emit_by_name (widget,
2481 gtk_selection_default_handler (widget, data);
2484 /*************************************************************
2485 * gtk_selection_default_handler:
2486 * Handles some default targets that exist for any widget
2487 * If it can't fit results into buffer, returns -1. This
2488 * won't happen in any conceivable case, since it would
2489 * require 1000 selection targets!
2492 * widget: selection owner
2493 * data: selection data [INOUT]
2495 *************************************************************/
2498 gtk_selection_default_handler (GtkWidget *widget,
2499 GtkSelectionData *data)
2501 if (data->target == gtk_selection_atoms[TIMESTAMP])
2503 /* Time which was used to obtain selection */
2505 GtkSelectionInfo *selection_info;
2507 tmp_list = current_selections;
2510 selection_info = (GtkSelectionInfo *)tmp_list->data;
2511 if ((selection_info->widget == widget) &&
2512 (selection_info->selection == data->selection))
2514 gulong time = selection_info->time;
2516 gtk_selection_data_set (data,
2517 GDK_SELECTION_TYPE_INTEGER,
2524 tmp_list = tmp_list->next;
2529 else if (data->target == gtk_selection_atoms[TARGETS])
2531 /* List of all targets supported for this widget/selection pair */
2535 GtkTargetList *target_list;
2536 GtkTargetPair *pair;
2538 target_list = gtk_selection_target_list_get (widget,
2540 count = g_list_length (target_list->list) + 3;
2542 data->type = GDK_SELECTION_TYPE_ATOM;
2544 data->length = count * sizeof (GdkAtom);
2546 /* selection data is always terminated by a trailing \0
2548 p = g_malloc (data->length + 1);
2549 data->data = (guchar *)p;
2550 data->data[data->length] = '\0';
2552 *p++ = gtk_selection_atoms[TIMESTAMP];
2553 *p++ = gtk_selection_atoms[TARGETS];
2554 *p++ = gtk_selection_atoms[MULTIPLE];
2556 tmp_list = target_list->list;
2559 pair = (GtkTargetPair *)tmp_list->data;
2560 *p++ = pair->target;
2562 tmp_list = tmp_list->next;
2573 * gtk_selection_data_copy:
2574 * @data: a pointer to a #GtkSelectionData structure.
2576 * Makes a copy of a #GtkSelectionData structure and its data.
2578 * Return value: a pointer to a copy of @data.
2581 gtk_selection_data_copy (GtkSelectionData *data)
2583 GtkSelectionData *new_data;
2585 g_return_val_if_fail (data != NULL, NULL);
2587 new_data = g_new (GtkSelectionData, 1);
2592 new_data->data = g_malloc (data->length + 1);
2593 memcpy (new_data->data, data->data, data->length + 1);
2600 * gtk_selection_data_free:
2601 * @data: a pointer to a #GtkSelectionData structure.
2603 * Frees a #GtkSelectionData structure returned from
2604 * gtk_selection_data_copy().
2607 gtk_selection_data_free (GtkSelectionData *data)
2609 g_return_if_fail (data != NULL);
2612 g_free (data->data);
2618 gtk_selection_data_get_type (void)
2620 static GType our_type = 0;
2623 our_type = g_boxed_type_register_static ("GtkSelectionData",
2624 (GBoxedCopyFunc) gtk_selection_data_copy,
2625 (GBoxedFreeFunc) gtk_selection_data_free);
2631 gtk_selection_bytes_per_item (gint format)
2636 return sizeof (char);
2639 return sizeof (short);
2642 return sizeof (long);
2645 g_assert_not_reached();
2650 #define __GTK_SELECTION_C__
2651 #include "gtkaliasdef.c"