1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 /* This file implements most of the work of the ICCM selection protocol.
21 * The code was written after an intensive study of the equivalent part
22 * of John Ousterhout's Tk toolkit, and does many things in much the
25 * The one thing in the ICCM that isn't fully supported here (or in Tk)
26 * is side effects targets. For these to be handled properly, MULTIPLE
27 * targets need to be done in the order specified. This cannot be
28 * guaranteed with the way we do things, since if we are doing INCR
29 * transfers, the order will depend on the timing of the requestor.
31 * By Owen Taylor <owt1@cornell.edu> 8/16/97
34 /* Terminology note: when not otherwise specified, the term "incr" below
35 * refers to the _sending_ part of the INCR protocol. The receiving
36 * portion is referred to just as "retrieval". (Terminology borrowed
37 * from Tk, because there is no good opposite to "retrieval" in English.
38 * "send" can't be made into a noun gracefully and we're already using
39 * "emission" for something else ....)
42 /* The MOTIF entry widget seems to ask for the TARGETS target, then
43 (regardless of the reply) ask for the TEXT target. It's slightly
44 possible though that it somehow thinks we are responding negatively
45 to the TARGETS request, though I don't really think so ... */
48 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
49 * file for a list of people on the GTK+ Team. See the ChangeLog
50 * files for a list of changes. These files are distributed with
51 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
58 #if defined (GDK_WINDOWING_X11)
59 #include "x11/gdkx.h" /* For gdk_window_lookup() */
60 #elif defined (GDK_WINDOWING_WIN32)
61 #include "win32/gdkwin32.h" /* For gdk_window_lookup() */
62 #elif defined (GDK_WINDOWING_NANOX)
63 #include "nanox/gdkprivate-nanox.h" /* For gdk_window_lookup() */
67 #include "gtkselection.h"
68 #include "gtksignal.h"
70 /* #define DEBUG_SELECTION */
72 /* Maximum size of a sent chunk, in bytes. Also the default size of
74 #ifdef GDK_WINDOWING_WIN32
75 /* No chunks on Win32 */
76 #define GTK_SELECTION_MAX_SIZE G_MAXINT
78 #define GTK_SELECTION_MAX_SIZE 4000
88 typedef struct _GtkSelectionInfo GtkSelectionInfo;
89 typedef struct _GtkIncrConversion GtkIncrConversion;
90 typedef struct _GtkIncrInfo GtkIncrInfo;
91 typedef struct _GtkRetrievalInfo GtkRetrievalInfo;
93 struct _GtkSelectionInfo
96 GtkWidget *widget; /* widget that owns selection */
97 guint32 time; /* time used to acquire selection */
100 struct _GtkIncrConversion
102 GdkAtom target; /* Requested target */
103 GdkAtom property; /* Property to store in */
104 GtkSelectionData data; /* The data being supplied */
105 gint offset; /* Current offset in sent selection.
107 * -2 => Only the final (empty) portion
113 GtkWidget *widget; /* Selection owner */
114 GdkWindow *requestor; /* Requestor window - we create a GdkWindow
115 so we can receive events */
116 GdkAtom selection; /* Selection we're sending */
118 GtkIncrConversion *conversions; /* Information about requested conversions -
119 * With MULTIPLE requests (benighted 1980's
120 * hardware idea), there can be more than
122 gint num_conversions;
123 gint num_incrs; /* number of remaining INCR style transactions */
128 struct _GtkRetrievalInfo
131 GdkAtom selection; /* Selection being retrieved. */
132 GdkAtom target; /* Form of selection that we requested */
133 guint32 idle_time; /* Number of seconds since we last heard
134 from selection owner */
135 guchar *buffer; /* Buffer in which to accumulate results */
136 gint offset; /* Current offset in buffer, -1 indicates
138 guint32 notify_time; /* Timestamp from SelectionNotify */
141 /* Local Functions */
142 static void gtk_selection_init (void);
143 static gint gtk_selection_incr_timeout (GtkIncrInfo *info);
144 static gint gtk_selection_retrieval_timeout (GtkRetrievalInfo *info);
145 static void gtk_selection_retrieval_report (GtkRetrievalInfo *info,
151 static void gtk_selection_invoke_handler (GtkWidget *widget,
152 GtkSelectionData *data,
154 static void gtk_selection_default_handler (GtkWidget *widget,
155 GtkSelectionData *data);
156 static int gtk_selection_bytes_per_item (gint format);
159 static gint initialize = TRUE;
160 static GList *current_retrievals = NULL;
161 static GList *current_incrs = NULL;
162 static GList *current_selections = NULL;
164 static GdkAtom gtk_selection_atoms[LAST_ATOM];
165 static const char *gtk_selection_handler_key = "gtk-selection-handlers";
176 gtk_target_list_new (const GtkTargetEntry *targets,
179 GtkTargetList *result = g_new (GtkTargetList, 1);
181 result->ref_count = 1;
184 gtk_target_list_add_table (result, targets, ntargets);
190 gtk_target_list_ref (GtkTargetList *list)
192 g_return_if_fail (list != NULL);
198 gtk_target_list_unref (GtkTargetList *list)
200 g_return_if_fail (list != NULL);
201 g_return_if_fail (list->ref_count > 0);
204 if (list->ref_count == 0)
206 GList *tmp_list = list->list;
209 GtkTargetPair *pair = tmp_list->data;
212 tmp_list = tmp_list->next;
215 g_list_free (list->list);
221 gtk_target_list_add (GtkTargetList *list,
228 g_return_if_fail (list != NULL);
230 pair = g_new (GtkTargetPair, 1);
231 pair->target = target;
235 list->list = g_list_append (list->list, pair);
239 gtk_target_list_add_table (GtkTargetList *list,
240 const GtkTargetEntry *targets,
245 for (i=ntargets-1; i >= 0; i--)
247 GtkTargetPair *pair = g_new (GtkTargetPair, 1);
248 pair->target = gdk_atom_intern (targets[i].target, FALSE);
249 pair->flags = targets[i].flags;
250 pair->info = targets[i].info;
252 list->list = g_list_prepend (list->list, pair);
257 gtk_target_list_remove (GtkTargetList *list,
262 g_return_if_fail (list != NULL);
264 tmp_list = list->list;
267 GtkTargetPair *pair = tmp_list->data;
269 if (pair->target == target)
273 list->list = g_list_remove_link (list->list, tmp_list);
274 g_list_free_1 (tmp_list);
279 tmp_list = tmp_list->next;
284 gtk_target_list_find (GtkTargetList *list,
288 GList *tmp_list = list->list;
291 GtkTargetPair *pair = tmp_list->data;
293 if (pair->target == target)
298 tmp_list = tmp_list->next;
305 /*************************************************************
306 * gtk_selection_owner_set:
307 * Claim ownership of a selection.
309 * widget: new selection owner
310 * selection: which selection
311 * time: time (use GDK_CURRENT_TIME only if necessary)
314 *************************************************************/
317 gtk_selection_owner_set (GtkWidget *widget,
322 GtkWidget *old_owner;
323 GtkSelectionInfo *selection_info = NULL;
330 if (!GTK_WIDGET_REALIZED (widget))
331 gtk_widget_realize (widget);
333 window = widget->window;
336 tmp_list = current_selections;
339 selection_info = (GtkSelectionInfo *)tmp_list->data;
341 if (selection_info->selection == selection)
344 tmp_list = tmp_list->next;
347 if (tmp_list == NULL)
348 selection_info = NULL;
350 if (selection_info->widget == widget)
353 if (gdk_selection_owner_set (window, selection, time, TRUE))
361 old_owner = selection_info->widget;
362 current_selections = g_list_remove_link (current_selections,
364 g_list_free (tmp_list);
365 g_free (selection_info);
370 if (selection_info == NULL)
372 selection_info = g_new (GtkSelectionInfo, 1);
373 selection_info->selection = selection;
374 selection_info->widget = widget;
375 selection_info->time = time;
376 current_selections = g_list_append (current_selections,
381 old_owner = selection_info->widget;
382 selection_info->widget = widget;
383 selection_info->time = time;
386 /* If another widget in the application lost the selection,
387 * send it a GDK_SELECTION_CLEAR event, unless we're setting
388 * the owner to None, in which case an event will be sent */
389 if (old_owner && (widget != NULL))
391 GdkEventSelection event;
393 event.type = GDK_SELECTION_CLEAR;
394 event.window = old_owner->window;
395 event.selection = selection;
398 gtk_widget_event (old_owner, (GdkEvent *) &event);
406 /*************************************************************
407 * gtk_selection_add_target
408 * Add specified target to list of supported targets
411 * widget: The widget for which this target applies
414 * info: guint to pass to to the selection_get signal
417 *************************************************************/
419 typedef struct _GtkSelectionTargetList GtkSelectionTargetList;
421 struct _GtkSelectionTargetList {
426 static GtkTargetList *
427 gtk_selection_target_list_get (GtkWidget *widget,
430 GtkSelectionTargetList *sellist;
434 lists = gtk_object_get_data (GTK_OBJECT (widget), gtk_selection_handler_key);
439 sellist = tmp_list->data;
440 if (sellist->selection == selection)
441 return sellist->list;
442 tmp_list = tmp_list->next;
445 sellist = g_new (GtkSelectionTargetList, 1);
446 sellist->selection = selection;
447 sellist->list = gtk_target_list_new (NULL, 0);
449 lists = g_list_prepend (lists, sellist);
450 gtk_object_set_data (GTK_OBJECT (widget), gtk_selection_handler_key, lists);
452 return sellist->list;
456 gtk_selection_target_list_remove (GtkWidget *widget)
458 GtkSelectionTargetList *sellist;
462 lists = gtk_object_get_data (GTK_OBJECT (widget), gtk_selection_handler_key);
467 sellist = tmp_list->data;
469 gtk_target_list_unref (sellist->list);
472 tmp_list = tmp_list->next;
476 gtk_object_set_data (GTK_OBJECT (widget), gtk_selection_handler_key, NULL);
480 gtk_selection_add_target (GtkWidget *widget,
487 g_return_if_fail (widget != NULL);
489 list = gtk_selection_target_list_get (widget, selection);
490 gtk_target_list_add (list, target, 0, info);
494 gtk_selection_add_targets (GtkWidget *widget,
496 const GtkTargetEntry *targets,
501 g_return_if_fail (widget != NULL);
502 g_return_if_fail (targets != NULL);
504 list = gtk_selection_target_list_get (widget, selection);
505 gtk_target_list_add_table (list, targets, ntargets);
508 /*************************************************************
509 * gtk_selection_remove_all:
510 * Removes all handlers and unsets ownership of all
511 * selections for a widget. Called when widget is being
517 *************************************************************/
520 gtk_selection_remove_all (GtkWidget *widget)
524 GtkSelectionInfo *selection_info;
526 /* Remove pending requests/incrs for this widget */
528 tmp_list = current_incrs;
531 next = tmp_list->next;
532 if (((GtkIncrInfo *)tmp_list->data)->widget == widget)
534 current_incrs = g_list_remove_link (current_incrs, tmp_list);
535 /* structure will be freed in timeout */
536 g_list_free (tmp_list);
541 tmp_list = current_retrievals;
544 next = tmp_list->next;
545 if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget)
547 current_retrievals = g_list_remove_link (current_retrievals,
549 /* structure will be freed in timeout */
550 g_list_free (tmp_list);
555 /* Disclaim ownership of any selections */
557 tmp_list = current_selections;
560 next = tmp_list->next;
561 selection_info = (GtkSelectionInfo *)tmp_list->data;
563 if (selection_info->widget == widget)
565 gdk_selection_owner_set (NULL,
566 selection_info->selection,
567 GDK_CURRENT_TIME, FALSE);
568 current_selections = g_list_remove_link (current_selections,
570 g_list_free (tmp_list);
571 g_free (selection_info);
577 /* Remove all selection lists */
578 gtk_selection_target_list_remove (widget);
581 /*************************************************************
582 * gtk_selection_convert:
583 * Request the contents of a selection. When received,
584 * a "selection_received" signal will be generated.
587 * widget: The widget which acts as requestor
588 * selection: Which selection to get
589 * target: Form of information desired (e.g., STRING)
590 * time: Time of request (usually of triggering event)
591 * In emergency, you could use GDK_CURRENT_TIME
594 * TRUE if requested succeeded. FALSE if we could not process
595 * request. (e.g., there was already a request in process for
597 *************************************************************/
600 gtk_selection_convert (GtkWidget *widget,
605 GtkRetrievalInfo *info;
607 GdkWindow *owner_window;
609 g_return_val_if_fail (widget != NULL, FALSE);
612 gtk_selection_init ();
614 if (!GTK_WIDGET_REALIZED (widget))
615 gtk_widget_realize (widget);
617 /* Check to see if there are already any retrievals in progress for
618 this widget. If we changed GDK to use the selection for the
619 window property in which to store the retrieved information, then
620 we could support multiple retrievals for different selections.
621 This might be useful for DND. */
623 tmp_list = current_retrievals;
626 info = (GtkRetrievalInfo *)tmp_list->data;
627 if (info->widget == widget)
629 tmp_list = tmp_list->next;
632 info = g_new (GtkRetrievalInfo, 1);
634 info->widget = widget;
635 info->selection = selection;
636 info->target = target;
640 /* Check if this process has current owner. If so, call handler
641 procedure directly to avoid deadlocks with INCR. */
643 owner_window = gdk_selection_owner_get (selection);
645 if (owner_window != NULL)
647 GtkWidget *owner_widget;
648 GtkSelectionData selection_data;
650 selection_data.selection = selection;
651 selection_data.target = target;
652 selection_data.data = NULL;
653 selection_data.length = -1;
655 gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget);
657 if (owner_widget != NULL)
659 gtk_selection_invoke_handler (owner_widget,
663 gtk_selection_retrieval_report (info,
665 selection_data.format,
667 selection_data.length,
670 g_free (selection_data.data);
677 /* Otherwise, we need to go through X */
679 current_retrievals = g_list_append (current_retrievals, info);
680 gdk_selection_convert (widget->window, selection, target, time);
681 gtk_timeout_add (1000, (GtkFunction) gtk_selection_retrieval_timeout, info);
686 /*************************************************************
687 * gtk_selection_data_set:
688 * Store new data into a GtkSelectionData object. Should
689 * _only_ by called from a selection handler callback.
690 * Null terminates the stored data.
692 * type: the type of selection data
693 * format: format (number of bits in a unit)
694 * data: pointer to the data (will be copied)
695 * length: length of the data
697 *************************************************************/
700 gtk_selection_data_set (GtkSelectionData *selection_data,
706 if (selection_data->data)
707 g_free (selection_data->data);
709 selection_data->type = type;
710 selection_data->format = format;
714 selection_data->data = g_new (guchar, length+1);
715 memcpy (selection_data->data, data, length);
716 selection_data->data[length] = 0;
720 g_return_if_fail (length <= 0);
723 selection_data->data = NULL;
725 selection_data->data = g_strdup("");
728 selection_data->length = length;
731 /*************************************************************
732 * gtk_selection_init:
733 * Initialize local variables
737 *************************************************************/
740 gtk_selection_init (void)
742 gtk_selection_atoms[INCR] = gdk_atom_intern ("INCR", FALSE);
743 gtk_selection_atoms[MULTIPLE] = gdk_atom_intern ("MULTIPLE", FALSE);
744 gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern ("TIMESTAMP", FALSE);
745 gtk_selection_atoms[TARGETS] = gdk_atom_intern ("TARGETS", FALSE);
748 /*************************************************************
749 * gtk_selection_clear:
750 * Handler for "selection_clear_event"
755 *************************************************************/
758 gtk_selection_clear (GtkWidget *widget,
759 GdkEventSelection *event)
761 /* FIXME: there can be a problem if we change the selection
762 via gtk_selection_owner_set after another client claims
763 the selection, but before we get the notification event.
764 Tk filters based on serial #'s, which aren't retained by
765 GTK. Filtering based on time's will be inherently
766 somewhat unreliable. */
769 GtkSelectionInfo *selection_info = NULL;
771 tmp_list = current_selections;
774 selection_info = (GtkSelectionInfo *)tmp_list->data;
776 if ((selection_info->selection == event->selection) &&
777 (selection_info->widget == widget))
780 tmp_list = tmp_list->next;
785 if (selection_info->time > event->time)
786 return FALSE; /* return FALSE to indicate that
787 * the selection was out of date,
788 * and this clear should be ignored */
791 current_selections = g_list_remove_link (current_selections, tmp_list);
792 g_list_free (tmp_list);
793 g_free (selection_info);
801 /*************************************************************
802 * gtk_selection_request:
803 * Handler for "selection_request_event"
808 *************************************************************/
811 gtk_selection_request (GtkWidget *widget,
812 GdkEventSelection *event)
820 gtk_selection_init ();
822 /* Check if we own selection */
824 tmp_list = current_selections;
827 GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data;
829 if ((selection_info->selection == event->selection) &&
830 (selection_info->widget == widget))
833 tmp_list = tmp_list->next;
836 if (tmp_list == NULL)
839 info = g_new(GtkIncrInfo, 1);
841 info->widget = widget;
842 info->selection = event->selection;
845 /* Create GdkWindow structure for the requestor */
847 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
848 info->requestor = gdk_window_lookup (event->requestor);
849 if (!info->requestor)
850 info->requestor = gdk_window_foreign_new (event->requestor);
852 info->requestor = NULL;
855 /* Determine conversions we need to perform */
857 if (event->target == gtk_selection_atoms[MULTIPLE])
865 gdk_error_trap_push();
866 if (!gdk_property_get (info->requestor, event->property, 0, /* AnyPropertyType */
867 0, GTK_SELECTION_MAX_SIZE, FALSE,
868 &type, &format, &length, &mult_atoms))
870 gdk_selection_send_notify (event->requestor, event->selection,
871 event->target, GDK_NONE, event->time);
876 gdk_error_trap_pop();
878 info->num_conversions = length / (2*sizeof (GdkAtom));
879 info->conversions = g_new (GtkIncrConversion, info->num_conversions);
881 for (i=0; i<info->num_conversions; i++)
883 info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
884 info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
887 else /* only a single conversion */
889 info->conversions = g_new (GtkIncrConversion, 1);
890 info->num_conversions = 1;
891 info->conversions[0].target = event->target;
892 info->conversions[0].property = event->property;
893 mult_atoms = (guchar *)info->conversions;
896 /* Loop through conversions and determine which of these are big
897 enough to require doing them via INCR */
898 for (i=0; i<info->num_conversions; i++)
900 GtkSelectionData data;
903 data.selection = event->selection;
904 data.target = info->conversions[i].target;
908 #ifdef DEBUG_SELECTION
909 g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
910 event->selection, info->conversions[i].target,
911 gdk_atom_name(info->conversions[i].target),
912 event->requestor, event->property);
915 gtk_selection_invoke_handler (widget, &data, event->time);
919 ((GdkAtom *)mult_atoms)[2*i+1] = GDK_NONE;
920 info->conversions[i].property = GDK_NONE;
924 g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
926 items = data.length / gtk_selection_bytes_per_item (data.format);
928 if (data.length > GTK_SELECTION_MAX_SIZE)
930 /* Sending via INCR */
932 info->conversions[i].offset = 0;
933 info->conversions[i].data = data;
936 gdk_property_change (info->requestor,
937 info->conversions[i].property,
938 gtk_selection_atoms[INCR],
940 GDK_PROP_MODE_REPLACE,
941 (guchar *)&items, 1);
945 info->conversions[i].offset = -1;
947 gdk_property_change (info->requestor,
948 info->conversions[i].property,
951 GDK_PROP_MODE_REPLACE,
958 /* If we have some INCR's, we need to send the rest of the data in
961 if (info->num_incrs > 0)
963 /* FIXME: this could be dangerous if window doesn't still
966 #ifdef DEBUG_SELECTION
967 g_message ("Starting INCR...");
970 gdk_window_set_events (info->requestor,
971 gdk_window_get_events (info->requestor) |
972 GDK_PROPERTY_CHANGE_MASK);
973 current_incrs = g_list_append (current_incrs, info);
974 gtk_timeout_add (1000, (GtkFunction)gtk_selection_incr_timeout, info);
977 /* If it was a MULTIPLE request, set the property to indicate which
978 conversions succeeded */
979 if (event->target == gtk_selection_atoms[MULTIPLE])
981 gdk_property_change (info->requestor, event->property,
982 GDK_SELECTION_TYPE_ATOM, 32,
983 GDK_PROP_MODE_REPLACE,
984 mult_atoms, 2*info->num_conversions);
988 if (info->num_conversions == 1 &&
989 info->conversions[0].property == GDK_NONE)
991 /* Reject the entire conversion */
992 gdk_selection_send_notify (event->requestor, event->selection,
993 event->target, GDK_NONE, event->time);
997 gdk_selection_send_notify (event->requestor, event->selection,
998 event->target, event->property, event->time);
1001 if (info->num_incrs == 0)
1003 g_free (info->conversions);
1010 /*************************************************************
1011 * gtk_selection_incr_event:
1012 * Called whenever an PropertyNotify event occurs for an
1013 * GdkWindow with user_data == NULL. These will be notifications
1014 * that a window we are sending the selection to via the
1015 * INCR protocol has deleted a property and is ready for
1019 * window: the requestor window
1020 * event: the property event structure
1023 *************************************************************/
1026 gtk_selection_incr_event (GdkWindow *window,
1027 GdkEventProperty *event)
1030 GtkIncrInfo *info = NULL;
1036 if (event->state != GDK_PROPERTY_DELETE)
1039 #ifdef DEBUG_SELECTION
1040 g_message ("PropertyDelete, property %ld", event->atom);
1043 /* Now find the appropriate ongoing INCR */
1044 tmp_list = current_incrs;
1047 info = (GtkIncrInfo *)tmp_list->data;
1048 if (info->requestor == event->window)
1051 tmp_list = tmp_list->next;
1054 if (tmp_list == NULL)
1057 /* Find out which target this is for */
1058 for (i=0; i<info->num_conversions; i++)
1060 if (info->conversions[i].property == event->atom &&
1061 info->conversions[i].offset != -1)
1065 info->idle_time = 0;
1067 if (info->conversions[i].offset == -2) /* only the last 0-length
1075 num_bytes = info->conversions[i].data.length -
1076 info->conversions[i].offset;
1077 buffer = info->conversions[i].data.data +
1078 info->conversions[i].offset;
1080 if (num_bytes > GTK_SELECTION_MAX_SIZE)
1082 num_bytes = GTK_SELECTION_MAX_SIZE;
1083 info->conversions[i].offset += GTK_SELECTION_MAX_SIZE;
1086 info->conversions[i].offset = -2;
1088 #ifdef DEBUG_SELECTION
1089 g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld",
1090 num_bytes, info->conversions[i].offset,
1091 GDK_WINDOW_XWINDOW(info->requestor), event->atom);
1094 bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
1095 gdk_property_change (info->requestor, event->atom,
1096 info->conversions[i].data.type,
1097 info->conversions[i].data.format,
1098 GDK_PROP_MODE_REPLACE,
1100 num_bytes / bytes_per_item);
1102 if (info->conversions[i].offset == -2)
1104 g_free (info->conversions[i].data.data);
1105 info->conversions[i].data.data = NULL;
1111 info->conversions[i].offset = -1;
1117 /* Check if we're finished with all the targets */
1119 if (info->num_incrs == 0)
1121 current_incrs = g_list_remove_link (current_incrs, tmp_list);
1122 g_list_free (tmp_list);
1123 /* Let the timeout free it */
1129 /*************************************************************
1130 * gtk_selection_incr_timeout:
1131 * Timeout callback for the sending portion of the INCR
1134 * info: Information about this incr
1136 *************************************************************/
1139 gtk_selection_incr_timeout (GtkIncrInfo *info)
1144 GDK_THREADS_ENTER ();
1146 /* Determine if retrieval has finished by checking if it still in
1147 list of pending retrievals */
1149 tmp_list = current_incrs;
1152 if (info == (GtkIncrInfo *)tmp_list->data)
1154 tmp_list = tmp_list->next;
1157 /* If retrieval is finished */
1158 if (!tmp_list || info->idle_time >= 5)
1160 if (tmp_list && info->idle_time >= 5)
1162 current_incrs = g_list_remove_link (current_incrs, tmp_list);
1163 g_list_free (tmp_list);
1166 g_free (info->conversions);
1167 /* FIXME: we should check if requestor window is still in use,
1168 and if not, remove it? */
1172 retval = FALSE; /* remove timeout */
1178 retval = TRUE; /* timeout will happen again */
1181 GDK_THREADS_LEAVE ();
1186 /*************************************************************
1187 * gtk_selection_notify:
1188 * Handler for "selection_notify_event" signals on windows
1189 * where a retrieval is currently in process. The selection
1190 * owner has responded to our conversion request.
1192 * widget: Widget getting signal
1193 * event: Selection event structure
1194 * info: Information about this retrieval
1196 * was event handled?
1197 *************************************************************/
1200 gtk_selection_notify (GtkWidget *widget,
1201 GdkEventSelection *event)
1204 GtkRetrievalInfo *info = NULL;
1205 guchar *buffer = NULL;
1210 #ifdef DEBUG_SELECTION
1211 g_message ("Initial receipt of selection %ld, target %ld (property = %ld)",
1212 event->selection, event->target, event->property);
1215 tmp_list = current_retrievals;
1218 info = (GtkRetrievalInfo *)tmp_list->data;
1219 if (info->widget == widget && info->selection == event->selection)
1221 tmp_list = tmp_list->next;
1224 if (!tmp_list) /* no retrieval in progress */
1227 if (event->property != GDK_NONE)
1228 length = gdk_selection_property_get (widget->window, &buffer,
1231 if (event->property == GDK_NONE || buffer == NULL)
1233 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1234 g_list_free (tmp_list);
1235 /* structure will be freed in timeout */
1236 gtk_selection_retrieval_report (info,
1237 GDK_NONE, 0, NULL, -1, event->time);
1242 if (type == gtk_selection_atoms[INCR])
1244 /* The remainder of the selection will come through PropertyNotify
1247 info->notify_time = event->time;
1248 info->idle_time = 0;
1249 info->offset = 0; /* Mark as OK to proceed */
1250 gdk_window_set_events (widget->window,
1251 gdk_window_get_events (widget->window)
1252 | GDK_PROPERTY_CHANGE_MASK);
1256 /* We don't delete the info structure - that will happen in timeout */
1257 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1258 g_list_free (tmp_list);
1260 info->offset = length;
1261 gtk_selection_retrieval_report (info,
1263 buffer, length, event->time);
1266 gdk_property_delete (widget->window, event->property);
1273 /*************************************************************
1274 * gtk_selection_property_notify:
1275 * Handler for "property_notify_event" signals on windows
1276 * where a retrieval is currently in process. The selection
1277 * owner has added more data.
1279 * widget: Widget getting signal
1280 * event: Property event structure
1281 * info: Information about this retrieval
1283 * was event handled?
1284 *************************************************************/
1287 gtk_selection_property_notify (GtkWidget *widget,
1288 GdkEventProperty *event)
1291 GtkRetrievalInfo *info = NULL;
1297 g_return_val_if_fail (widget != NULL, FALSE);
1298 g_return_val_if_fail (event != NULL, FALSE);
1300 #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
1301 if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */
1302 (event->atom != gdk_selection_property)) /* not the right property */
1306 #ifdef DEBUG_SELECTION
1307 g_message ("PropertyNewValue, property %ld",
1311 tmp_list = current_retrievals;
1314 info = (GtkRetrievalInfo *)tmp_list->data;
1315 if (info->widget == widget)
1317 tmp_list = tmp_list->next;
1320 if (!tmp_list) /* No retrieval in progress */
1323 if (info->offset < 0) /* We haven't got the SelectionNotify
1324 for this retrieval yet */
1327 info->idle_time = 0;
1329 length = gdk_selection_property_get (widget->window, &new_buffer,
1331 gdk_property_delete (widget->window, event->atom);
1333 /* We could do a lot better efficiency-wise by paying attention to
1334 what length was sent in the initial INCR transaction, instead of
1335 doing memory allocation at every step. But its only guaranteed to
1336 be a _lower bound_ (pretty useless!) */
1338 if (length == 0 || type == GDK_NONE) /* final zero length portion */
1340 /* Info structure will be freed in timeout */
1341 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1342 g_list_free (tmp_list);
1343 gtk_selection_retrieval_report (info,
1345 (type == GDK_NONE) ? NULL : info->buffer,
1346 (type == GDK_NONE) ? -1 : info->offset,
1349 else /* append on newly arrived data */
1353 #ifdef DEBUG_SELECTION
1354 g_message ("Start - Adding %d bytes at offset 0",
1357 info->buffer = new_buffer;
1358 info->offset = length;
1363 #ifdef DEBUG_SELECTION
1364 g_message ("Appending %d bytes at offset %d",
1365 length,info->offset);
1367 /* We copy length+1 bytes to preserve guaranteed null termination */
1368 info->buffer = g_realloc (info->buffer, info->offset+length+1);
1369 memcpy (info->buffer + info->offset, new_buffer, length+1);
1370 info->offset += length;
1371 g_free (new_buffer);
1378 /*************************************************************
1379 * gtk_selection_retrieval_timeout:
1380 * Timeout callback while receiving a selection.
1382 * info: Information about this retrieval
1384 *************************************************************/
1387 gtk_selection_retrieval_timeout (GtkRetrievalInfo *info)
1392 GDK_THREADS_ENTER ();
1394 /* Determine if retrieval has finished by checking if it still in
1395 list of pending retrievals */
1397 tmp_list = current_retrievals;
1400 if (info == (GtkRetrievalInfo *)tmp_list->data)
1402 tmp_list = tmp_list->next;
1405 /* If retrieval is finished */
1406 if (!tmp_list || info->idle_time >= 5)
1408 if (tmp_list && info->idle_time >= 5)
1410 current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
1411 g_list_free (tmp_list);
1412 gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);
1415 g_free (info->buffer);
1418 retval = FALSE; /* remove timeout */
1424 retval = TRUE; /* timeout will happen again */
1427 GDK_THREADS_LEAVE ();
1432 /*************************************************************
1433 * gtk_selection_retrieval_report:
1434 * Emits a "selection_received" signal.
1436 * info: information about the retrieval that completed
1437 * buffer: buffer containing data (NULL => errror)
1438 * time: timestamp for data in buffer
1440 *************************************************************/
1443 gtk_selection_retrieval_report (GtkRetrievalInfo *info,
1444 GdkAtom type, gint format,
1445 guchar *buffer, gint length,
1448 GtkSelectionData data;
1450 data.selection = info->selection;
1451 data.target = info->target;
1453 data.format = format;
1455 data.length = length;
1458 gtk_signal_emit_by_name (GTK_OBJECT(info->widget),
1459 "selection_received",
1463 /*************************************************************
1464 * gtk_selection_invoke_handler:
1465 * Finds and invokes handler for specified
1466 * widget/selection/target combination, calls
1467 * gtk_selection_default_handler if none exists.
1470 * widget: selection owner
1471 * data: selection data [INOUT]
1472 * time: time from requeset
1475 * Number of bytes written to buffer, -1 if error
1476 *************************************************************/
1479 gtk_selection_invoke_handler (GtkWidget *widget,
1480 GtkSelectionData *data,
1483 GtkTargetList *target_list;
1487 g_return_if_fail (widget != NULL);
1489 target_list = gtk_selection_target_list_get (widget, data->selection);
1491 gtk_target_list_find (target_list, data->target, &info))
1493 gtk_signal_emit_by_name (GTK_OBJECT (widget),
1499 gtk_selection_default_handler (widget, data);
1502 /*************************************************************
1503 * gtk_selection_default_handler:
1504 * Handles some default targets that exist for any widget
1505 * If it can't fit results into buffer, returns -1. This
1506 * won't happen in any conceivable case, since it would
1507 * require 1000 selection targets!
1510 * widget: selection owner
1511 * data: selection data [INOUT]
1513 *************************************************************/
1516 gtk_selection_default_handler (GtkWidget *widget,
1517 GtkSelectionData *data)
1519 if (data->target == gtk_selection_atoms[TIMESTAMP])
1521 /* Time which was used to obtain selection */
1523 GtkSelectionInfo *selection_info;
1525 tmp_list = current_selections;
1528 selection_info = (GtkSelectionInfo *)tmp_list->data;
1529 if ((selection_info->widget == widget) &&
1530 (selection_info->selection == data->selection))
1532 gulong time = selection_info->time;
1534 gtk_selection_data_set (data,
1535 GDK_SELECTION_TYPE_INTEGER,
1542 tmp_list = tmp_list->next;
1547 else if (data->target == gtk_selection_atoms[TARGETS])
1549 /* List of all targets supported for this widget/selection pair */
1553 GtkTargetList *target_list;
1554 GtkTargetPair *pair;
1556 target_list = gtk_selection_target_list_get (widget,
1558 count = g_list_length (target_list->list) + 3;
1560 data->type = GDK_SELECTION_TYPE_ATOM;
1562 data->length = count * sizeof (GdkAtom);
1564 p = g_new (GdkAtom, count);
1565 data->data = (guchar *)p;
1567 *p++ = gtk_selection_atoms[TIMESTAMP];
1568 *p++ = gtk_selection_atoms[TARGETS];
1569 *p++ = gtk_selection_atoms[MULTIPLE];
1571 tmp_list = target_list->list;
1574 pair = (GtkTargetPair *)tmp_list->data;
1575 *p++ = pair->target;
1577 tmp_list = tmp_list->next;
1588 gtk_selection_data_copy (GtkSelectionData *data)
1590 GtkSelectionData *new_data;
1592 g_return_val_if_fail (data != NULL, NULL);
1594 new_data = g_new (GtkSelectionData, 1);
1601 gtk_selection_data_free (GtkSelectionData *data)
1603 g_return_if_fail (data != NULL);
1609 gtk_selection_bytes_per_item (gint format)
1614 return sizeof (char);
1617 return sizeof (short);
1620 return sizeof (long);
1623 g_assert_not_reached();