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 for (f = formats; f; f = f->next)
367 GdkPixbufFormat *fmt = f->data;
369 if (writable && !gdk_pixbuf_format_is_writable (fmt))
372 mimes = gdk_pixbuf_format_get_mime_types (fmt);
373 for (m = mimes; *m; m++)
375 atom = gdk_atom_intern (*m, FALSE);
376 gtk_target_list_add (list, atom, 0, info);
381 g_slist_free (formats);
385 * gtk_target_list_add_uri_targets:
386 * @list: a #GtkTargetList
387 * @info: an ID that will be passed back to the application
389 * Appends the URI targets supported by #GtkSelection to
390 * the target list. All targets are added with the same @info.
395 gtk_target_list_add_uri_targets (GtkTargetList *list,
398 g_return_if_fail (list != NULL);
402 gtk_target_list_add (list, text_uri_list_atom, 0, info);
406 * gtk_target_list_add_table:
407 * @list: a #GtkTargetList
408 * @targets: the table of #GtkTargetEntry
409 * @ntargets: number of targets in the table
411 * Prepends a table of #GtkTargetEntry to a target list.
414 gtk_target_list_add_table (GtkTargetList *list,
415 const GtkTargetEntry *targets,
420 for (i=ntargets-1; i >= 0; i--)
422 GtkTargetPair *pair = g_new (GtkTargetPair, 1);
423 pair->target = gdk_atom_intern (targets[i].target, FALSE);
424 pair->flags = targets[i].flags;
425 pair->info = targets[i].info;
427 list->list = g_list_prepend (list->list, pair);
432 * gtk_target_list_remove:
433 * @list: a #GtkTargetList
434 * @target: the interned atom representing the target
436 * Removes a target from a target list.
439 gtk_target_list_remove (GtkTargetList *list,
444 g_return_if_fail (list != NULL);
446 tmp_list = list->list;
449 GtkTargetPair *pair = tmp_list->data;
451 if (pair->target == target)
455 list->list = g_list_remove_link (list->list, tmp_list);
456 g_list_free_1 (tmp_list);
461 tmp_list = tmp_list->next;
466 * gtk_target_list_find:
467 * @list: a #GtkTargetList
468 * @target: an interned atom representing the target to search for
469 * @info: a pointer to the location to store application info for target
471 * Looks up a given target in a #GtkTargetList.
473 * Return value: %TRUE if the target was found, otherwise %FALSE
476 gtk_target_list_find (GtkTargetList *list,
480 GList *tmp_list = list->list;
483 GtkTargetPair *pair = tmp_list->data;
485 if (pair->target == target)
490 tmp_list = tmp_list->next;
497 * gtk_selection_owner_set_for_display:
498 * @display: the #Gdkdisplay where the selection is set
499 * @widget: new selection owner (a #GdkWidget), or %NULL.
500 * @selection: an interned atom representing the selection to claim.
501 * @time_: timestamp with which to claim the selection
503 * Claim ownership of a given selection for a particular widget, or,
504 * if @widget is %NULL, release ownership of the selection.
506 * Return value: TRUE if the operation succeeded
511 gtk_selection_owner_set_for_display (GdkDisplay *display,
517 GtkWidget *old_owner;
518 GtkSelectionInfo *selection_info = NULL;
521 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
522 g_return_val_if_fail (selection != GDK_NONE, FALSE);
523 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
524 g_return_val_if_fail (widget == NULL || gtk_widget_get_display (widget) == display, FALSE);
529 window = widget->window;
531 tmp_list = current_selections;
534 if (((GtkSelectionInfo *)tmp_list->data)->selection == selection)
536 selection_info = tmp_list->data;
540 tmp_list = tmp_list->next;
543 if (gdk_selection_owner_set_for_display (display, window, selection, time, TRUE))
551 old_owner = selection_info->widget;
552 current_selections = g_list_remove_link (current_selections,
554 g_list_free (tmp_list);
555 g_free (selection_info);
560 if (selection_info == NULL)
562 selection_info = g_new (GtkSelectionInfo, 1);
563 selection_info->selection = selection;
564 selection_info->widget = widget;
565 selection_info->time = time;
566 selection_info->display = display;
567 current_selections = g_list_prepend (current_selections,
572 old_owner = selection_info->widget;
573 selection_info->widget = widget;
574 selection_info->time = time;
575 selection_info->display = display;
578 /* If another widget in the application lost the selection,
579 * send it a GDK_SELECTION_CLEAR event.
581 if (old_owner && old_owner != widget)
583 GdkEvent *event = gdk_event_new (GDK_SELECTION_CLEAR);
585 event->selection.window = g_object_ref (old_owner->window);
586 event->selection.selection = selection;
587 event->selection.time = time;
589 gtk_widget_event (old_owner, event);
591 gdk_event_free (event);
600 * gtk_selection_owner_set:
601 * @widget: a #GtkWidget, or %NULL.
602 * @selection: an interned atom representing the selection to claim
603 * @time_: timestamp with which to claim the selection
605 * Claims ownership of a given selection for a particular widget,
606 * or, if @widget is %NULL, release ownership of the selection.
608 * Return value: %TRUE if the operation succeeded
611 gtk_selection_owner_set (GtkWidget *widget,
617 g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
618 g_return_val_if_fail (selection != GDK_NONE, FALSE);
621 display = gtk_widget_get_display (widget);
625 g_warning ("gtk_selection_owner_set (NULL,...) is not multihead safe"));
627 display = gdk_display_get_default ();
630 return gtk_selection_owner_set_for_display (display, widget,
634 typedef struct _GtkSelectionTargetList GtkSelectionTargetList;
636 struct _GtkSelectionTargetList {
641 static GtkTargetList *
642 gtk_selection_target_list_get (GtkWidget *widget,
645 GtkSelectionTargetList *sellist;
649 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
654 sellist = tmp_list->data;
655 if (sellist->selection == selection)
656 return sellist->list;
657 tmp_list = tmp_list->next;
660 sellist = g_new (GtkSelectionTargetList, 1);
661 sellist->selection = selection;
662 sellist->list = gtk_target_list_new (NULL, 0);
664 lists = g_list_prepend (lists, sellist);
665 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
667 return sellist->list;
671 gtk_selection_target_list_remove (GtkWidget *widget)
673 GtkSelectionTargetList *sellist;
677 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
682 sellist = tmp_list->data;
684 gtk_target_list_unref (sellist->list);
687 tmp_list = tmp_list->next;
691 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, NULL);
695 * gtk_selection_clear_targets:
696 * @widget: a #GtkWidget
697 * @selection: an atom representing a selection
699 * Remove all targets registered for the given selection for the
703 gtk_selection_clear_targets (GtkWidget *widget,
706 GtkSelectionTargetList *sellist;
710 g_return_if_fail (GTK_IS_WIDGET (widget));
711 g_return_if_fail (selection != GDK_NONE);
713 lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
718 sellist = tmp_list->data;
719 if (sellist->selection == selection)
721 lists = g_list_delete_link (lists, tmp_list);
722 gtk_target_list_unref (sellist->list);
728 tmp_list = tmp_list->next;
731 g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists);
735 * gtk_selection_add_target:
736 * @widget: a #GtkTarget
737 * @selection: the selection
738 * @target: target to add.
739 * @info: A unsigned integer which will be passed back to the application.
741 * Appends a specified target to the list of supported targets for a
742 * given widget and selection.
745 gtk_selection_add_target (GtkWidget *widget,
752 g_return_if_fail (GTK_IS_WIDGET (widget));
753 g_return_if_fail (selection != GDK_NONE);
755 list = gtk_selection_target_list_get (widget, selection);
756 gtk_target_list_add (list, target, 0, info);
757 #ifdef GDK_WINDOWING_WIN32
758 gdk_win32_selection_add_targets (widget->window, selection, 1, &target);
763 * gtk_selection_add_targets:
764 * @widget: a #GtkWidget
765 * @selection: the selection
766 * @targets: a table of targets to add
767 * @ntargets: number of entries in @targets
769 * Prepends a table of targets to the list of supported targets
770 * for a given widget and selection.
773 gtk_selection_add_targets (GtkWidget *widget,
775 const GtkTargetEntry *targets,
780 g_return_if_fail (GTK_IS_WIDGET (widget));
781 g_return_if_fail (selection != GDK_NONE);
782 g_return_if_fail (targets != NULL);
784 list = gtk_selection_target_list_get (widget, selection);
785 gtk_target_list_add_table (list, targets, ntargets);
787 #ifdef GDK_WINDOWING_WIN32
790 GdkAtom *atoms = g_new (GdkAtom, ntargets);
792 for (i = 0; i < ntargets; ++i)
793 atoms[i] = gdk_atom_intern (targets[i].target, FALSE);
794 gdk_win32_selection_add_targets (widget->window, selection, ntargets, atoms);
802 * gtk_selection_remove_all:
803 * @widget: a #GtkWidget
805 * Removes all handlers and unsets ownership of all
806 * selections for a widget. Called when widget is being
807 * destroyed. This function will not generally be
808 * called by applications.
811 gtk_selection_remove_all (GtkWidget *widget)
815 GtkSelectionInfo *selection_info;
817 /* Remove pending requests/incrs for this widget */
819 tmp_list = current_retrievals;
822 next = tmp_list->next;
823 if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget)
825 current_retrievals = g_list_remove_link (current_retrievals,
827 /* structure will be freed in timeout */
828 g_list_free (tmp_list);
833 /* Disclaim ownership of any selections */
835 tmp_list = current_selections;
838 next = tmp_list->next;
839 selection_info = (GtkSelectionInfo *)tmp_list->data;
841 if (selection_info->widget == widget)
843 gdk_selection_owner_set_for_display (selection_info->display,
845 selection_info->selection,
846 GDK_CURRENT_TIME, FALSE);
847 current_selections = g_list_remove_link (current_selections,
849 g_list_free (tmp_list);
850 g_free (selection_info);
856 /* Remove all selection lists */
857 gtk_selection_target_list_remove (widget);
862 * gtk_selection_convert:
863 * @widget: The widget which acts as requestor
864 * @selection: Which selection to get
865 * @target: Form of information desired (e.g., STRING)
866 * @time_: Time of request (usually of triggering event)
867 In emergency, you could use #GDK_CURRENT_TIME
869 * Requests the contents of a selection. When received,
870 * a "selection_received" signal will be generated.
872 * Return value: %TRUE if requested succeeded. %FALSE if we could not process
873 * request. (e.g., there was already a request in process for
877 gtk_selection_convert (GtkWidget *widget,
882 GtkRetrievalInfo *info;
884 GdkWindow *owner_window;
887 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
888 g_return_val_if_fail (selection != GDK_NONE, FALSE);
891 gtk_selection_init ();
893 if (!GTK_WIDGET_REALIZED (widget))
894 gtk_widget_realize (widget);
896 /* Check to see if there are already any retrievals in progress for
897 this widget. If we changed GDK to use the selection for the
898 window property in which to store the retrieved information, then
899 we could support multiple retrievals for different selections.
900 This might be useful for DND. */
902 tmp_list = current_retrievals;
905 info = (GtkRetrievalInfo *)tmp_list->data;
906 if (info->widget == widget)
908 tmp_list = tmp_list->next;
911 info = g_new (GtkRetrievalInfo, 1);
913 info->widget = widget;
914 info->selection = selection;
915 info->target = target;
920 /* Check if this process has current owner. If so, call handler
921 procedure directly to avoid deadlocks with INCR. */
923 display = gtk_widget_get_display (widget);
924 owner_window = gdk_selection_owner_get_for_display (display, selection);
926 if (owner_window != NULL)
928 GtkWidget *owner_widget;
929 GtkSelectionData selection_data;
931 selection_data.selection = selection;
932 selection_data.target = target;
933 selection_data.data = NULL;
934 selection_data.length = -1;
935 selection_data.display = display;
937 gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget);
939 if (owner_widget != NULL)
941 gtk_selection_invoke_handler (owner_widget,
945 gtk_selection_retrieval_report (info,
947 selection_data.format,
949 selection_data.length,
952 g_free (selection_data.data);
959 /* Otherwise, we need to go through X */
961 current_retrievals = g_list_append (current_retrievals, info);
962 gdk_selection_convert (widget->window, selection, target, time_);
963 g_timeout_add (1000, (GSourceFunc) gtk_selection_retrieval_timeout, info);
970 * gtk_selection_data_set:
971 * @selection_data: a pointer to a #GtkSelectionData structure.
972 * @type: the type of selection data
973 * @format: format (number of bits in a unit)
974 * @data: pointer to the data (will be copied)
975 * @length: length of the data
977 * Stores new data into a #GtkSelectionData object. Should
978 * <emphasis>only</emphasis> be called from a selection handler callback.
979 * Zero-terminates the stored data.
982 gtk_selection_data_set (GtkSelectionData *selection_data,
988 if (selection_data->data)
989 g_free (selection_data->data);
991 selection_data->type = type;
992 selection_data->format = format;
996 selection_data->data = g_new (guchar, length+1);
997 memcpy (selection_data->data, data, length);
998 selection_data->data[length] = 0;
1002 g_return_if_fail (length <= 0);
1005 selection_data->data = NULL;
1007 selection_data->data = g_strdup("");
1010 selection_data->length = length;
1014 selection_set_string (GtkSelectionData *selection_data,
1018 gchar *tmp = g_strndup (str, len);
1019 gchar *latin1 = gdk_utf8_to_string_target (tmp);
1024 gtk_selection_data_set (selection_data,
1025 GDK_SELECTION_TYPE_STRING,
1026 8, latin1, strlen (latin1));
1036 selection_set_compound_text (GtkSelectionData *selection_data,
1045 gboolean result = FALSE;
1047 tmp = g_strndup (str, len);
1048 if (gdk_utf8_to_compound_text_for_display (selection_data->display, tmp,
1049 &encoding, &format, &text, &new_length))
1051 gtk_selection_data_set (selection_data, encoding, format, text, new_length);
1052 gdk_free_compound_text (text);
1062 /* Normalize \r and \n into \r\n
1065 normalize_to_crlf (const gchar *str,
1068 GString *result = g_string_sized_new (len);
1069 const gchar *p = str;
1074 g_string_append_c (result, '\r');
1078 g_string_append_c (result, *p);
1081 g_string_append_c (result, '\n');
1087 g_string_append_c (result, *p);
1091 return g_string_free (result, FALSE);
1094 /* Normalize \r and \r\n into \n
1097 normalize_to_lf (gchar *str,
1100 GString *result = g_string_sized_new (len);
1101 const gchar *p = str;
1109 g_string_append_c (result, '\n');
1115 g_string_append_c (result, *p);
1119 return g_string_free (result, FALSE);
1123 selection_set_text_plain (GtkSelectionData *selection_data,
1127 const gchar *charset = NULL;
1129 GError *error = NULL;
1131 result = normalize_to_crlf (str, len);
1132 if (selection_data->target == text_plain_atom)
1134 else if (selection_data->target == text_plain_locale_atom)
1135 g_get_charset (&charset);
1139 gchar *tmp = result;
1140 result = g_convert_with_fallback (tmp, -1,
1142 NULL, NULL, NULL, &error);
1148 g_warning ("Error converting from UTF-8 to %s: %s",
1149 charset, error->message);
1150 g_error_free (error);
1155 gtk_selection_data_set (selection_data,
1156 selection_data->target,
1157 8, result, strlen (result));
1164 selection_get_text_plain (GtkSelectionData *selection_data)
1166 const gchar *charset = NULL;
1167 gchar *str, *result;
1169 GError *error = NULL;
1171 str = g_strdup (selection_data->data);
1172 len = selection_data->length;
1174 if (selection_data->type == text_plain_atom)
1175 charset = "ISO-8859-1";
1176 else if (selection_data->type == text_plain_locale_atom)
1177 g_get_charset (&charset);
1182 str = g_convert_with_fallback (tmp, len,
1184 NULL, NULL, &len, &error);
1189 g_warning ("Error converting from %s to UTF-8: %s",
1190 charset, error->message);
1191 g_error_free (error);
1196 else if (!g_utf8_validate (str, -1, NULL))
1198 g_warning ("Error converting from text/plain;charset=utf-8 to UTF-8");
1204 result = normalize_to_lf (str, len);
1211 * gtk_selection_data_set_text:
1212 * @selection_data: a #GtkSelectionData
1213 * @str: a UTF-8 string
1214 * @len: the length of @str, or -1 if @str is nul-terminated.
1216 * Sets the contents of the selection from a UTF-8 encoded string.
1217 * The string is converted to the form determined by
1218 * @selection_data->target.
1220 * Return value: %TRUE if the selection was successfully set,
1224 gtk_selection_data_set_text (GtkSelectionData *selection_data,
1233 if (selection_data->target == utf8_atom)
1235 gtk_selection_data_set (selection_data,
1237 8, (guchar *)str, len);
1240 else if (selection_data->target == GDK_TARGET_STRING)
1242 return selection_set_string (selection_data, str, len);
1244 else if (selection_data->target == ctext_atom ||
1245 selection_data->target == text_atom)
1247 if (selection_set_compound_text (selection_data, str, len))
1249 else if (selection_data->target == text_atom)
1250 return selection_set_string (selection_data, str, len);
1252 else if (selection_data->target == text_plain_atom ||
1253 selection_data->target == text_plain_utf8_atom ||
1254 selection_data->target == text_plain_locale_atom)
1256 return selection_set_text_plain (selection_data, str, len);
1263 * gtk_selection_data_get_text:
1264 * @selection_data: a #GtkSelectionData
1266 * Gets the contents of the selection data as a UTF-8 string.
1268 * Return value: if the selection data contained a recognized
1269 * text type and it could be converted to UTF-8, a newly allocated
1270 * string containing the converted text, otherwise %NULL.
1271 * If the result is non-%NULL it must be freed with g_free().
1274 gtk_selection_data_get_text (GtkSelectionData *selection_data)
1276 guchar *result = NULL;
1280 if (selection_data->length >= 0 &&
1281 (selection_data->type == GDK_TARGET_STRING ||
1282 selection_data->type == ctext_atom ||
1283 selection_data->type == utf8_atom))
1287 gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1288 selection_data->type,
1289 selection_data->format,
1290 selection_data->data,
1291 selection_data->length,
1296 for (i = 1; i < count; i++)
1300 else if (selection_data->length >= 0 &&
1301 (selection_data->type == text_plain_atom ||
1302 selection_data->type == text_plain_utf8_atom ||
1303 selection_data->type == text_plain_locale_atom))
1305 result = selection_get_text_plain (selection_data);
1312 * gtk_selection_data_set_pixbuf:
1313 * @selection_data: a #GtkSelectionData
1314 * @pixbuf: a #GdkPixbuf
1316 * Sets the contents of the selection from a #GdkPixbuf
1317 * The pixbuf is converted to the form determined by
1318 * @selection_data->target.
1320 * Return value: %TRUE if the selection was successfully set,
1326 gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data,
1329 GSList *formats, *f;
1336 formats = gdk_pixbuf_get_formats ();
1338 for (f = formats; f; f = f->next)
1340 GdkPixbufFormat *fmt = f->data;
1342 mimes = gdk_pixbuf_format_get_mime_types (fmt);
1343 for (m = mimes; *m; m++)
1345 atom = gdk_atom_intern (*m, FALSE);
1346 if (selection_data->target == atom)
1349 type = gdk_pixbuf_format_get_name (fmt),
1350 result = gdk_pixbuf_save_to_buffer (pixbuf, &str, &len,
1353 gtk_selection_data_set (selection_data,
1354 atom, 8, (guchar *)str, len);
1358 g_slist_free (formats);
1367 g_slist_free (formats);
1373 * gtk_selection_data_get_pixbuf:
1374 * @selection_data: a #GtkSelectionData
1376 * Gets the contents of the selection data as a #GdkPixbuf.
1378 * Return value: if the selection data contained a recognized
1379 * image type and it could be converted to a #GdkPixbuf, a
1380 * newly allocated pixbuf is returned, otherwise %NULL.
1381 * If the result is non-%NULL it must be freed with g_object_unref().
1386 gtk_selection_data_get_pixbuf (GtkSelectionData *selection_data)
1388 GdkPixbufLoader *loader;
1389 GdkPixbuf *result = NULL;
1391 if (selection_data->length > 0)
1393 loader = gdk_pixbuf_loader_new ();
1395 if (gdk_pixbuf_loader_write (loader,
1396 selection_data->data,
1397 selection_data->length,
1399 result = gdk_pixbuf_loader_get_pixbuf (loader);
1402 g_object_ref (result);
1404 gdk_pixbuf_loader_close (loader, NULL);
1405 g_object_unref (loader);
1412 * gtk_selection_data_set_uris:
1413 * @selection_data: a #GtkSelectionData
1414 * @uris: a %NULL-terminated array of strings hilding URIs
1416 * Sets the contents of the selection from a list of URIs.
1417 * The string is converted to the form determined by
1418 * @selection_data->target.
1420 * Return value: %TRUE if the selection was successfully set,
1426 gtk_selection_data_set_uris (GtkSelectionData *selection_data,
1431 if (selection_data->target == text_uri_list_atom)
1438 list = g_string_new (NULL);
1439 for (i = 0; uris[i]; i++)
1441 g_string_append (list, uris[i]);
1442 g_string_append (list, "\r\n");
1445 result = g_convert (list->str, list->len,
1447 NULL, &length, NULL);
1448 g_string_free (list, TRUE);
1452 gtk_selection_data_set (selection_data,
1454 8, (guchar *)result, length);
1464 * gtk_selection_data_get_uris:
1465 * @selection_data: a #GtkSelectionData
1467 * Gets the contents of the selection data as array of URIs.
1469 * Return value: if the selection data contains a list of
1470 * URIs, a newly allocated %NULL-terminated string array
1471 * containing the URIs, otherwise %NULL. If the result is
1472 * non-%NULL it must be freed with g_strfreev().
1477 gtk_selection_data_get_uris (GtkSelectionData *selection_data)
1479 gchar **result = NULL;
1483 if (selection_data->length >= 0 &&
1484 selection_data->type == text_uri_list_atom)
1488 gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
1490 selection_data->format,
1491 selection_data->data,
1492 selection_data->length,
1495 result = g_uri_list_extract_uris (list[0]);
1497 for (i = 1; i < count; i++)
1507 * gtk_selection_data_get_targets:
1508 * @selection_data: a #GtkSelectionData object
1509 * @targets: location to store an array of targets. The result
1510 * stored here must be freed with g_free().
1511 * @n_atoms: location to store number of items in @targets.
1513 * Gets the contents of @selection_data as an array of targets.
1514 * This can be used to interpret the results of getting
1515 * the standard TARGETS target that is always supplied for
1518 * Return value: %TRUE if @selection_data contains a valid
1519 * array of targets, otherwise %FALSE.
1522 gtk_selection_data_get_targets (GtkSelectionData *selection_data,
1526 if (selection_data->length >= 0 &&
1527 selection_data->format == 32 &&
1528 selection_data->type == GDK_SELECTION_TYPE_ATOM)
1531 *targets = g_memdup (selection_data->data, selection_data->length);
1533 *n_atoms = selection_data->length / sizeof (GdkAtom);
1549 * gtk_selection_data_targets_include_text:
1550 * @selection_data: a #GtkSelectionData object
1552 * Given a #GtkSelectionData object holding a list of targets,
1553 * determines if any of the targets in @targets can be used to
1556 * Return value: %TRUE if @selection_data holds a list of targets,
1557 * and a suitable target for text is included, otherwise %FALSE.
1560 gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
1565 gboolean result = FALSE;
1569 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1571 for (i=0; i < n_targets; i++)
1573 if (targets[i] == utf8_atom ||
1574 targets[i] == text_atom ||
1575 targets[i] == GDK_TARGET_STRING ||
1576 targets[i] == ctext_atom ||
1577 targets[i] == text_plain_atom ||
1578 targets[i] == text_plain_utf8_atom ||
1579 targets[i] == text_plain_locale_atom)
1593 * gtk_selection_data_targets_include_image:
1594 * @selection_data: a #GtkSelectionData object
1595 * @writable: whether to accept only targets for which GTK+ knows
1596 * how to convert a pixbuf into the format
1598 * Given a #GtkSelectionData object holding a list of targets,
1599 * determines if any of the targets in @targets can be used to
1600 * provide a #GdkPixbuf.
1602 * Return value: %TRUE if @selection_data holds a list of targets,
1603 * and a suitable target for images is included, otherwise %FALSE.
1608 gtk_selection_data_targets_include_image (GtkSelectionData *selection_data,
1614 gboolean result = FALSE;
1615 GtkTargetList *list;
1620 if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
1622 list = gtk_target_list_new (NULL, 0);
1623 gtk_target_list_add_image_targets (list, 0, writable);
1624 for (i=0; i < n_targets && !result; i++)
1626 for (l = list->list; l && !result; l = l->next)
1628 GtkTargetPair *pair = (GtkTargetPair *)l->data;
1629 if (pair->target == targets[i])
1633 gtk_target_list_unref (list);
1640 /*************************************************************
1641 * gtk_selection_init:
1642 * Initialize local variables
1646 *************************************************************/
1649 gtk_selection_init (void)
1651 gtk_selection_atoms[INCR] = gdk_atom_intern ("INCR", FALSE);
1652 gtk_selection_atoms[MULTIPLE] = gdk_atom_intern ("MULTIPLE", FALSE);
1653 gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern ("TIMESTAMP", FALSE);
1654 gtk_selection_atoms[TARGETS] = gdk_atom_intern ("TARGETS", FALSE);
1660 * gtk_selection_clear:
1661 * @widget: a #GtkWidget
1664 * The default handler for the GtkWidget::selection_clear_event
1667 * Return value: %TRUE if the event was handled, otherwise false
1671 * Deprecated: Instead of calling this function, chain up from
1672 * your selection_clear_event handler. Calling this function
1673 * from any other context is illegal.
1676 gtk_selection_clear (GtkWidget *widget,
1677 GdkEventSelection *event)
1679 /* Note that we filter clear events in gdkselection-x11.c, so
1680 * that we only will get here if the clear event actually
1681 * represents a change that we didn't do ourself.
1684 GtkSelectionInfo *selection_info = NULL;
1686 tmp_list = current_selections;
1689 selection_info = (GtkSelectionInfo *)tmp_list->data;
1691 if ((selection_info->selection == event->selection) &&
1692 (selection_info->widget == widget))
1695 tmp_list = tmp_list->next;
1700 current_selections = g_list_remove_link (current_selections, tmp_list);
1701 g_list_free (tmp_list);
1702 g_free (selection_info);
1709 /*************************************************************
1710 * _gtk_selection_request:
1711 * Handler for "selection_request_event"
1716 *************************************************************/
1719 _gtk_selection_request (GtkWidget *widget,
1720 GdkEventSelection *event)
1722 GdkDisplay *display = gtk_widget_get_display (widget);
1726 gulong selection_max_size;
1729 gtk_selection_init ();
1731 selection_max_size = GTK_SELECTION_MAX_SIZE (display);
1733 /* Check if we own selection */
1735 tmp_list = current_selections;
1738 GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data;
1740 if ((selection_info->selection == event->selection) &&
1741 (selection_info->widget == widget))
1744 tmp_list = tmp_list->next;
1747 if (tmp_list == NULL)
1750 info = g_new (GtkIncrInfo, 1);
1752 g_object_ref (widget);
1754 info->selection = event->selection;
1755 info->num_incrs = 0;
1757 /* Create GdkWindow structure for the requestor */
1759 info->requestor = gdk_window_lookup_for_display (display,
1761 if (!info->requestor)
1762 info->requestor = gdk_window_foreign_new_for_display (display,
1765 /* Determine conversions we need to perform */
1767 if (event->target == gtk_selection_atoms[MULTIPLE])
1776 gdk_error_trap_push ();
1777 if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */
1778 0, selection_max_size, FALSE,
1779 &type, &format, &length, &mult_atoms))
1781 gdk_selection_send_notify_for_display (display,
1787 g_free (mult_atoms);
1791 gdk_error_trap_pop ();
1793 /* This is annoying; the ICCCM doesn't specify the property type
1794 * used for the property contents, so the autoconversion for
1795 * ATOM / ATOM_PAIR in GDK doesn't work properly.
1797 #ifdef GDK_WINDOWING_X11
1798 if (type != GDK_SELECTION_TYPE_ATOM &&
1799 type != gdk_atom_intern ("ATOM_PAIR", FALSE))
1801 info->num_conversions = length / (2*sizeof (glong));
1802 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1804 for (i=0; i<info->num_conversions; i++)
1806 info->conversions[i].target = gdk_x11_xatom_to_atom_for_display (display,
1807 ((glong *)mult_atoms)[2*i]);
1808 info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display,
1809 ((glong *)mult_atoms)[2*i + 1]);
1815 info->num_conversions = length / (2*sizeof (GdkAtom));
1816 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
1818 for (i=0; i<info->num_conversions; i++)
1820 info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
1821 info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
1825 else /* only a single conversion */
1827 info->conversions = g_new (GtkIncrConversion, 1);
1828 info->num_conversions = 1;
1829 info->conversions[0].target = event->target;
1830 info->conversions[0].property = event->property;
1833 /* Loop through conversions and determine which of these are big
1834 enough to require doing them via INCR */
1835 for (i=0; i<info->num_conversions; i++)
1837 GtkSelectionData data;
1840 data.selection = event->selection;
1841 data.target = info->conversions[i].target;
1844 data.display = gtk_widget_get_display (widget);
1846 #ifdef DEBUG_SELECTION
1847 g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
1849 info->conversions[i].target,
1850 gdk_atom_name (info->conversions[i].target),
1851 event->requestor, info->conversions[i].property);
1854 gtk_selection_invoke_handler (widget, &data, event->time);
1856 if (data.length < 0)
1858 info->conversions[i].property = GDK_NONE;
1862 g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
1864 items = data.length / gtk_selection_bytes_per_item (data.format);
1866 if (data.length > selection_max_size)
1868 /* Sending via INCR */
1869 #ifdef DEBUG_SELECTION
1870 g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n",
1871 data.length, selection_max_size);
1874 info->conversions[i].offset = 0;
1875 info->conversions[i].data = data;
1878 gdk_property_change (info->requestor,
1879 info->conversions[i].property,
1880 gtk_selection_atoms[INCR],
1882 GDK_PROP_MODE_REPLACE,
1883 (guchar *)&items, 1);
1887 info->conversions[i].offset = -1;
1889 gdk_property_change (info->requestor,
1890 info->conversions[i].property,
1893 GDK_PROP_MODE_REPLACE,
1900 /* If we have some INCR's, we need to send the rest of the data in
1903 if (info->num_incrs > 0)
1905 /* FIXME: this could be dangerous if window doesn't still
1908 #ifdef DEBUG_SELECTION
1909 g_message ("Starting INCR...");
1912 gdk_window_set_events (info->requestor,
1913 gdk_window_get_events (info->requestor) |
1914 GDK_PROPERTY_CHANGE_MASK);
1915 current_incrs = g_list_append (current_incrs, info);
1916 g_timeout_add (1000, (GSourceFunc) gtk_selection_incr_timeout, info);
1919 /* If it was a MULTIPLE request, set the property to indicate which
1920 conversions succeeded */
1921 if (event->target == gtk_selection_atoms[MULTIPLE])
1923 GdkAtom *mult_atoms = g_new (GdkAtom, 2 * info->num_conversions);
1924 for (i = 0; i < info->num_conversions; i++)
1926 mult_atoms[2*i] = info->conversions[i].target;
1927 mult_atoms[2*i+1] = info->conversions[i].property;
1930 gdk_property_change (info->requestor, event->property,
1931 gdk_atom_intern ("ATOM_PAIR", FALSE), 32,
1932 GDK_PROP_MODE_REPLACE,
1933 (guchar *)mult_atoms, 2*info->num_conversions);
1934 g_free (mult_atoms);
1937 if (info->num_conversions == 1 &&
1938 info->conversions[0].property == GDK_NONE)
1940 /* Reject the entire conversion */
1941 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1950 gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
1958 if (info->num_incrs == 0)
1960 g_free (info->conversions);
1964 g_object_unref (widget);
1969 /*************************************************************
1970 * _gtk_selection_incr_event:
1971 * Called whenever an PropertyNotify event occurs for an
1972 * GdkWindow with user_data == NULL. These will be notifications
1973 * that a window we are sending the selection to via the
1974 * INCR protocol has deleted a property and is ready for
1978 * window: the requestor window
1979 * event: the property event structure
1982 *************************************************************/
1985 _gtk_selection_incr_event (GdkWindow *window,
1986 GdkEventProperty *event)
1989 GtkIncrInfo *info = NULL;
1992 gulong selection_max_size;
1996 if (event->state != GDK_PROPERTY_DELETE)
1999 #ifdef DEBUG_SELECTION
2000 g_message ("PropertyDelete, property %ld", event->atom);
2003 selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window));
2005 /* Now find the appropriate ongoing INCR */
2006 tmp_list = current_incrs;
2009 info = (GtkIncrInfo *)tmp_list->data;
2010 if (info->requestor == event->window)
2013 tmp_list = tmp_list->next;
2016 if (tmp_list == NULL)
2019 /* Find out which target this is for */
2020 for (i=0; i<info->num_conversions; i++)
2022 if (info->conversions[i].property == event->atom &&
2023 info->conversions[i].offset != -1)
2027 info->idle_time = 0;
2029 if (info->conversions[i].offset == -2) /* only the last 0-length
2037 num_bytes = info->conversions[i].data.length -
2038 info->conversions[i].offset;
2039 buffer = info->conversions[i].data.data +
2040 info->conversions[i].offset;
2042 if (num_bytes > selection_max_size)
2044 num_bytes = selection_max_size;
2045 info->conversions[i].offset += selection_max_size;
2048 info->conversions[i].offset = -2;
2050 #ifdef DEBUG_SELECTION
2051 g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
2052 num_bytes, info->conversions[i].offset,
2053 GDK_WINDOW_XWINDOW(info->requestor), event->atom);
2056 bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
2057 gdk_property_change (info->requestor, event->atom,
2058 info->conversions[i].data.type,
2059 info->conversions[i].data.format,
2060 GDK_PROP_MODE_REPLACE,
2062 num_bytes / bytes_per_item);
2064 if (info->conversions[i].offset == -2)
2066 g_free (info->conversions[i].data.data);
2067 info->conversions[i].data.data = NULL;
2073 info->conversions[i].offset = -1;
2078 /* Check if we're finished with all the targets */
2080 if (info->num_incrs == 0)
2082 current_incrs = g_list_remove_link (current_incrs, tmp_list);
2083 g_list_free (tmp_list);
2084 /* Let the timeout free it */
2090 /*************************************************************
2091 * gtk_selection_incr_timeout:
2092 * Timeout callback for the sending portion of the INCR
2095 * info: Information about this incr
2097 *************************************************************/
2100 gtk_selection_incr_timeout (GtkIncrInfo *info)
2105 GDK_THREADS_ENTER ();
2107 /* Determine if retrieval has finished by checking if it still in
2108 list of pending retrievals */
2110 tmp_list = current_incrs;
2113 if (info == (GtkIncrInfo *)tmp_list->data)
2115 tmp_list = tmp_list->next;
2118 /* If retrieval is finished */
2119 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2121 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2123 current_incrs = g_list_remove_link (current_incrs, tmp_list);
2124 g_list_free (tmp_list);
2127 g_free (info->conversions);
2128 /* FIXME: we should check if requestor window is still in use,
2129 and if not, remove it? */
2133 retval = FALSE; /* remove timeout */
2139 retval = TRUE; /* timeout will happen again */
2142 GDK_THREADS_LEAVE ();
2147 /*************************************************************
2148 * _gtk_selection_notify:
2149 * Handler for "selection_notify_event" signals on windows
2150 * where a retrieval is currently in process. The selection
2151 * owner has responded to our conversion request.
2153 * widget: Widget getting signal
2154 * event: Selection event structure
2155 * info: Information about this retrieval
2157 * was event handled?
2158 *************************************************************/
2161 _gtk_selection_notify (GtkWidget *widget,
2162 GdkEventSelection *event)
2165 GtkRetrievalInfo *info = NULL;
2166 guchar *buffer = NULL;
2171 #ifdef DEBUG_SELECTION
2172 g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
2173 event->selection, event->target, event->property);
2176 tmp_list = current_retrievals;
2179 info = (GtkRetrievalInfo *)tmp_list->data;
2180 if (info->widget == widget && info->selection == event->selection)
2182 tmp_list = tmp_list->next;
2185 if (!tmp_list) /* no retrieval in progress */
2188 if (event->property != GDK_NONE)
2189 length = gdk_selection_property_get (widget->window, &buffer,
2192 length = 0; /* silence gcc */
2194 if (event->property == GDK_NONE || buffer == NULL)
2196 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2197 g_list_free (tmp_list);
2198 /* structure will be freed in timeout */
2199 gtk_selection_retrieval_report (info,
2200 GDK_NONE, 0, NULL, -1, event->time);
2205 if (type == gtk_selection_atoms[INCR])
2207 /* The remainder of the selection will come through PropertyNotify
2210 info->notify_time = event->time;
2211 info->idle_time = 0;
2212 info->offset = 0; /* Mark as OK to proceed */
2213 gdk_window_set_events (widget->window,
2214 gdk_window_get_events (widget->window)
2215 | GDK_PROPERTY_CHANGE_MASK);
2219 /* We don't delete the info structure - that will happen in timeout */
2220 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2221 g_list_free (tmp_list);
2223 info->offset = length;
2224 gtk_selection_retrieval_report (info,
2226 buffer, length, event->time);
2229 gdk_property_delete (widget->window, event->property);
2236 /*************************************************************
2237 * _gtk_selection_property_notify:
2238 * Handler for "property_notify_event" signals on windows
2239 * where a retrieval is currently in process. The selection
2240 * owner has added more data.
2242 * widget: Widget getting signal
2243 * event: Property event structure
2244 * info: Information about this retrieval
2246 * was event handled?
2247 *************************************************************/
2250 _gtk_selection_property_notify (GtkWidget *widget,
2251 GdkEventProperty *event)
2254 GtkRetrievalInfo *info = NULL;
2260 g_return_val_if_fail (widget != NULL, FALSE);
2261 g_return_val_if_fail (event != NULL, FALSE);
2263 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
2264 if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */
2265 (event->atom != gdk_atom_intern ("GDK_SELECTION", FALSE))) /* not the right property */
2269 #ifdef DEBUG_SELECTION
2270 g_message ("PropertyNewValue, property %ld",
2274 tmp_list = current_retrievals;
2277 info = (GtkRetrievalInfo *)tmp_list->data;
2278 if (info->widget == widget)
2280 tmp_list = tmp_list->next;
2283 if (!tmp_list) /* No retrieval in progress */
2286 if (info->offset < 0) /* We haven't got the SelectionNotify
2287 for this retrieval yet */
2290 info->idle_time = 0;
2292 length = gdk_selection_property_get (widget->window, &new_buffer,
2294 gdk_property_delete (widget->window, event->atom);
2296 /* We could do a lot better efficiency-wise by paying attention to
2297 what length was sent in the initial INCR transaction, instead of
2298 doing memory allocation at every step. But its only guaranteed to
2299 be a _lower bound_ (pretty useless!) */
2301 if (length == 0 || type == GDK_NONE) /* final zero length portion */
2303 /* Info structure will be freed in timeout */
2304 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2305 g_list_free (tmp_list);
2306 gtk_selection_retrieval_report (info,
2308 (type == GDK_NONE) ? NULL : info->buffer,
2309 (type == GDK_NONE) ? -1 : info->offset,
2312 else /* append on newly arrived data */
2316 #ifdef DEBUG_SELECTION
2317 g_message ("Start - Adding %d bytes at offset 0",
2320 info->buffer = new_buffer;
2321 info->offset = length;
2326 #ifdef DEBUG_SELECTION
2327 g_message ("Appending %d bytes at offset %d",
2328 length,info->offset);
2330 /* We copy length+1 bytes to preserve guaranteed null termination */
2331 info->buffer = g_realloc (info->buffer, info->offset+length+1);
2332 memcpy (info->buffer + info->offset, new_buffer, length+1);
2333 info->offset += length;
2334 g_free (new_buffer);
2341 /*************************************************************
2342 * gtk_selection_retrieval_timeout:
2343 * Timeout callback while receiving a selection.
2345 * info: Information about this retrieval
2347 *************************************************************/
2350 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
2355 GDK_THREADS_ENTER ();
2357 /* Determine if retrieval has finished by checking if it still in
2358 list of pending retrievals */
2360 tmp_list = current_retrievals;
2363 if (info == (GtkRetrievalInfo *)tmp_list->data)
2365 tmp_list = tmp_list->next;
2368 /* If retrieval is finished */
2369 if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
2371 if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
2373 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
2374 g_list_free (tmp_list);
2375 gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
2378 g_free (info->buffer);
2381 retval = FALSE; /* remove timeout */
2387 retval = TRUE; /* timeout will happen again */
2390 GDK_THREADS_LEAVE ();
2395 /*************************************************************
2396 * gtk_selection_retrieval_report:
2397 * Emits a "selection_received" signal.
2399 * info: information about the retrieval that completed
2400 * buffer: buffer containing data (NULL => errror)
2401 * time: timestamp for data in buffer
2403 *************************************************************/
2406 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
2407 GdkAtom type, gint format,
2408 guchar *buffer, gint length,
2411 GtkSelectionData data;
2413 data.selection = info->selection;
2414 data.target = info->target;
2416 data.format = format;
2418 data.length = length;
2420 data.display = gtk_widget_get_display (info->widget);
2422 g_signal_emit_by_name (info->widget,
2423 "selection_received",
2427 /*************************************************************
2428 * gtk_selection_invoke_handler:
2429 * Finds and invokes handler for specified
2430 * widget/selection/target combination, calls
2431 * gtk_selection_default_handler if none exists.
2434 * widget: selection owner
2435 * data: selection data [INOUT]
2436 * time: time from requeset
2439 * Number of bytes written to buffer, -1 if error
2440 *************************************************************/
2443 gtk_selection_invoke_handler (GtkWidget *widget,
2444 GtkSelectionData *data,
2447 GtkTargetList *target_list;
2451 g_return_if_fail (widget != NULL);
2453 target_list = gtk_selection_target_list_get (widget, data->selection);
2455 gtk_target_list_find (target_list, data->target, &info))
2457 g_signal_emit_by_name (widget,
2463 gtk_selection_default_handler (widget, data);
2466 /*************************************************************
2467 * gtk_selection_default_handler:
2468 * Handles some default targets that exist for any widget
2469 * If it can't fit results into buffer, returns -1. This
2470 * won't happen in any conceivable case, since it would
2471 * require 1000 selection targets!
2474 * widget: selection owner
2475 * data: selection data [INOUT]
2477 *************************************************************/
2480 gtk_selection_default_handler (GtkWidget *widget,
2481 GtkSelectionData *data)
2483 if (data->target == gtk_selection_atoms[TIMESTAMP])
2485 /* Time which was used to obtain selection */
2487 GtkSelectionInfo *selection_info;
2489 tmp_list = current_selections;
2492 selection_info = (GtkSelectionInfo *)tmp_list->data;
2493 if ((selection_info->widget == widget) &&
2494 (selection_info->selection == data->selection))
2496 gulong time = selection_info->time;
2498 gtk_selection_data_set (data,
2499 GDK_SELECTION_TYPE_INTEGER,
2506 tmp_list = tmp_list->next;
2511 else if (data->target == gtk_selection_atoms[TARGETS])
2513 /* List of all targets supported for this widget/selection pair */
2517 GtkTargetList *target_list;
2518 GtkTargetPair *pair;
2520 target_list = gtk_selection_target_list_get (widget,
2522 count = g_list_length (target_list->list) + 3;
2524 data->type = GDK_SELECTION_TYPE_ATOM;
2526 data->length = count * sizeof (GdkAtom);
2528 /* selection data is always terminated by a trailing \0
2530 p = g_malloc (data->length + 1);
2531 data->data = (guchar *)p;
2532 data->data[data->length] = '\0';
2534 *p++ = gtk_selection_atoms[TIMESTAMP];
2535 *p++ = gtk_selection_atoms[TARGETS];
2536 *p++ = gtk_selection_atoms[MULTIPLE];
2538 tmp_list = target_list->list;
2541 pair = (GtkTargetPair *)tmp_list->data;
2542 *p++ = pair->target;
2544 tmp_list = tmp_list->next;
2555 * gtk_selection_data_copy:
2556 * @selection_data: a pointer to a #GtkSelectionData structure.
2558 * Makes a copy of a #GtkSelectionData structure and its data.
2560 * Return value: a pointer to a copy of @data.
2563 gtk_selection_data_copy (GtkSelectionData *selection_data)
2565 GtkSelectionData *new_data;
2567 g_return_val_if_fail (selection_data != NULL, NULL);
2569 new_data = g_new (GtkSelectionData, 1);
2570 *new_data = *selection_data;
2572 if (selection_data->data)
2574 new_data->data = g_malloc (selection_data->length + 1);
2575 memcpy (new_data->data, selection_data->data, selection_data->length + 1);
2582 * gtk_selection_data_free:
2583 * @data: a pointer to a #GtkSelectionData structure.
2585 * Frees a #GtkSelectionData structure returned from
2586 * gtk_selection_data_copy().
2589 gtk_selection_data_free (GtkSelectionData *data)
2591 g_return_if_fail (data != NULL);
2594 g_free (data->data);
2600 gtk_selection_data_get_type (void)
2602 static GType our_type = 0;
2605 our_type = g_boxed_type_register_static ("GtkSelectionData",
2606 (GBoxedCopyFunc) gtk_selection_data_copy,
2607 (GBoxedFreeFunc) gtk_selection_data_free);
2613 gtk_selection_bytes_per_item (gint format)
2618 return sizeof (char);
2621 return sizeof (short);
2624 return sizeof (long);
2627 g_assert_not_reached();
2632 #define __GTK_SELECTION_C__
2633 #include "gtkaliasdef.c"