1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1999 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.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29 #include <X11/Xatom.h>
32 #include "gdk.h" /* For gdk_flush() */
36 #include "gdkproperty.h"
37 #include "gdkprivate-x11.h"
38 #include "gdkinternals.h"
39 #include "gdkscreen-x11.h"
40 #include "gdkdisplay-x11.h"
43 typedef struct _GdkDragContextPrivateX11 GdkDragContextPrivateX11;
47 GDK_DRAG_STATUS_MOTION_WAIT,
48 GDK_DRAG_STATUS_ACTION_WAIT,
54 gint x, y, width, height;
60 GHashTable *child_hash;
65 /* Structure that holds information about a drag in progress.
66 * this is used on both source and destination sides.
68 struct _GdkDragContextPrivateX11 {
69 GdkDragContext context;
74 guint16 last_x; /* Coordinates from last event */
76 GdkDragAction old_action; /* The last action we sent to the source */
77 GdkDragAction old_actions; /* The last actions we sent to the source */
78 GdkDragAction xdnd_actions; /* What is currently set in XdndActionList */
80 Window dest_xid; /* The last window we looked up */
81 Window drop_xid; /* The (non-proxied) window that is receiving drops */
82 guint xdnd_targets_set : 1; /* Whether we've already set XdndTypeList */
83 guint xdnd_actions_set : 1; /* Whether we've already set XdndActionList */
84 guint xdnd_have_actions : 1; /* Whether an XdndActionList was provided */
85 guint motif_targets_set : 1; /* Whether we've already set motif initiator info */
86 guint drag_status : 4; /* current status of drag */
88 guint drop_failed : 1; /* Whether the drop was unsuccessful */
89 guint version; /* Xdnd protocol version */
91 GSList *window_caches;
94 #define PRIVATE_DATA(context) ((GdkDragContextPrivateX11 *) GDK_DRAG_CONTEXT (context)->windowing_data)
96 /* Forward declarations */
98 static void gdk_window_cache_destroy (GdkWindowCache *cache);
100 static void motif_read_target_table (GdkDisplay *display);
102 static GdkFilterReturn motif_dnd_filter (GdkXEvent *xev,
106 static GdkFilterReturn xdnd_enter_filter (GdkXEvent *xev,
109 static GdkFilterReturn xdnd_leave_filter (GdkXEvent *xev,
112 static GdkFilterReturn xdnd_position_filter (GdkXEvent *xev,
115 static GdkFilterReturn xdnd_status_filter (GdkXEvent *xev,
118 static GdkFilterReturn xdnd_finished_filter (GdkXEvent *xev,
121 static GdkFilterReturn xdnd_drop_filter (GdkXEvent *xev,
125 static void xdnd_manage_source_filter (GdkDragContext *context,
127 gboolean add_filter);
129 static void gdk_drag_context_init (GdkDragContext *dragcontext);
130 static void gdk_drag_context_class_init (GdkDragContextClass *klass);
131 static void gdk_drag_context_finalize (GObject *object);
133 static gpointer parent_class = NULL;
134 static GList *contexts;
136 const static struct {
137 const char *atom_name;
139 } const xdnd_filters[] = {
140 { "XdndEnter", xdnd_enter_filter },
141 { "XdndLeave", xdnd_leave_filter },
142 { "XdndPosition", xdnd_position_filter },
143 { "XdndStatus", xdnd_status_filter },
144 { "XdndFinished", xdnd_finished_filter },
145 { "XdndDrop", xdnd_drop_filter },
149 gdk_drag_context_get_type (void)
151 static GType object_type = 0;
155 static const GTypeInfo object_info =
157 sizeof (GdkDragContextClass),
158 (GBaseInitFunc) NULL,
159 (GBaseFinalizeFunc) NULL,
160 (GClassInitFunc) gdk_drag_context_class_init,
161 NULL, /* class_finalize */
162 NULL, /* class_data */
163 sizeof (GdkDragContext),
165 (GInstanceInitFunc) gdk_drag_context_init,
168 object_type = g_type_register_static (G_TYPE_OBJECT,
177 gdk_drag_context_init (GdkDragContext *dragcontext)
179 GdkDragContextPrivateX11 *private;
181 private = g_new0 (GdkDragContextPrivateX11, 1);
183 dragcontext->windowing_data = private;
185 contexts = g_list_prepend (contexts, dragcontext);
189 gdk_drag_context_class_init (GdkDragContextClass *klass)
191 GObjectClass *object_class = G_OBJECT_CLASS (klass);
193 parent_class = g_type_class_peek_parent (klass);
195 object_class->finalize = gdk_drag_context_finalize;
199 gdk_drag_context_finalize (GObject *object)
201 GdkDragContext *context = GDK_DRAG_CONTEXT (object);
202 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
205 g_list_free (context->targets);
207 if (context->source_window)
209 if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
211 xdnd_manage_source_filter (context, context->source_window, FALSE);
213 g_object_unref (context->source_window);
216 if (context->dest_window)
217 g_object_unref (context->dest_window);
219 for (tmp_list = private->window_caches; tmp_list; tmp_list = tmp_list->next)
220 gdk_window_cache_destroy (tmp_list->data);
221 g_slist_free (private->window_caches);
223 contexts = g_list_remove (contexts, context);
227 G_OBJECT_CLASS (parent_class)->finalize (object);
233 * gdk_drag_context_new:
235 * Creates a new #GdkDragContext.
237 * Return value: the newly created #GdkDragContext.
240 gdk_drag_context_new (void)
242 return g_object_new (gdk_drag_context_get_type (), NULL);
246 * gdk_drag_context_ref:
247 * @context: a #GdkDragContext.
249 * Deprecated function; use g_object_ref() instead.
252 gdk_drag_context_ref (GdkDragContext *context)
254 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
256 g_object_ref (context);
260 * gdk_drag_context_unref:
261 * @context: a #GdkDragContext.
263 * Deprecated function; use g_object_unref() instead.
266 gdk_drag_context_unref (GdkDragContext *context)
268 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
270 g_object_unref (context);
273 static GdkDragContext *
274 gdk_drag_context_find (GdkDisplay *display,
279 GList *tmp_list = contexts;
280 GdkDragContext *context;
281 GdkDragContextPrivateX11 *private;
282 Window context_dest_xid;
286 context = (GdkDragContext *)tmp_list->data;
287 private = PRIVATE_DATA (context);
289 if ((context->source_window && gdk_drawable_get_display (context->source_window) != display) ||
290 (context->dest_window && gdk_drawable_get_display (context->dest_window) != display))
293 context_dest_xid = context->dest_window ?
296 GDK_DRAWABLE_XID (context->dest_window)) :
299 if ((!context->is_source == !is_source) &&
300 ((source_xid == None) || (context->source_window &&
301 (GDK_DRAWABLE_XID (context->source_window) == source_xid))) &&
302 ((dest_xid == None) || (context_dest_xid == dest_xid)))
305 tmp_list = tmp_list->next;
312 precache_target_list (GdkDragContext *context)
314 if (context->targets)
316 GPtrArray *targets = g_ptr_array_new ();
320 for (tmp_list = context->targets; tmp_list; tmp_list = tmp_list->next)
321 g_ptr_array_add (targets, gdk_atom_name (GDK_POINTER_TO_ATOM (tmp_list->data)));
323 _gdk_x11_precache_atoms (GDK_WINDOW_DISPLAY (context->source_window),
324 (const gchar **)targets->pdata,
327 for (i =0; i < targets->len; i++)
328 g_free (targets->pdata[i]);
330 g_ptr_array_free (targets, TRUE);
334 /* Utility functions */
337 gdk_window_cache_add (GdkWindowCache *cache,
339 gint x, gint y, gint width, gint height,
342 GdkCacheChild *child = g_new (GdkCacheChild, 1);
347 child->width = width;
348 child->height = height;
349 child->mapped = mapped;
351 cache->children = g_list_prepend (cache->children, child);
352 g_hash_table_insert (cache->child_hash, GUINT_TO_POINTER (xid),
356 static GdkFilterReturn
357 gdk_window_cache_filter (GdkXEvent *xev,
361 XEvent *xevent = (XEvent *)xev;
362 GdkWindowCache *cache = data;
364 switch (xevent->type)
366 case CirculateNotify:
368 case ConfigureNotify:
370 XConfigureEvent *xce = &xevent->xconfigure;
373 node = g_hash_table_lookup (cache->child_hash,
374 GUINT_TO_POINTER (xce->window));
377 GdkCacheChild *child = node->data;
380 child->width = xce->width;
381 child->height = xce->height;
382 if (xce->above == None && (node->next))
384 GList *last = g_list_last (cache->children);
385 cache->children = g_list_remove_link (cache->children, node);
392 GList *above_node = g_hash_table_lookup (cache->child_hash,
393 GUINT_TO_POINTER (xce->above));
394 if (above_node && node->next != above_node)
396 /* Put the window above (before in the list) above_node
398 cache->children = g_list_remove_link (cache->children, node);
399 node->prev = above_node->prev;
401 node->prev->next = node;
403 cache->children = node;
404 node->next = above_node;
405 above_node->prev = node;
413 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
415 if (!g_hash_table_lookup (cache->child_hash,
416 GUINT_TO_POINTER (xcwe->window)))
417 gdk_window_cache_add (cache, xcwe->window,
418 xcwe->x, xcwe->y, xcwe->width, xcwe->height,
424 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
427 node = g_hash_table_lookup (cache->child_hash,
428 GUINT_TO_POINTER (xdwe->window));
431 g_hash_table_remove (cache->child_hash,
432 GUINT_TO_POINTER (xdwe->window));
433 cache->children = g_list_remove_link (cache->children, node);
435 g_list_free_1 (node);
441 XMapEvent *xme = &xevent->xmap;
444 node = g_hash_table_lookup (cache->child_hash,
445 GUINT_TO_POINTER (xme->window));
448 GdkCacheChild *child = node->data;
449 child->mapped = TRUE;
457 XMapEvent *xume = &xevent->xmap;
460 node = g_hash_table_lookup (cache->child_hash,
461 GUINT_TO_POINTER (xume->window));
464 GdkCacheChild *child = node->data;
465 child->mapped = FALSE;
470 return GDK_FILTER_CONTINUE;
472 return GDK_FILTER_REMOVE;
475 static GdkWindowCache *
476 gdk_window_cache_new (GdkScreen *screen)
478 XWindowAttributes xwa;
479 Display *xdisplay = GDK_SCREEN_XDISPLAY (screen);
480 GdkWindow *root_window = gdk_screen_get_root_window (screen);
481 GdkChildInfoX11 *children;
484 GdkWindowCache *result = g_new (GdkWindowCache, 1);
486 result->children = NULL;
487 result->child_hash = g_hash_table_new (g_direct_hash, NULL);
488 result->screen = screen;
490 XGetWindowAttributes (xdisplay, GDK_WINDOW_XWINDOW (root_window), &xwa);
491 result->old_event_mask = xwa.your_event_mask;
492 XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
493 result->old_event_mask | SubstructureNotifyMask);
494 gdk_window_add_filter (root_window, gdk_window_cache_filter, result);
496 if (!_gdk_x11_get_window_child_info (gdk_screen_get_display (screen),
497 GDK_WINDOW_XWINDOW (root_window),
499 &children, &nchildren))
502 for (i = 0; i < nchildren ; i++)
504 gdk_window_cache_add (result, children[i].window,
505 children[i].x, children[i].y, children[i].width, children[i].height,
506 children[i].is_mapped);
515 gdk_window_cache_destroy (GdkWindowCache *cache)
517 GdkWindow *root_window = gdk_screen_get_root_window (cache->screen);
519 XSelectInput (GDK_WINDOW_XDISPLAY (root_window),
520 GDK_WINDOW_XWINDOW (root_window),
521 cache->old_event_mask);
522 gdk_window_remove_filter (root_window, gdk_window_cache_filter, cache);
524 g_list_foreach (cache->children, (GFunc)g_free, NULL);
525 g_list_free (cache->children);
526 g_hash_table_destroy (cache->child_hash);
532 get_client_window_at_coords_recurse (GdkDisplay *display,
534 gboolean is_toplevel,
538 GdkChildInfoX11 *children;
539 unsigned int nchildren;
541 gboolean found_child = FALSE;
542 GdkChildInfoX11 child;
543 gboolean has_wm_state = FALSE;
545 if (!_gdk_x11_get_window_child_info (display, win, TRUE,
546 is_toplevel? &has_wm_state : NULL,
547 &children, &nchildren))
553 for (i = nchildren - 1; (i >= 0) && !found_child; i--)
555 GdkChildInfoX11 *cur_child = &children[i];
557 if ((cur_child->is_mapped) && (cur_child->window_class == InputOutput) &&
558 (x >= cur_child->x) && (x < cur_child->x + cur_child->width) &&
559 (y >= cur_child->y) && (y < cur_child->y + cur_child->height))
572 if (child.has_wm_state)
575 return get_client_window_at_coords_recurse (display, child.window, FALSE, x, y);
582 get_client_window_at_coords (GdkWindowCache *cache,
588 Window retval = None;
590 gdk_error_trap_push ();
592 tmp_list = cache->children;
594 while (tmp_list && !retval)
596 GdkCacheChild *child = tmp_list->data;
598 if ((child->xid != ignore) && (child->mapped))
600 if ((x_root >= child->x) && (x_root < child->x + child->width) &&
601 (y_root >= child->y) && (y_root < child->y + child->height))
603 retval = get_client_window_at_coords_recurse (gdk_screen_get_display (cache->screen),
612 tmp_list = tmp_list->next;
615 gdk_error_trap_pop ();
620 return GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (cache->screen));
623 /*************************************************************
624 ***************************** MOTIF *************************
625 *************************************************************/
627 /* values used in the message type for Motif DND */
640 /* Values used to specify type of protocol to use */
644 XmDRAG_PREFER_PREREGISTER,
646 XmDRAG_PREFER_DYNAMIC,
648 XmDRAG_PREFER_RECEIVER
651 /* Operation codes */
659 /* Drop site status */
661 XmNO_DROP_SITE = 0x01,
662 XmDROP_SITE_INVALID = 0x02,
663 XmDROP_SITE_VALID = 0x03
666 /* completion status */
674 /* Byte swapping routines. The motif specification leaves it
675 * up to us to save a few bytes in the client messages
677 static gchar local_byte_order = '\0';
679 #ifdef G_ENABLE_DEBUG
681 print_target_list (GList *targets)
685 gchar *name = gdk_atom_name (GDK_POINTER_TO_ATOM (targets->data));
686 g_message ("\t%s", name);
688 targets = targets->next;
691 #endif /* G_ENABLE_DEBUG */
694 init_byte_order (void)
696 guint32 myint = 0x01020304;
697 local_byte_order = (*(gchar *)&myint == 1) ? 'B' : 'l';
701 card16_to_host (guint16 x, gchar byte_order) {
702 if (byte_order == local_byte_order)
705 return (x << 8) | (x >> 8);
709 card32_to_host (guint32 x, gchar byte_order) {
710 if (byte_order == local_byte_order)
713 return (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
716 /* Motif packs together fields of varying length into the
717 * client message. We can't rely on accessing these
718 * through data.s[], data.l[], etc, because on some architectures
719 * (i.e., Alpha) these won't be valid for format == 8.
722 #define MOTIF_XCLIENT_BYTE(xevent,i) \
723 (xevent)->xclient.data.b[i]
724 #define MOTIF_XCLIENT_SHORT(xevent,i) \
725 ((gint16 *)&((xevent)->xclient.data.b[0]))[i]
726 #define MOTIF_XCLIENT_LONG(xevent,i) \
727 ((gint32 *)&((xevent)->xclient.data.b[0]))[i]
729 #define MOTIF_UNPACK_BYTE(xevent,i) MOTIF_XCLIENT_BYTE(xevent,i)
730 #define MOTIF_UNPACK_SHORT(xevent,i) \
731 card16_to_host (MOTIF_XCLIENT_SHORT(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
732 #define MOTIF_UNPACK_LONG(xevent,i) \
733 card32_to_host (MOTIF_XCLIENT_LONG(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
735 /***** Dest side ***********/
737 /* Property placed on source windows */
738 typedef struct _MotifDragInitiatorInfo {
740 guint8 protocol_version;
741 guint16 targets_index;
742 guint32 selection_atom;
743 } MotifDragInitiatorInfo;
745 /* Header for target table on the drag window */
746 typedef struct _MotifTargetTableHeader {
748 guchar protocol_version;
751 } MotifTargetTableHeader;
753 /* Property placed on target windows */
754 typedef struct _MotifDragReceiverInfo {
756 guint8 protocol_version;
757 guint8 protocol_style;
759 guint32 proxy_window;
760 guint16 num_drop_sites;
763 } MotifDragReceiverInfo;
765 /* Target table handling */
767 static GdkFilterReturn
768 motif_drag_window_filter (GdkXEvent *xevent,
772 XEvent *xev = (XEvent *)xevent;
773 GdkDisplay *display = GDK_WINDOW_DISPLAY (event->any.window);
774 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
776 switch (xev->xany.type)
779 display_x11->motif_drag_window = None;
780 display_x11->motif_drag_gdk_window = NULL;
783 if (display_x11->motif_target_lists &&
784 (xev->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS")))
785 motif_read_target_table (display);
788 return GDK_FILTER_REMOVE;
792 motif_lookup_drag_window (GdkDisplay *display,
793 Display *lookup_xdisplay)
795 Window retval = None;
796 gulong bytes_after, nitems;
801 XGetWindowProperty (lookup_xdisplay, RootWindow (lookup_xdisplay, 0),
802 gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW"),
804 XA_WINDOW, &type, &format, &nitems, &bytes_after,
807 if ((format == 32) && (nitems == 1) && (bytes_after == 0))
809 retval = *(Window *)data;
811 g_message ("Found drag window %#lx\n", GDK_DISPLAY_X11 (display)->motif_drag_window));
820 /* Finds the window where global Motif drag information is stored.
821 * If it doesn't exist and 'create' is TRUE, create one.
824 motif_find_drag_window (GdkDisplay *display,
827 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
829 if (!display_x11->motif_drag_window)
831 Atom motif_drag_window_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW");
832 display_x11->motif_drag_window = motif_lookup_drag_window (display, display_x11->xdisplay);
834 if (!display_x11->motif_drag_window && create)
836 /* Create a persistant window. (Copied from LessTif) */
838 Display *persistant_xdisplay;
839 XSetWindowAttributes attr;
840 persistant_xdisplay = XOpenDisplay (gdk_display_get_name (display));
841 XSetCloseDownMode (persistant_xdisplay, RetainPermanent);
843 XGrabServer (persistant_xdisplay);
845 display_x11->motif_drag_window = motif_lookup_drag_window (display, persistant_xdisplay);
847 if (!display_x11->motif_drag_window)
849 attr.override_redirect = True;
850 attr.event_mask = PropertyChangeMask;
852 display_x11->motif_drag_window =
853 XCreateWindow (persistant_xdisplay,
854 RootWindow (persistant_xdisplay, 0),
855 -100, -100, 10, 10, 0, 0,
856 InputOnly, (Visual *)CopyFromParent,
857 (CWOverrideRedirect | CWEventMask), &attr);
860 g_message ("Created drag window %#lx\n", display_x11->motif_drag_window));
862 XChangeProperty (persistant_xdisplay,
863 RootWindow (persistant_xdisplay, 0),
864 motif_drag_window_atom, XA_WINDOW,
866 (guchar *)&motif_drag_window_atom, 1);
869 XUngrabServer (persistant_xdisplay);
870 XCloseDisplay (persistant_xdisplay);
873 /* There is a miniscule race condition here if the drag window
874 * gets destroyed exactly now.
876 if (display_x11->motif_drag_window)
878 display_x11->motif_drag_gdk_window =
879 gdk_window_foreign_new_for_display (display, display_x11->motif_drag_window);
880 gdk_window_add_filter (display_x11->motif_drag_gdk_window,
881 motif_drag_window_filter,
886 return display_x11->motif_drag_window;
890 motif_read_target_table (GdkDisplay *display)
892 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
893 gulong bytes_after, nitems;
898 Atom motif_drag_targets_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS");
900 if (display_x11->motif_target_lists)
902 for (i=0; i<display_x11->motif_n_target_lists; i++)
903 g_list_free (display_x11->motif_target_lists[i]);
905 g_free (display_x11->motif_target_lists);
906 display_x11->motif_target_lists = NULL;
907 display_x11->motif_n_target_lists = 0;
910 if (motif_find_drag_window (display, FALSE))
913 MotifTargetTableHeader *header = NULL;
914 guchar *target_bytes = NULL;
916 gboolean success = FALSE;
918 gdk_error_trap_push ();
919 XGetWindowProperty (display_x11->xdisplay,
920 display_x11->motif_drag_window,
921 motif_drag_targets_atom,
922 0, (sizeof(MotifTargetTableHeader)+3)/4, FALSE,
923 motif_drag_targets_atom,
924 &type, &format, &nitems, &bytes_after,
927 if (gdk_error_trap_pop () || (format != 8) || (nitems < sizeof (MotifTargetTableHeader)))
930 header = (MotifTargetTableHeader *)data;
932 header->n_lists = card16_to_host (header->n_lists, header->byte_order);
933 header->total_size = card32_to_host (header->total_size, header->byte_order);
935 gdk_error_trap_push ();
936 XGetWindowProperty (display_x11->xdisplay,
937 display_x11->motif_drag_window,
938 motif_drag_targets_atom,
939 (sizeof(MotifTargetTableHeader)+3)/4,
940 (header->total_size + 3)/4 - (sizeof(MotifTargetTableHeader) + 3)/4,
942 motif_drag_targets_atom, &type, &format, &nitems,
943 &bytes_after, &target_bytes);
945 if (gdk_error_trap_pop () || (format != 8) || (bytes_after != 0) ||
946 (nitems != header->total_size - sizeof(MotifTargetTableHeader)))
949 display_x11->motif_n_target_lists = header->n_lists;
950 display_x11->motif_target_lists = g_new0 (GList *, display_x11->motif_n_target_lists);
953 for (i=0; i<header->n_lists; i++)
958 if (p + sizeof(guint16) - target_bytes > nitems)
961 n_targets = card16_to_host (*(gushort *)p, header->byte_order);
963 /* We need to make a copy of the targets, since it may
966 targets = g_new (guint32, n_targets);
967 memcpy (targets, p + sizeof(guint16), sizeof(guint32) * n_targets);
969 p += sizeof(guint16) + n_targets * sizeof(guint32);
970 if (p - target_bytes > nitems)
973 for (j=0; j<n_targets; j++)
974 display_x11->motif_target_lists[i] =
975 g_list_prepend (display_x11->motif_target_lists[i],
976 GUINT_TO_POINTER (card32_to_host (targets[j],
977 header->byte_order)));
979 display_x11->motif_target_lists[i] = g_list_reverse (display_x11->motif_target_lists[i]);
989 XFree (target_bytes);
993 if (display_x11->motif_target_lists)
995 g_free (display_x11->motif_target_lists);
996 display_x11->motif_target_lists = NULL;
997 display_x11->motif_n_target_lists = 0;
999 g_warning ("Error reading Motif target table\n");
1005 targets_sort_func (gconstpointer a, gconstpointer b)
1007 return (GPOINTER_TO_UINT (a) < GPOINTER_TO_UINT (b)) ?
1008 -1 : ((GPOINTER_TO_UINT (a) > GPOINTER_TO_UINT (b)) ? 1 : 0);
1011 /* Check if given (sorted) list is in the targets table */
1013 motif_target_table_check (GdkDisplay *display,
1016 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1017 GList *tmp_list1, *tmp_list2;
1020 for (i=0; i<display_x11->motif_n_target_lists; i++)
1022 tmp_list1 = display_x11->motif_target_lists[i];
1025 while (tmp_list1 && tmp_list2)
1027 if (tmp_list1->data != tmp_list2->data)
1030 tmp_list1 = tmp_list1->next;
1031 tmp_list2 = tmp_list2->next;
1033 if (!tmp_list1 && !tmp_list2) /* Found it */
1041 motif_add_to_target_table (GdkDisplay *display,
1042 GList *targets) /* targets is list of GdkAtom */
1044 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1045 GList *sorted = NULL;
1050 /* make a sorted copy of the list */
1054 Atom xatom = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (targets->data));
1055 sorted = g_list_insert_sorted (sorted, GUINT_TO_POINTER (xatom), targets_sort_func);
1056 targets = targets->next;
1059 /* First check if it is there already */
1061 if (display_x11->motif_target_lists)
1062 index = motif_target_table_check (display, sorted);
1064 /* We need to grab the server while doing this, to ensure
1070 /* We need to make sure that it exists _before_ we grab the
1071 * server, since we can't open a new connection after we
1074 motif_find_drag_window (display, TRUE);
1076 gdk_x11_display_grab (display);
1077 motif_read_target_table (display);
1079 /* Check again, in case it was added in the meantime */
1081 if (display_x11->motif_target_lists)
1082 index = motif_target_table_check (display, sorted);
1086 guint32 total_size = 0;
1090 MotifTargetTableHeader *header;
1092 if (!display_x11->motif_target_lists)
1094 display_x11->motif_target_lists = g_new (GList *, 1);
1095 display_x11->motif_n_target_lists = 1;
1099 display_x11->motif_n_target_lists++;
1100 display_x11->motif_target_lists = g_realloc (display_x11->motif_target_lists,
1101 sizeof(GList *) * display_x11->motif_n_target_lists);
1103 display_x11->motif_target_lists[display_x11->motif_n_target_lists - 1] = sorted;
1105 index = display_x11->motif_n_target_lists - 1;
1107 total_size = sizeof (MotifTargetTableHeader);
1108 for (i = 0; i < display_x11->motif_n_target_lists ; i++)
1109 total_size += sizeof(guint16) + sizeof(guint32) * g_list_length (display_x11->motif_target_lists[i]);
1111 data = g_malloc (total_size);
1113 header = (MotifTargetTableHeader *)data;
1114 p = data + sizeof(MotifTargetTableHeader);
1116 header->byte_order = local_byte_order;
1117 header->protocol_version = 0;
1118 header->n_lists = display_x11->motif_n_target_lists;
1119 header->total_size = total_size;
1121 for (i = 0; i < display_x11->motif_n_target_lists ; i++)
1123 guint16 n_targets = g_list_length (display_x11->motif_target_lists[i]);
1124 guint32 *targets = g_new (guint32, n_targets);
1125 guint32 *p32 = targets;
1127 tmp_list = display_x11->motif_target_lists[i];
1130 *p32 = GPOINTER_TO_UINT (tmp_list->data);
1132 tmp_list = tmp_list->next;
1137 p += sizeof(guint16);
1139 memcpy (p, targets, n_targets * sizeof(guint32));
1142 p += sizeof(guint32) * n_targets;
1146 XChangeProperty (display_x11->xdisplay,
1147 display_x11->motif_drag_window,
1148 gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
1149 gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
1153 gdk_x11_display_ungrab (display);
1156 g_list_free (sorted);
1160 /* Translate flags */
1163 motif_dnd_translate_flags (GdkDragContext *context, guint16 flags)
1165 guint recommended_op = flags & 0x000f;
1166 guint possible_ops = (flags & 0x0f0) >> 4;
1168 switch (recommended_op)
1171 context->suggested_action = GDK_ACTION_MOVE;
1174 context->suggested_action = GDK_ACTION_COPY;
1177 context->suggested_action = GDK_ACTION_LINK;
1180 context->suggested_action = GDK_ACTION_COPY;
1184 context->actions = 0;
1185 if (possible_ops & XmDROP_MOVE)
1186 context->actions |= GDK_ACTION_MOVE;
1187 if (possible_ops & XmDROP_COPY)
1188 context->actions |= GDK_ACTION_COPY;
1189 if (possible_ops & XmDROP_LINK)
1190 context->actions |= GDK_ACTION_LINK;
1194 motif_dnd_get_flags (GdkDragContext *context)
1198 switch (context->suggested_action)
1200 case GDK_ACTION_MOVE:
1201 flags = XmDROP_MOVE;
1203 case GDK_ACTION_COPY:
1204 flags = XmDROP_COPY;
1206 case GDK_ACTION_LINK:
1207 flags = XmDROP_LINK;
1210 flags = XmDROP_NOOP;
1214 if (context->actions & GDK_ACTION_MOVE)
1215 flags |= XmDROP_MOVE << 8;
1216 if (context->actions & GDK_ACTION_COPY)
1217 flags |= XmDROP_COPY << 8;
1218 if (context->actions & GDK_ACTION_LINK)
1219 flags |= XmDROP_LINK << 8;
1227 motif_set_targets (GdkDragContext *context)
1229 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1230 MotifDragInitiatorInfo info;
1232 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1234 info.byte_order = local_byte_order;
1235 info.protocol_version = 0;
1237 info.targets_index = motif_add_to_target_table (display, context->targets);
1242 g_snprintf(buf, 20, "_GDK_SELECTION_%d", i);
1244 private->motif_selection = gdk_x11_get_xatom_by_name_for_display (display, buf);
1245 if (!XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), private->motif_selection))
1249 info.selection_atom = private->motif_selection;
1251 XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
1252 GDK_DRAWABLE_XID (context->source_window),
1253 private->motif_selection,
1254 gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
1256 (guchar *)&info, sizeof (info));
1258 private->motif_targets_set = 1;
1262 motif_check_dest (GdkDisplay *display,
1265 gboolean retval = FALSE;
1267 MotifDragReceiverInfo *info;
1270 unsigned long nitems, after;
1271 Atom motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO");
1273 gdk_error_trap_push ();
1274 XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win,
1275 motif_drag_receiver_info_atom,
1276 0, (sizeof(*info)+3)/4, False, AnyPropertyType,
1277 &type, &format, &nitems, &after,
1280 if (gdk_error_trap_pop() == 0)
1284 info = (MotifDragReceiverInfo *)data;
1286 if ((format == 8) && (nitems == sizeof(*info)))
1288 if ((info->protocol_version == 0) &&
1289 ((info->protocol_style == XmDRAG_PREFER_PREREGISTER) ||
1290 (info->protocol_style == XmDRAG_PREFER_DYNAMIC) ||
1291 (info->protocol_style == XmDRAG_DYNAMIC)))
1297 g_warning ("Invalid Motif drag receiver property on window %ld\n", win));
1304 return retval ? win : None;
1308 motif_send_enter (GdkDragContext *context,
1311 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1312 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1315 xev.xclient.type = ClientMessage;
1316 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1317 xev.xclient.format = 8;
1318 xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1320 MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_ENTER;
1321 MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1322 MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
1323 MOTIF_XCLIENT_LONG (&xev, 1) = time;
1324 MOTIF_XCLIENT_LONG (&xev, 2) = GDK_DRAWABLE_XID (context->source_window);
1326 if (!private->motif_targets_set)
1327 motif_set_targets (context);
1329 MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection;
1330 MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1332 if (!_gdk_send_xevent (display,
1333 GDK_DRAWABLE_XID (context->dest_window),
1336 g_message ("Send event to %lx failed",
1337 GDK_DRAWABLE_XID (context->dest_window)));
1341 motif_send_leave (GdkDragContext *context,
1344 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1347 xev.xclient.type = ClientMessage;
1348 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1349 xev.xclient.format = 8;
1350 xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1352 MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_LEAVE;
1353 MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1354 MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
1355 MOTIF_XCLIENT_LONG (&xev, 1) = time;
1356 MOTIF_XCLIENT_LONG (&xev, 2) = 0;
1357 MOTIF_XCLIENT_LONG (&xev, 3) = 0;
1358 MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1360 if (!_gdk_send_xevent (display,
1361 GDK_DRAWABLE_XID (context->dest_window),
1364 g_message ("Send event to %lx failed",
1365 GDK_DRAWABLE_XID (context->dest_window)));
1369 motif_send_motion (GdkDragContext *context,
1372 GdkDragAction action,
1375 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1376 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1380 xev.xclient.type = ClientMessage;
1381 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1382 xev.xclient.format = 8;
1383 xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1385 MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1386 MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
1387 MOTIF_XCLIENT_LONG (&xev, 1) = time;
1388 MOTIF_XCLIENT_LONG (&xev, 3) = 0;
1389 MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1391 if ((context->suggested_action != private->old_action) ||
1392 (context->actions != private->old_actions))
1394 MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
1396 /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
1401 MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION;
1403 MOTIF_XCLIENT_SHORT (&xev, 4) = x_root;
1404 MOTIF_XCLIENT_SHORT (&xev, 5) = y_root;
1406 private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
1410 if (!_gdk_send_xevent (display,
1411 GDK_DRAWABLE_XID (context->dest_window),
1414 g_message ("Send event to %lx failed",
1415 GDK_DRAWABLE_XID (context->dest_window)));
1421 motif_send_drop (GdkDragContext *context, guint32 time)
1423 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1424 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1427 xev.xclient.type = ClientMessage;
1428 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1429 xev.xclient.format = 8;
1430 xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1432 MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START;
1433 MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1434 MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
1435 MOTIF_XCLIENT_LONG (&xev, 1) = time;
1437 MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
1438 MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
1440 MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection;
1441 MOTIF_XCLIENT_LONG (&xev, 4) = GDK_DRAWABLE_XID (context->source_window);
1443 if (!_gdk_send_xevent (display,
1444 GDK_DRAWABLE_XID (context->dest_window),
1447 g_message ("Send event to %lx failed",
1448 GDK_DRAWABLE_XID (context->dest_window)));
1454 motif_read_initiator_info (GdkDisplay *display,
1455 Window source_window,
1466 MotifDragInitiatorInfo *initiator_info;
1468 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1470 gdk_error_trap_push ();
1471 XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), source_window, atom,
1472 0, sizeof(*initiator_info), FALSE,
1473 gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
1474 &type, &format, &nitems, &bytes_after,
1477 if (gdk_error_trap_pop () || (format != 8) || (nitems != sizeof (MotifDragInitiatorInfo)) || (bytes_after != 0))
1479 g_warning ("Error reading initiator info\n");
1483 initiator_info = (MotifDragInitiatorInfo *)data;
1485 motif_read_target_table (display);
1487 initiator_info->targets_index =
1488 card16_to_host (initiator_info->targets_index, initiator_info->byte_order);
1489 initiator_info->selection_atom =
1490 card32_to_host (initiator_info->selection_atom, initiator_info->byte_order);
1492 if (initiator_info->targets_index >= display_x11->motif_n_target_lists)
1494 g_warning ("Invalid target index in TOP_LEVEL_ENTER MESSAGE");
1495 XFree (initiator_info);
1499 tmp_list = g_list_last (display_x11->motif_target_lists[initiator_info->targets_index]);
1504 GdkAtom atom = gdk_x11_xatom_to_atom_for_display (display, GPOINTER_TO_UINT (tmp_list->data));
1505 *targets = g_list_prepend (*targets, GDK_ATOM_TO_POINTER (atom));
1506 tmp_list = tmp_list->prev;
1509 #ifdef G_ENABLE_DEBUG
1510 if (_gdk_debug_flags & GDK_DEBUG_DND)
1511 print_target_list (*targets);
1512 #endif /* G_ENABLE_DEBUG */
1514 *selection = initiator_info->selection_atom;
1516 XFree (initiator_info);
1521 static GdkDragContext *
1522 motif_drag_context_new (GdkWindow *dest_window,
1524 guint32 source_window,
1527 GdkDragContext *new_context;
1528 GdkDragContextPrivateX11 *private;
1529 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (dest_window);
1530 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1532 /* FIXME, current_dest_drag really shouldn't be NULL'd
1533 * if we error below.
1535 if (display_x11->current_dest_drag != NULL)
1537 if (timestamp >= display_x11->current_dest_drag->start_time)
1539 g_object_unref (display_x11->current_dest_drag);
1540 display_x11->current_dest_drag = NULL;
1546 new_context = gdk_drag_context_new ();
1547 private = PRIVATE_DATA (new_context);
1549 new_context->protocol = GDK_DRAG_PROTO_MOTIF;
1550 new_context->is_source = FALSE;
1552 new_context->source_window = gdk_window_lookup_for_display (display, source_window);
1553 if (new_context->source_window)
1554 g_object_ref (new_context->source_window);
1557 new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
1558 if (!new_context->source_window)
1560 g_object_unref (new_context);
1565 new_context->dest_window = dest_window;
1566 g_object_ref (dest_window);
1567 new_context->start_time = timestamp;
1569 if (!motif_read_initiator_info (GDK_WINDOW_DISPLAY (dest_window),
1572 &new_context->targets,
1573 &private->motif_selection))
1575 g_object_unref (new_context);
1583 * The MOTIF drag protocol has no real provisions for distinguishing
1584 * multiple simultaneous drops. If the sources grab the pointer
1585 * when doing drags, that shouldn't happen, in any case. If it
1586 * does, we can't do much except hope for the best.
1589 static GdkFilterReturn
1590 motif_top_level_enter (GdkEvent *event,
1593 guint32 source_window,
1596 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1597 GdkDragContext *new_context;
1599 GDK_NOTE(DND, g_message ("Motif DND top level enter: flags: %#4x time: %d source_widow: %#4x atom: %d",
1600 flags, timestamp, source_window, atom));
1602 new_context = motif_drag_context_new (event->any.window, timestamp, source_window, atom);
1604 return GDK_FILTER_REMOVE;
1606 event->dnd.type = GDK_DRAG_ENTER;
1607 event->dnd.context = new_context;
1608 g_object_ref (new_context);
1610 display_x11->current_dest_drag = new_context;
1612 return GDK_FILTER_TRANSLATE;
1615 static GdkFilterReturn
1616 motif_top_level_leave (GdkEvent *event,
1620 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1622 GDK_NOTE(DND, g_message ("Motif DND top level leave: flags: %#4x time: %d",
1625 if ((display_x11->current_dest_drag != NULL) &&
1626 (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1627 (timestamp >= display_x11->current_dest_drag->start_time))
1629 event->dnd.type = GDK_DRAG_LEAVE;
1630 /* Pass ownership of context to the event */
1631 event->dnd.context = display_x11->current_dest_drag;
1633 display_x11->current_dest_drag = NULL;
1635 return GDK_FILTER_TRANSLATE;
1638 return GDK_FILTER_REMOVE;
1641 static GdkFilterReturn
1642 motif_motion (GdkEvent *event,
1648 GdkDragContextPrivateX11 *private;
1649 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1651 GDK_NOTE(DND, g_message ("Motif DND motion: flags: %#4x time: %d (%d, %d)",
1652 flags, timestamp, x_root, y_root));
1654 if ((display_x11->current_dest_drag != NULL) &&
1655 (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1656 (timestamp >= display_x11->current_dest_drag->start_time))
1658 private = PRIVATE_DATA (display_x11->current_dest_drag);
1660 event->dnd.type = GDK_DRAG_MOTION;
1661 event->dnd.context = display_x11->current_dest_drag;
1662 g_object_ref (display_x11->current_dest_drag);
1664 event->dnd.time = timestamp;
1666 motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
1668 event->dnd.x_root = x_root;
1669 event->dnd.y_root = y_root;
1671 private->last_x = x_root;
1672 private->last_y = y_root;
1674 private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
1676 return GDK_FILTER_TRANSLATE;
1679 return GDK_FILTER_REMOVE;
1682 static GdkFilterReturn
1683 motif_operation_changed (GdkEvent *event,
1687 GdkDragContextPrivateX11 *private;
1688 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1689 GDK_NOTE(DND, g_message ("Motif DND operation changed: flags: %#4x time: %d",
1692 if ((display_x11->current_dest_drag != NULL) &&
1693 (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1694 (timestamp >= display_x11->current_dest_drag->start_time))
1696 event->dnd.type = GDK_DRAG_MOTION;
1697 event->dnd.send_event = FALSE;
1698 event->dnd.context = display_x11->current_dest_drag;
1699 g_object_ref (display_x11->current_dest_drag);
1701 event->dnd.time = timestamp;
1702 private = PRIVATE_DATA (display_x11->current_dest_drag);
1704 motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
1706 event->dnd.x_root = private->last_x;
1707 event->dnd.y_root = private->last_y;
1709 private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
1711 return GDK_FILTER_TRANSLATE;
1714 return GDK_FILTER_REMOVE;
1717 static GdkFilterReturn
1718 motif_drop_start (GdkEvent *event,
1721 guint32 source_window,
1726 GdkDragContext *new_context;
1727 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1729 GDK_NOTE(DND, g_message ("Motif DND drop start: flags: %#4x time: %d (%d, %d) source_widow: %#4x atom: %d",
1730 flags, timestamp, x_root, y_root, source_window, atom));
1732 new_context = motif_drag_context_new (event->any.window, timestamp, source_window, atom);
1734 return GDK_FILTER_REMOVE;
1736 motif_dnd_translate_flags (new_context, flags);
1738 event->dnd.type = GDK_DROP_START;
1739 event->dnd.context = new_context;
1740 event->dnd.time = timestamp;
1741 event->dnd.x_root = x_root;
1742 event->dnd.y_root = y_root;
1744 gdk_x11_window_set_user_time (event->any.window, timestamp);
1746 g_object_ref (new_context);
1747 display_x11->current_dest_drag = new_context;
1749 return GDK_FILTER_TRANSLATE;
1752 static GdkFilterReturn
1753 motif_drag_status (GdkEvent *event,
1757 GdkDragContext *context;
1758 GdkDisplay *display;
1761 g_message ("Motif status message: flags %x", flags));
1763 display = gdk_drawable_get_display (event->any.window);
1765 return GDK_FILTER_REMOVE;
1767 context = gdk_drag_context_find (display, TRUE, GDK_DRAWABLE_XID (event->any.window), None);
1771 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1772 if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
1773 (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
1774 private->drag_status = GDK_DRAG_STATUS_DRAG;
1776 event->dnd.type = GDK_DRAG_STATUS;
1777 event->dnd.send_event = FALSE;
1778 event->dnd.context = context;
1779 g_object_ref (context);
1781 event->dnd.time = timestamp;
1783 if ((flags & 0x00f0) >> 4 == XmDROP_SITE_VALID)
1785 switch (flags & 0x000f)
1788 context->action = 0;
1791 context->action = GDK_ACTION_MOVE;
1794 context->action = GDK_ACTION_COPY;
1797 context->action = GDK_ACTION_LINK;
1802 context->action = 0;
1804 return GDK_FILTER_TRANSLATE;
1806 return GDK_FILTER_REMOVE;
1809 static GdkFilterReturn
1810 motif_dnd_filter (GdkXEvent *xev,
1814 XEvent *xevent = (XEvent *)xev;
1819 guint32 source_window;
1821 gint16 x_root, y_root;
1824 if (!event->any.window ||
1825 gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
1826 return GDK_FILTER_CONTINUE; /* Not for us */
1828 /* First read some fields common to all Motif DND messages */
1830 reason = MOTIF_UNPACK_BYTE (xevent, 0);
1831 flags = MOTIF_UNPACK_SHORT (xevent, 1);
1832 timestamp = MOTIF_UNPACK_LONG (xevent, 1);
1834 is_reply = ((reason & 0x80) != 0);
1836 switch (reason & 0x7f)
1838 case XmTOP_LEVEL_ENTER:
1839 source_window = MOTIF_UNPACK_LONG (xevent, 2);
1840 atom = MOTIF_UNPACK_LONG (xevent, 3);
1841 return motif_top_level_enter (event, flags, timestamp, source_window, atom);
1842 case XmTOP_LEVEL_LEAVE:
1843 return motif_top_level_leave (event, flags, timestamp);
1846 x_root = MOTIF_UNPACK_SHORT (xevent, 4);
1847 y_root = MOTIF_UNPACK_SHORT (xevent, 5);
1850 return motif_motion (event, flags, timestamp, x_root, y_root);
1852 return motif_drag_status (event, flags, timestamp);
1854 case XmDROP_SITE_ENTER:
1855 return motif_drag_status (event, flags, timestamp);
1857 case XmDROP_SITE_LEAVE:
1858 return motif_drag_status (event,
1859 XmNO_DROP_SITE << 8 | XmDROP_NOOP,
1862 x_root = MOTIF_UNPACK_SHORT (xevent, 4);
1863 y_root = MOTIF_UNPACK_SHORT (xevent, 5);
1864 atom = MOTIF_UNPACK_LONG (xevent, 3);
1865 source_window = MOTIF_UNPACK_LONG (xevent, 4);
1868 return motif_drop_start (event, flags, timestamp, source_window, atom, x_root, y_root);
1871 case XmOPERATION_CHANGED:
1873 return motif_operation_changed (event, flags, timestamp);
1875 return motif_drag_status (event, flags, timestamp);
1878 /* To the best of my knowledge, these next two messages are
1879 * not part of the protocol, though they are defined in
1883 case XmDRAG_DROP_FINISH:
1887 return GDK_FILTER_REMOVE;
1890 /*************************************************************
1891 ***************************** XDND **************************
1892 *************************************************************/
1894 /* Utility functions */
1899 GdkDragAction action;
1900 } xdnd_actions_table[] = {
1901 { "XdndActionCopy", None, GDK_ACTION_COPY },
1902 { "XdndActionMove", None, GDK_ACTION_MOVE },
1903 { "XdndActionLink", None, GDK_ACTION_LINK },
1904 { "XdndActionAsk", None, GDK_ACTION_ASK },
1905 { "XdndActionPrivate", None, GDK_ACTION_COPY },
1908 static const gint xdnd_n_actions = sizeof(xdnd_actions_table) / sizeof(xdnd_actions_table[0]);
1909 static gboolean xdnd_actions_initialized = FALSE;
1912 xdnd_initialize_actions (void)
1916 xdnd_actions_initialized = TRUE;
1917 for (i=0; i < xdnd_n_actions; i++)
1918 xdnd_actions_table[i].atom = gdk_atom_intern (xdnd_actions_table[i].name, FALSE);
1921 static GdkDragAction
1922 xdnd_action_from_atom (GdkDisplay *display,
1925 GdkAtom atom = gdk_x11_xatom_to_atom_for_display (display, xatom);
1928 if (!xdnd_actions_initialized)
1929 xdnd_initialize_actions();
1931 for (i=0; i<xdnd_n_actions; i++)
1932 if (atom == xdnd_actions_table[i].atom)
1933 return xdnd_actions_table[i].action;
1939 xdnd_action_to_atom (GdkDisplay *display,
1940 GdkDragAction action)
1944 if (!xdnd_actions_initialized)
1945 xdnd_initialize_actions();
1947 for (i=0; i<xdnd_n_actions; i++)
1948 if (action == xdnd_actions_table[i].action)
1949 return gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
1956 static GdkFilterReturn
1957 xdnd_status_filter (GdkXEvent *xev,
1961 GdkDisplay *display;
1962 XEvent *xevent = (XEvent *)xev;
1963 guint32 dest_window = xevent->xclient.data.l[0];
1964 guint32 flags = xevent->xclient.data.l[1];
1965 Atom action = xevent->xclient.data.l[4];
1966 GdkDragContext *context;
1968 if (!event->any.window ||
1969 gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
1970 return GDK_FILTER_CONTINUE; /* Not for us */
1973 g_message ("XdndStatus: dest_window: %#x action: %ld",
1974 dest_window, action));
1976 display = gdk_drawable_get_display (event->any.window);
1977 context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
1981 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1982 if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
1983 private->drag_status = GDK_DRAG_STATUS_DRAG;
1985 event->dnd.send_event = FALSE;
1986 event->dnd.type = GDK_DRAG_STATUS;
1987 event->dnd.context = context;
1988 g_object_ref (context);
1990 event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
1991 if (!(action != 0) != !(flags & 1))
1994 g_warning ("Received status event with flags not corresponding to action!\n"));
1998 context->action = xdnd_action_from_atom (display, action);
2000 return GDK_FILTER_TRANSLATE;
2003 return GDK_FILTER_REMOVE;
2006 static GdkFilterReturn
2007 xdnd_finished_filter (GdkXEvent *xev,
2011 GdkDisplay *display;
2012 XEvent *xevent = (XEvent *)xev;
2013 guint32 dest_window = xevent->xclient.data.l[0];
2014 GdkDragContext *context;
2015 GdkDragContextPrivateX11 *private;
2017 if (!event->any.window ||
2018 gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2019 return GDK_FILTER_CONTINUE; /* Not for us */
2022 g_message ("XdndFinished: dest_window: %#x", dest_window));
2024 display = gdk_drawable_get_display (event->any.window);
2025 context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
2029 private = PRIVATE_DATA (context);
2030 if (private->version == 5)
2031 private->drop_failed = xevent->xclient.data.l[1] == 0;
2033 event->dnd.type = GDK_DROP_FINISHED;
2034 event->dnd.context = context;
2035 g_object_ref (context);
2037 return GDK_FILTER_TRANSLATE;
2040 return GDK_FILTER_REMOVE;
2044 xdnd_set_targets (GdkDragContext *context)
2046 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2048 GList *tmp_list = context->targets;
2050 gint n_atoms = g_list_length (context->targets);
2051 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2053 atomlist = g_new (Atom, n_atoms);
2057 atomlist[i] = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (tmp_list->data));
2058 tmp_list = tmp_list->next;
2062 XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
2063 GDK_DRAWABLE_XID (context->source_window),
2064 gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
2065 XA_ATOM, 32, PropModeReplace,
2066 (guchar *)atomlist, n_atoms);
2070 private->xdnd_targets_set = 1;
2074 xdnd_set_actions (GdkDragContext *context)
2076 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2081 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2083 if (!xdnd_actions_initialized)
2084 xdnd_initialize_actions();
2086 actions = context->actions;
2088 for (i=0; i<xdnd_n_actions; i++)
2090 if (actions & xdnd_actions_table[i].action)
2092 actions &= ~xdnd_actions_table[i].action;
2097 atomlist = g_new (Atom, n_atoms);
2099 actions = context->actions;
2101 for (i=0; i<xdnd_n_actions; i++)
2103 if (actions & xdnd_actions_table[i].action)
2105 actions &= ~xdnd_actions_table[i].action;
2106 atomlist[n_atoms] = gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
2111 XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
2112 GDK_DRAWABLE_XID (context->source_window),
2113 gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
2114 XA_ATOM, 32, PropModeReplace,
2115 (guchar *)atomlist, n_atoms);
2119 private->xdnd_actions_set = TRUE;
2120 private->xdnd_actions = context->actions;
2124 send_client_message_async_cb (Window window,
2128 GdkDragContext *context = data;
2130 g_message ("Got async callback for #%lx, success = %d",
2133 /* On failure, we immediately continue with the protocol
2134 * so we don't end up blocking for a timeout
2137 context->dest_window &&
2138 window == GDK_WINDOW_XID (context->dest_window))
2140 GdkEvent temp_event;
2141 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2143 g_object_unref (context->dest_window);
2144 context->dest_window = NULL;
2145 context->action = 0;
2147 private->drag_status = GDK_DRAG_STATUS_DRAG;
2149 temp_event.dnd.type = GDK_DRAG_STATUS;
2150 temp_event.dnd.window = context->source_window;
2151 temp_event.dnd.send_event = TRUE;
2152 temp_event.dnd.context = context;
2153 temp_event.dnd.time = GDK_CURRENT_TIME;
2155 gdk_event_put (&temp_event);
2158 g_object_unref (context);
2163 gdk_drag_context_get_display (GdkDragContext *context)
2165 if (context->source_window)
2166 return GDK_DRAWABLE_DISPLAY (context->source_window);
2167 else if (context->dest_window)
2168 return GDK_DRAWABLE_DISPLAY (context->dest_window);
2170 g_assert_not_reached ();
2175 send_client_message_async (GdkDragContext *context,
2179 XClientMessageEvent *event_send)
2181 GdkDisplay *display = gdk_drag_context_get_display (context);
2183 g_object_ref (context);
2185 _gdk_x11_send_client_message_async (display, window,
2186 propagate, event_mask, event_send,
2187 send_client_message_async_cb, context);
2191 xdnd_send_xevent (GdkDragContext *context,
2196 GdkDisplay *display = gdk_drag_context_get_display (context);
2200 g_assert (event_send->xany.type == ClientMessage);
2202 /* We short-circuit messages to ourselves */
2203 if (gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
2207 for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
2209 if (gdk_x11_get_xatom_by_name_for_display (display, xdnd_filters[i].atom_name) ==
2210 event_send->xclient.message_type)
2212 GdkEvent temp_event;
2213 temp_event.any.window = window;
2215 if ((*xdnd_filters[i].func) (event_send, &temp_event, NULL) == GDK_FILTER_TRANSLATE)
2217 gdk_event_put (&temp_event);
2218 g_object_unref (temp_event.dnd.context);
2226 xwindow = GDK_WINDOW_XWINDOW (window);
2228 if (_gdk_x11_display_is_root_window (display, xwindow))
2229 event_mask = ButtonPressMask;
2233 send_client_message_async (context, xwindow, propagate, event_mask,
2234 &event_send->xclient);
2240 xdnd_send_enter (GdkDragContext *context)
2243 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2244 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->dest_window);
2246 xev.xclient.type = ClientMessage;
2247 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndEnter");
2248 xev.xclient.format = 32;
2249 xev.xclient.window = private->drop_xid ?
2251 GDK_DRAWABLE_XID (context->dest_window);
2252 xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2253 xev.xclient.data.l[1] = (private->version << 24); /* version */
2254 xev.xclient.data.l[2] = 0;
2255 xev.xclient.data.l[3] = 0;
2256 xev.xclient.data.l[4] = 0;
2259 g_message ("Sending enter source window %#lx XDND protocol version %d\n",
2260 GDK_DRAWABLE_XID (context->source_window), private->version));
2261 if (g_list_length (context->targets) > 3)
2263 if (!private->xdnd_targets_set)
2264 xdnd_set_targets (context);
2265 xev.xclient.data.l[1] |= 1;
2269 GList *tmp_list = context->targets;
2274 xev.xclient.data.l[i] = gdk_x11_atom_to_xatom_for_display (display,
2275 GDK_POINTER_TO_ATOM (tmp_list->data));
2276 tmp_list = tmp_list->next;
2281 if (!xdnd_send_xevent (context, context->dest_window,
2285 g_message ("Send event to %lx failed",
2286 GDK_DRAWABLE_XID (context->dest_window)));
2287 g_object_unref (context->dest_window);
2288 context->dest_window = NULL;
2293 xdnd_send_leave (GdkDragContext *context)
2295 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2298 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2300 xev.xclient.type = ClientMessage;
2301 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndLeave");
2302 xev.xclient.format = 32;
2303 xev.xclient.window = private->drop_xid ?
2305 GDK_DRAWABLE_XID (context->dest_window);
2306 xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2307 xev.xclient.data.l[1] = 0;
2308 xev.xclient.data.l[2] = 0;
2309 xev.xclient.data.l[3] = 0;
2310 xev.xclient.data.l[4] = 0;
2312 if (!xdnd_send_xevent (context, context->dest_window,
2316 g_message ("Send event to %lx failed",
2317 GDK_DRAWABLE_XID (context->dest_window)));
2318 g_object_unref (context->dest_window);
2319 context->dest_window = NULL;
2324 xdnd_send_drop (GdkDragContext *context, guint32 time)
2326 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2327 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2330 xev.xclient.type = ClientMessage;
2331 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndDrop");
2332 xev.xclient.format = 32;
2333 xev.xclient.window = private->drop_xid ?
2335 GDK_DRAWABLE_XID (context->dest_window);
2336 xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2337 xev.xclient.data.l[1] = 0;
2338 xev.xclient.data.l[2] = time;
2339 xev.xclient.data.l[3] = 0;
2340 xev.xclient.data.l[4] = 0;
2342 if (!xdnd_send_xevent (context, context->dest_window,
2346 g_message ("Send event to %lx failed",
2347 GDK_DRAWABLE_XID (context->dest_window)));
2348 g_object_unref (context->dest_window);
2349 context->dest_window = NULL;
2354 xdnd_send_motion (GdkDragContext *context,
2357 GdkDragAction action,
2360 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2361 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2364 xev.xclient.type = ClientMessage;
2365 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndPosition");
2366 xev.xclient.format = 32;
2367 xev.xclient.window = private->drop_xid ?
2369 GDK_DRAWABLE_XID (context->dest_window);
2370 xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2371 xev.xclient.data.l[1] = 0;
2372 xev.xclient.data.l[2] = (x_root << 16) | y_root;
2373 xev.xclient.data.l[3] = time;
2374 xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
2376 if (!xdnd_send_xevent (context, context->dest_window,
2380 g_message ("Send event to %lx failed",
2381 GDK_DRAWABLE_XID (context->dest_window)));
2382 g_object_unref (context->dest_window);
2383 context->dest_window = NULL;
2385 private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
2389 xdnd_check_dest (GdkDisplay *display,
2393 gboolean retval = FALSE;
2396 unsigned long nitems, after;
2401 Atom xdnd_proxy_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndProxy");
2402 Atom xdnd_aware_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndAware");
2406 gdk_error_trap_push ();
2408 if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win,
2410 1, False, AnyPropertyType,
2411 &type, &format, &nitems, &after,
2416 proxy_data = (Window *)data;
2418 if ((format == 32) && (nitems == 1))
2420 proxy = *proxy_data;
2424 g_warning ("Invalid XdndProxy "
2425 "property on window %ld\n", win));
2430 if ((XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), proxy ? proxy : win,
2432 1, False, AnyPropertyType,
2433 &type, &format, &nitems, &after,
2434 &data) == Success) &&
2437 version = (Atom *)data;
2439 if ((format == 32) && (nitems == 1))
2444 *xdnd_version = *version;
2448 g_warning ("Invalid XdndAware "
2449 "property on window %ld\n", win));
2455 gdk_error_trap_pop ();
2457 return retval ? (proxy ? proxy : win) : None;
2463 xdnd_read_actions (GdkDragContext *context)
2465 GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
2468 gulong nitems, after;
2474 PRIVATE_DATA (context)->xdnd_have_actions = FALSE;
2476 if (gdk_window_get_window_type (context->source_window) == GDK_WINDOW_FOREIGN)
2478 /* Get the XdndActionList, if set */
2480 gdk_error_trap_push ();
2482 if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
2483 GDK_DRAWABLE_XID (context->source_window),
2484 gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
2486 False, XA_ATOM, &type, &format, &nitems,
2487 &after, &data) == Success &&
2490 atoms = (Atom *)data;
2492 context->actions = 0;
2494 for (i=0; i<nitems; i++)
2495 context->actions |= xdnd_action_from_atom (display, atoms[i]);
2497 PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
2499 #ifdef G_ENABLE_DEBUG
2500 if (_gdk_debug_flags & GDK_DEBUG_DND)
2502 GString *action_str = g_string_new (NULL);
2503 if (context->actions & GDK_ACTION_MOVE)
2504 g_string_append(action_str, "MOVE ");
2505 if (context->actions & GDK_ACTION_COPY)
2506 g_string_append(action_str, "COPY ");
2507 if (context->actions & GDK_ACTION_LINK)
2508 g_string_append(action_str, "LINK ");
2509 if (context->actions & GDK_ACTION_ASK)
2510 g_string_append(action_str, "ASK ");
2512 g_message("Xdnd actions = %s", action_str->str);
2513 g_string_free (action_str, TRUE);
2515 #endif /* G_ENABLE_DEBUG */
2520 gdk_error_trap_pop ();
2526 GdkDragContext *source_context;
2528 source_context = gdk_drag_context_find (display, TRUE,
2529 GDK_DRAWABLE_XID (context->source_window),
2530 GDK_DRAWABLE_XID (context->dest_window));
2534 context->actions = source_context->actions;
2535 PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
2540 /* We have to make sure that the XdndActionList we keep internally
2541 * is up to date with the XdndActionList on the source window
2542 * because we get no notification, because Xdnd wasn't meant
2543 * to continually send actions. So we select on PropertyChangeMask
2544 * and add this filter.
2546 static GdkFilterReturn
2547 xdnd_source_window_filter (GdkXEvent *xev,
2551 XEvent *xevent = (XEvent *)xev;
2552 GdkDragContext *context = cb_data;
2553 GdkDisplay *display = GDK_WINDOW_DISPLAY(event->any.window);
2555 if ((xevent->xany.type == PropertyNotify) &&
2556 (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList")))
2558 xdnd_read_actions (context);
2560 return GDK_FILTER_REMOVE;
2563 return GDK_FILTER_CONTINUE;
2567 xdnd_manage_source_filter (GdkDragContext *context,
2569 gboolean add_filter)
2571 if (!GDK_WINDOW_DESTROYED (window) &&
2572 gdk_window_get_window_type (window) == GDK_WINDOW_FOREIGN)
2574 gdk_error_trap_push ();
2578 gdk_window_set_events (window,
2579 gdk_window_get_events (window) |
2580 GDK_PROPERTY_CHANGE_MASK);
2581 gdk_window_add_filter (window, xdnd_source_window_filter, context);
2585 gdk_window_remove_filter (window,
2586 xdnd_source_window_filter,
2588 /* Should we remove the GDK_PROPERTY_NOTIFY mask?
2589 * but we might want it for other reasons. (Like
2590 * INCR selection transactions).
2594 gdk_display_sync (gdk_drawable_get_display (window));
2595 gdk_error_trap_pop ();
2600 base_precache_atoms (GdkDisplay *display)
2602 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
2604 if (!display_x11->base_dnd_atoms_precached)
2606 static const char *const precache_atoms[] = {
2607 "ENLIGHTENMENT_DESKTOP",
2611 "_MOTIF_DRAG_RECEIVER_INFO"
2614 _gdk_x11_precache_atoms (display,
2615 precache_atoms, G_N_ELEMENTS (precache_atoms));
2617 display_x11->base_dnd_atoms_precached = TRUE;
2622 xdnd_precache_atoms (GdkDisplay *display)
2624 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
2626 if (!display_x11->xdnd_atoms_precached)
2628 static const char *const precache_atoms[] = {
2634 "XdndActionPrivate",
2645 _gdk_x11_precache_atoms (display,
2646 precache_atoms, G_N_ELEMENTS (precache_atoms));
2648 display_x11->xdnd_atoms_precached = TRUE;
2652 static GdkFilterReturn
2653 xdnd_enter_filter (GdkXEvent *xev,
2657 GdkDisplay *display;
2658 GdkDisplayX11 *display_x11;
2659 XEvent *xevent = (XEvent *)xev;
2660 GdkDragContext *new_context;
2665 gulong nitems, after;
2669 guint32 source_window;
2673 if (!event->any.window ||
2674 gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2675 return GDK_FILTER_CONTINUE; /* Not for us */
2677 source_window = xevent->xclient.data.l[0];
2678 get_types = ((xevent->xclient.data.l[1] & 1) != 0);
2679 version = (xevent->xclient.data.l[1] & 0xff000000) >> 24;
2681 display = GDK_DRAWABLE_DISPLAY (event->any.window);
2682 display_x11 = GDK_DISPLAY_X11 (display);
2684 xdnd_precache_atoms (display);
2687 g_message ("XdndEnter: source_window: %#x, version: %#x",
2688 source_window, version));
2692 /* Old source ignore */
2693 GDK_NOTE (DND, g_message ("Ignored old XdndEnter message"));
2694 return GDK_FILTER_REMOVE;
2697 if (display_x11->current_dest_drag != NULL)
2699 g_object_unref (display_x11->current_dest_drag);
2700 display_x11->current_dest_drag = NULL;
2703 new_context = gdk_drag_context_new ();
2704 new_context->protocol = GDK_DRAG_PROTO_XDND;
2705 PRIVATE_DATA(new_context)->version = version;
2707 new_context->source_window = gdk_window_lookup_for_display (display, source_window);
2708 if (new_context->source_window)
2709 g_object_ref (new_context->source_window);
2712 new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
2713 if (!new_context->source_window)
2715 g_object_unref (new_context);
2716 return GDK_FILTER_REMOVE;
2719 new_context->dest_window = event->any.window;
2720 g_object_ref (new_context->dest_window);
2722 new_context->targets = NULL;
2725 gdk_error_trap_push ();
2726 XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (event->any.window),
2728 gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
2730 False, XA_ATOM, &type, &format, &nitems,
2733 if (gdk_error_trap_pop () || (format != 32) || (type != XA_ATOM))
2735 g_object_unref (new_context);
2736 return GDK_FILTER_REMOVE;
2739 atoms = (Atom *)data;
2741 for (i=0; i<nitems; i++)
2742 new_context->targets =
2743 g_list_append (new_context->targets,
2744 GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display,
2752 if (xevent->xclient.data.l[2+i])
2753 new_context->targets =
2754 g_list_append (new_context->targets,
2755 GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display,
2756 xevent->xclient.data.l[2+i])));
2759 #ifdef G_ENABLE_DEBUG
2760 if (_gdk_debug_flags & GDK_DEBUG_DND)
2761 print_target_list (new_context->targets);
2762 #endif /* G_ENABLE_DEBUG */
2764 xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
2765 xdnd_read_actions (new_context);
2767 event->dnd.type = GDK_DRAG_ENTER;
2768 event->dnd.context = new_context;
2769 g_object_ref (new_context);
2771 display_x11->current_dest_drag = new_context;
2773 return GDK_FILTER_TRANSLATE;
2776 static GdkFilterReturn
2777 xdnd_leave_filter (GdkXEvent *xev,
2781 XEvent *xevent = (XEvent *)xev;
2782 guint32 source_window = xevent->xclient.data.l[0];
2783 GdkDisplay *display;
2784 GdkDisplayX11 *display_x11;
2786 if (!event->any.window ||
2787 gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2788 return GDK_FILTER_CONTINUE; /* Not for us */
2791 g_message ("XdndLeave: source_window: %#x",
2794 display = GDK_DRAWABLE_DISPLAY (event->any.window);
2795 display_x11 = GDK_DISPLAY_X11 (display);
2797 xdnd_precache_atoms (display);
2799 if ((display_x11->current_dest_drag != NULL) &&
2800 (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
2801 (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
2803 event->dnd.type = GDK_DRAG_LEAVE;
2804 /* Pass ownership of context to the event */
2805 event->dnd.context = display_x11->current_dest_drag;
2807 display_x11->current_dest_drag = NULL;
2809 return GDK_FILTER_TRANSLATE;
2812 return GDK_FILTER_REMOVE;
2815 static GdkFilterReturn
2816 xdnd_position_filter (GdkXEvent *xev,
2820 XEvent *xevent = (XEvent *)xev;
2821 guint32 source_window = xevent->xclient.data.l[0];
2822 gint16 x_root = xevent->xclient.data.l[2] >> 16;
2823 gint16 y_root = xevent->xclient.data.l[2] & 0xffff;
2824 guint32 time = xevent->xclient.data.l[3];
2825 Atom action = xevent->xclient.data.l[4];
2827 GdkDisplay *display;
2828 GdkDisplayX11 *display_x11;
2830 if (!event->any.window ||
2831 gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2832 return GDK_FILTER_CONTINUE; /* Not for us */
2835 g_message ("XdndPosition: source_window: %#x position: (%d, %d) time: %d action: %ld",
2836 source_window, x_root, y_root, time, action));
2838 display = GDK_DRAWABLE_DISPLAY (event->any.window);
2839 display_x11 = GDK_DISPLAY_X11 (display);
2841 xdnd_precache_atoms (display);
2843 if ((display_x11->current_dest_drag != NULL) &&
2844 (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
2845 (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
2847 event->dnd.type = GDK_DRAG_MOTION;
2848 event->dnd.context = display_x11->current_dest_drag;
2849 g_object_ref (display_x11->current_dest_drag);
2851 event->dnd.time = time;
2853 display_x11->current_dest_drag->suggested_action = xdnd_action_from_atom (display, action);
2855 if (!(PRIVATE_DATA (display_x11->current_dest_drag))->xdnd_have_actions)
2856 display_x11->current_dest_drag->actions = display_x11->current_dest_drag->suggested_action;
2858 event->dnd.x_root = x_root;
2859 event->dnd.y_root = y_root;
2861 (PRIVATE_DATA (display_x11->current_dest_drag))->last_x = x_root;
2862 (PRIVATE_DATA (display_x11->current_dest_drag))->last_y = y_root;
2864 return GDK_FILTER_TRANSLATE;
2867 return GDK_FILTER_REMOVE;
2870 static GdkFilterReturn
2871 xdnd_drop_filter (GdkXEvent *xev,
2875 XEvent *xevent = (XEvent *)xev;
2876 guint32 source_window = xevent->xclient.data.l[0];
2877 guint32 time = xevent->xclient.data.l[2];
2878 GdkDisplay *display;
2879 GdkDisplayX11 *display_x11;
2881 if (!event->any.window ||
2882 gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2883 return GDK_FILTER_CONTINUE; /* Not for us */
2886 g_message ("XdndDrop: source_window: %#x time: %d",
2887 source_window, time));
2889 display = GDK_DRAWABLE_DISPLAY (event->any.window);
2890 display_x11 = GDK_DISPLAY_X11 (display);
2892 xdnd_precache_atoms (display);
2894 if ((display_x11->current_dest_drag != NULL) &&
2895 (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
2896 (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
2898 GdkDragContextPrivateX11 *private;
2899 private = PRIVATE_DATA (display_x11->current_dest_drag);
2901 event->dnd.type = GDK_DROP_START;
2903 event->dnd.context = display_x11->current_dest_drag;
2904 g_object_ref (display_x11->current_dest_drag);
2906 event->dnd.time = time;
2907 event->dnd.x_root = private->last_x;
2908 event->dnd.y_root = private->last_y;
2910 gdk_x11_window_set_user_time (event->any.window, time);
2912 return GDK_FILTER_TRANSLATE;
2915 return GDK_FILTER_REMOVE;
2918 /*************************************************************
2919 ************************** Public API ***********************
2920 *************************************************************/
2922 _gdk_dnd_init (GdkDisplay *display)
2927 gdk_display_add_client_message_filter (
2929 gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE),
2930 motif_dnd_filter, NULL);
2932 for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
2934 gdk_display_add_client_message_filter (
2936 gdk_atom_intern (xdnd_filters[i].atom_name, FALSE),
2937 xdnd_filters[i].func, NULL);
2944 gdk_drag_do_leave (GdkDragContext *context, guint32 time)
2946 if (context->dest_window)
2948 switch (context->protocol)
2950 case GDK_DRAG_PROTO_MOTIF:
2951 motif_send_leave (context, time);
2953 case GDK_DRAG_PROTO_XDND:
2954 xdnd_send_leave (context);
2956 case GDK_DRAG_PROTO_ROOTWIN:
2957 case GDK_DRAG_PROTO_NONE:
2962 g_object_unref (context->dest_window);
2963 context->dest_window = NULL;
2969 * @window: the source window for this drag.
2970 * @targets: the list of offered targets.
2972 * Starts a drag and creates a new drag context for it.
2974 * This function is called by the drag source.
2976 * Return value: a newly created #GdkDragContext.
2979 gdk_drag_begin (GdkWindow *window,
2982 GdkDragContext *new_context;
2984 g_return_val_if_fail (window != NULL, NULL);
2986 new_context = gdk_drag_context_new ();
2987 new_context->is_source = TRUE;
2988 new_context->source_window = window;
2989 g_object_ref (window);
2991 new_context->targets = g_list_copy (targets);
2992 precache_target_list (new_context);
2994 new_context->actions = 0;
3000 _gdk_drag_get_protocol_for_display (GdkDisplay *display,
3002 GdkDragProtocol *protocol,
3008 g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
3010 base_precache_atoms (display);
3012 /* Check for a local drag
3014 window = gdk_window_lookup_for_display (display, xid);
3016 gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
3018 if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
3020 *protocol = GDK_DRAG_PROTO_XDND;
3022 xdnd_precache_atoms (display);
3023 GDK_NOTE (DND, g_message ("Entering local Xdnd window %#x\n", xid));
3030 if ((retval = xdnd_check_dest (display, xid, version)))
3032 *protocol = GDK_DRAG_PROTO_XDND;
3033 xdnd_precache_atoms (display);
3034 GDK_NOTE (DND, g_message ("Entering Xdnd window %#x\n", xid));
3037 else if ((retval = motif_check_dest (display, xid)))
3039 *protocol = GDK_DRAG_PROTO_MOTIF;
3040 GDK_NOTE (DND, g_message ("Entering motif window %#x\n", xid));
3045 /* Check if this is a root window */
3047 gboolean rootwin = FALSE;
3050 unsigned long nitems, after;
3051 unsigned char *data;
3053 if (_gdk_x11_display_is_root_window (display, (Window) xid))
3056 gdk_error_trap_push ();
3060 if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid,
3061 gdk_x11_get_xatom_by_name_for_display (display, "ENLIGHTENMENT_DESKTOP"),
3062 0, 0, False, AnyPropertyType,
3063 &type, &format, &nitems, &after, &data) == Success &&
3071 /* Until I find out what window manager the next one is for,
3072 * I'm leaving it commented out. It's supported in the
3073 * xscreensaver sources, though.
3078 if (XGetWindowProperty (gdk_display, win,
3079 gdk_x11_get_xatom_by_name ("__SWM_VROOT"),
3080 0, 0, False, AnyPropertyType,
3081 &type, &format, &nitems, &data) &&
3087 gdk_error_trap_pop ();
3091 *protocol = GDK_DRAG_PROTO_ROOTWIN;
3096 *protocol = GDK_DRAG_PROTO_NONE;
3101 * gdk_drag_get_protocol_for_display:
3102 * @display: the #GdkDisplay where the destination window resides
3103 * @xid: the X id of the destination window.
3104 * @protocol: location where the supported DND protocol is returned.
3105 * @returns: the X id of the window where the drop should happen. This
3106 * may be @xid or the X id of a proxy window, or None if @xid doesn't
3107 * support Drag and Drop.
3109 * Finds out the DND protocol supported by a window.
3114 gdk_drag_get_protocol_for_display (GdkDisplay *display,
3116 GdkDragProtocol *protocol)
3118 return _gdk_drag_get_protocol_for_display (display, xid, protocol, NULL);
3121 static GdkWindowCache *
3122 drag_context_find_window_cache (GdkDragContext *context,
3125 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3127 GdkWindowCache *cache;
3129 for (tmp_list = private->window_caches; tmp_list; tmp_list = tmp_list->next)
3131 cache = tmp_list->data;
3132 if (cache->screen == screen)
3136 cache = gdk_window_cache_new (screen);
3137 private->window_caches = g_slist_prepend (private->window_caches, cache);
3143 * gdk_drag_find_window_for_screen:
3144 * @context: a #GdkDragContext
3145 * @drag_window: a window which may be at the pointer position, but
3146 * should be ignored, since it is put up by the drag source as an icon.
3147 * @screen: the screen where the destination window is sought.
3148 * @x_root: the x position of the pointer in root coordinates.
3149 * @y_root: the y position of the pointer in root coordinates.
3150 * @dest_window: location to store the destination window in.
3151 * @protocol: location to store the DND protocol in.
3153 * Finds the destination window and DND protocol to use at the
3154 * given pointer position.
3156 * This function is called by the drag source to obtain the
3157 * @dest_window and @protocol parameters for gdk_drag_motion().
3162 gdk_drag_find_window_for_screen (GdkDragContext *context,
3163 GdkWindow *drag_window,
3167 GdkWindow **dest_window,
3168 GdkDragProtocol *protocol)
3170 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3171 GdkWindowCache *window_cache;
3172 GdkDisplay *display;
3175 g_return_if_fail (context != NULL);
3177 display = GDK_WINDOW_DISPLAY (context->source_window);
3179 window_cache = drag_context_find_window_cache (context, screen);
3181 dest = get_client_window_at_coords (window_cache,
3183 GDK_DRAWABLE_XID (drag_window) : None,
3186 if (private->dest_xid != dest)
3189 private->dest_xid = dest;
3191 /* Check if new destination accepts drags, and which protocol */
3193 /* There is some ugliness here. We actually need to pass
3194 * _three_ pieces of information to drag_motion - dest_window,
3195 * protocol, and the XID of the unproxied window. The first
3196 * two are passed explicitely, the third implicitly through
3197 * protocol->dest_xid.
3199 if ((recipient = _gdk_drag_get_protocol_for_display (display, dest,
3200 protocol, &private->version)))
3202 *dest_window = gdk_window_lookup_for_display (display, recipient);
3204 g_object_ref (*dest_window);
3206 *dest_window = gdk_window_foreign_new_for_display (display, recipient);
3209 *dest_window = NULL;
3213 *dest_window = context->dest_window;
3215 g_object_ref (*dest_window);
3216 *protocol = context->protocol;
3222 * @context: a #GdkDragContext.
3223 * @dest_window: the new destination window, obtained by
3224 * gdk_drag_find_window().
3225 * @protocol: the DND protocol in use, obtained by gdk_drag_find_window().
3226 * @x_root: the x position of the pointer in root coordinates.
3227 * @y_root: the y position of the pointer in root coordinates.
3228 * @suggested_action: the suggested action.
3229 * @possible_actions: the possible actions.
3230 * @time_: the timestamp for this operation.
3232 * Updates the drag context when the pointer moves or the
3233 * set of actions changes.
3235 * This function is called by the drag source.
3237 * Return value: FIXME
3240 gdk_drag_motion (GdkDragContext *context,
3241 GdkWindow *dest_window,
3242 GdkDragProtocol protocol,
3245 GdkDragAction suggested_action,
3246 GdkDragAction possible_actions,
3249 GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3251 g_return_val_if_fail (context != NULL, FALSE);
3253 private->old_actions = context->actions;
3254 context->actions = possible_actions;
3256 if (private->old_actions != possible_actions)
3257 private->xdnd_actions_set = FALSE;
3259 if (protocol == GDK_DRAG_PROTO_XDND && private->version == 0)
3261 /* This ugly hack is necessary since GTK+ doesn't know about
3262 * the XDND protocol version, and in particular doesn't know
3263 * that gdk_drag_find_window_for_screen() has the side-effect
3264 * of setting private->version, and therefore sometimes call
3265 * gdk_drag_motion() without a prior call to
3266 * gdk_drag_find_window_for_screen(). This happens, e.g.
3267 * when GTK+ is proxying DND events to embedded windows.
3271 GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
3273 xdnd_check_dest (display,
3274 GDK_DRAWABLE_XID (dest_window),
3279 /* When we have a Xdnd target, make sure our XdndActionList
3280 * matches the current actions;
3282 if (protocol == GDK_DRAG_PROTO_XDND && !private->xdnd_actions_set)
3286 if (gdk_window_get_window_type (dest_window) == GDK_WINDOW_FOREIGN)
3287 xdnd_set_actions (context);
3288 else if (context->dest_window == dest_window)
3290 GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
3291 GdkDragContext *dest_context;
3293 dest_context = gdk_drag_context_find (display, FALSE,
3294 GDK_DRAWABLE_XID (context->source_window),
3295 GDK_DRAWABLE_XID (dest_window));
3299 dest_context->actions = context->actions;
3300 PRIVATE_DATA (dest_context)->xdnd_have_actions = TRUE;
3306 if (context->dest_window != dest_window)
3308 GdkEvent temp_event;
3310 /* Send a leave to the last destination */
3311 gdk_drag_do_leave (context, time);
3312 private->drag_status = GDK_DRAG_STATUS_DRAG;
3314 /* Check if new destination accepts drags, and which protocol */
3318 context->dest_window = dest_window;
3319 private->drop_xid = private->dest_xid;
3320 g_object_ref (context->dest_window);
3321 context->protocol = protocol;
3325 case GDK_DRAG_PROTO_MOTIF:
3326 motif_send_enter (context, time);
3329 case GDK_DRAG_PROTO_XDND:
3330 xdnd_send_enter (context);
3333 case GDK_DRAG_PROTO_ROOTWIN:
3334 case GDK_DRAG_PROTO_NONE:
3338 private->old_action = suggested_action;
3339 context->suggested_action = suggested_action;
3340 private->old_actions = possible_actions;
3344 context->dest_window = NULL;
3345 private->drop_xid = None;
3346 context->action = 0;
3349 /* Push a status event, to let the client know that
3353 temp_event.dnd.type = GDK_DRAG_STATUS;
3354 temp_event.dnd.window = context->source_window;
3355 /* We use this to signal a synthetic status. Perhaps
3356 * we should use an extra field...
3358 temp_event.dnd.send_event = TRUE;
3360 temp_event.dnd.context = context;
3361 temp_event.dnd.time = time;
3363 gdk_event_put (&temp_event);
3367 private->old_action = context->suggested_action;
3368 context->suggested_action = suggested_action;
3371 /* Send a drag-motion event */
3373 private->last_x = x_root;
3374 private->last_y = y_root;
3376 if (context->dest_window)
3378 if (private->drag_status == GDK_DRAG_STATUS_DRAG)
3380 switch (context->protocol)
3382 case GDK_DRAG_PROTO_MOTIF:
3383 motif_send_motion (context, x_root, y_root, suggested_action, time);
3386 case GDK_DRAG_PROTO_XDND:
3387 xdnd_send_motion (context, x_root, y_root, suggested_action, time);
3390 case GDK_DRAG_PROTO_ROOTWIN:
3392 GdkEvent temp_event;
3393 /* GTK+ traditionally has used application/x-rootwin-drop,
3394 * but the XDND spec specifies x-rootwindow-drop.
3396 GdkAtom target1 = gdk_atom_intern ("application/x-rootwindow-drop", FALSE);
3397 GdkAtom target2 = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
3399 if (g_list_find (context->targets,
3400 GDK_ATOM_TO_POINTER (target1)) ||
3401 g_list_find (context->targets,
3402 GDK_ATOM_TO_POINTER (target2)))
3403 context->action = context->suggested_action;
3405 context->action = 0;
3407 temp_event.dnd.type = GDK_DRAG_STATUS;
3408 temp_event.dnd.window = context->source_window;
3409 temp_event.dnd.send_event = FALSE;
3410 temp_event.dnd.context = context;
3411 temp_event.dnd.time = time;
3413 gdk_event_put (&temp_event);
3416 case GDK_DRAG_PROTO_NONE:
3417 g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
3432 * @context: a #GdkDragContext.
3433 * @time_: the timestamp for this operation.
3435 * Drops on the current destination.
3437 * This function is called by the drag source.
3440 gdk_drag_drop (GdkDragContext *context,
3443 g_return_if_fail (context != NULL);
3445 if (context->dest_window)
3447 switch (context->protocol)
3449 case GDK_DRAG_PROTO_MOTIF:
3450 motif_send_leave (context, time);
3451 motif_send_drop (context, time);
3454 case GDK_DRAG_PROTO_XDND:
3455 xdnd_send_drop (context, time);
3458 case GDK_DRAG_PROTO_ROOTWIN:
3459 g_warning ("Drops for GDK_DRAG_PROTO_ROOTWIN must be handled internally");
3461 case GDK_DRAG_PROTO_NONE:
3462 g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
3472 * @context: a #GdkDragContext.
3473 * @time_: the timestamp for this operation.
3475 * Aborts a drag without dropping.
3477 * This function is called by the drag source.
3480 gdk_drag_abort (GdkDragContext *context,
3483 g_return_if_fail (context != NULL);
3485 gdk_drag_do_leave (context, time);
3488 /* Destination side */
3492 * @context: a #GdkDragContext.
3493 * @action: the selected action which will be taken when a drop happens,
3494 * or 0 to indicate that a drop will not be accepted.
3495 * @time_: the timestamp for this operation.
3497 * Selects one of the actions offered by the drag source.
3499 * This function is called by the drag destination in response to
3500 * gdk_drag_motion() called by the drag source.
3503 gdk_drag_status (GdkDragContext *context,
3504 GdkDragAction action,
3507 GdkDragContextPrivateX11 *private;
3509 GdkDisplay *display;
3511 g_return_if_fail (context != NULL);
3513 private = PRIVATE_DATA (context);
3514 display = GDK_DRAWABLE_DISPLAY (context->source_window);
3516 context->action = action;
3518 if (context->protocol == GDK_DRAG_PROTO_MOTIF)
3520 gboolean need_coords = FALSE;
3522 xev.xclient.type = ClientMessage;
3523 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
3524 "_MOTIF_DRAG_AND_DROP_MESSAGE");
3525 xev.xclient.format = 8;
3526 xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3528 if (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT)
3530 MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED | 0x80;
3534 if ((action != 0) != (private->old_action != 0))
3538 MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_ENTER | 0x80;
3542 MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_LEAVE | 0x80;
3546 MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION | 0x80;
3551 MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
3555 case GDK_ACTION_MOVE:
3556 MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_MOVE;
3558 case GDK_ACTION_COPY:
3559 MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY;
3561 case GDK_ACTION_LINK:
3562 MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_LINK;
3565 MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP;
3570 MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmDROP_SITE_VALID << 4);
3572 MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmNO_DROP_SITE << 4);
3574 MOTIF_XCLIENT_LONG (&xev, 1) = time;
3578 MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
3579 MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
3582 MOTIF_XCLIENT_LONG (&xev, 2) = 0;
3584 MOTIF_XCLIENT_LONG (&xev, 3) = 0;
3585 MOTIF_XCLIENT_LONG (&xev, 4) = 0;
3587 if (!_gdk_send_xevent (display,
3588 GDK_DRAWABLE_XID (context->source_window),
3591 g_message ("Send event to %lx failed",
3592 GDK_DRAWABLE_XID (context->source_window)));
3594 else if (context->protocol == GDK_DRAG_PROTO_XDND)
3596 xev.xclient.type = ClientMessage;
3597 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndStatus");
3598 xev.xclient.format = 32;
3599 xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3601 xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
3602 xev.xclient.data.l[1] = (action != 0) ? (2 | 1) : 0;
3603 xev.xclient.data.l[2] = 0;
3604 xev.xclient.data.l[3] = 0;
3605 xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
3607 if (!xdnd_send_xevent (context, context->source_window,
3610 g_message ("Send event to %lx failed",
3611 GDK_DRAWABLE_XID (context->source_window)));
3614 private->old_action = action;
3619 * @context: a #GdkDragContext.
3620 * @ok: %TRUE if the drop is accepted.
3621 * @time_: the timestamp for this operation.
3623 * Accepts or rejects a drop.
3625 * This function is called by the drag destination in response
3626 * to a drop initiated by the drag source.
3629 gdk_drop_reply (GdkDragContext *context,
3633 GdkDragContextPrivateX11 *private;
3635 g_return_if_fail (context != NULL);
3637 private = PRIVATE_DATA (context);
3639 if (context->protocol == GDK_DRAG_PROTO_MOTIF)
3641 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
3644 xev.xclient.type = ClientMessage;
3645 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
3646 "_MOTIF_DRAG_AND_DROP_MESSAGE");
3647 xev.xclient.format = 8;
3649 MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START | 0x80;
3650 MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
3652 MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY |
3653 (XmDROP_SITE_VALID << 4) |
3654 (XmDROP_NOOP << 8) |
3657 MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP |
3658 (XmNO_DROP_SITE << 4) |
3659 (XmDROP_NOOP << 8) |
3660 (XmDROP_CANCEL << 12);
3661 MOTIF_XCLIENT_SHORT (&xev, 2) = private->last_x;
3662 MOTIF_XCLIENT_SHORT (&xev, 3) = private->last_y;
3663 MOTIF_XCLIENT_LONG (&xev, 2) = 0;
3664 MOTIF_XCLIENT_LONG (&xev, 3) = 0;
3665 MOTIF_XCLIENT_LONG (&xev, 4) = 0;
3667 _gdk_send_xevent (display,
3668 GDK_DRAWABLE_XID (context->source_window),
3675 * @context: a #GtkDragContext.
3676 * @success: %TRUE if the data was successfully received.
3677 * @time_: the timestamp for this operation.
3679 * Ends the drag operation after a drop.
3681 * This function is called by the drag destination.
3684 gdk_drop_finish (GdkDragContext *context,
3688 g_return_if_fail (context != NULL);
3690 if (context->protocol == GDK_DRAG_PROTO_XDND)
3692 GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
3695 xev.xclient.type = ClientMessage;
3696 xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndFinished");
3697 xev.xclient.format = 32;
3698 xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3700 xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
3703 xev.xclient.data.l[1] = 1;
3704 xev.xclient.data.l[2] = xdnd_action_to_atom (display,
3709 xev.xclient.data.l[1] = 0;
3710 xev.xclient.data.l[2] = None;
3712 xev.xclient.data.l[3] = 0;
3713 xev.xclient.data.l[4] = 0;
3715 if (!xdnd_send_xevent (context, context->source_window,
3718 g_message ("Send event to %lx failed",
3719 GDK_DRAWABLE_XID (context->source_window)));
3725 gdk_window_register_dnd (GdkWindow *window)
3727 static const gulong xdnd_version = 5;
3728 MotifDragReceiverInfo info;
3729 Atom motif_drag_receiver_info_atom;
3730 GdkDisplay *display = gdk_drawable_get_display (window);
3732 g_return_if_fail (window != NULL);
3734 base_precache_atoms (display);
3736 if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
3739 g_object_set_data (G_OBJECT (window), "gdk-dnd-registered", GINT_TO_POINTER (TRUE));
3741 /* Set Motif drag receiver information property */
3743 motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display,
3744 "_MOTIF_DRAG_RECEIVER_INFO");
3745 info.byte_order = local_byte_order;
3746 info.protocol_version = 0;
3747 info.protocol_style = XmDRAG_DYNAMIC;
3748 info.proxy_window = None;
3749 info.num_drop_sites = 0;
3750 info.total_size = sizeof(info);
3752 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_DRAWABLE_XID (window),
3753 motif_drag_receiver_info_atom,
3754 motif_drag_receiver_info_atom,
3761 /* The property needs to be of type XA_ATOM, not XA_INTEGER. Blech */
3762 XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
3763 GDK_DRAWABLE_XID (window),
3764 gdk_x11_get_xatom_by_name_for_display (display, "XdndAware"),
3765 XA_ATOM, 32, PropModeReplace,
3766 (guchar *)&xdnd_version, 1);
3770 * gdk_drag_get_selection:
3771 * @context: a #GdkDragContext.
3773 * Returns the selection atom for the current source window.
3775 * Return value: the selection atom.
3778 gdk_drag_get_selection (GdkDragContext *context)
3780 g_return_val_if_fail (context != NULL, GDK_NONE);
3782 if (context->protocol == GDK_DRAG_PROTO_MOTIF)
3783 return gdk_x11_xatom_to_atom_for_display (GDK_DRAWABLE_DISPLAY (context->source_window),
3784 (PRIVATE_DATA (context))->motif_selection);
3785 else if (context->protocol == GDK_DRAG_PROTO_XDND)
3786 return gdk_atom_intern ("XdndSelection", FALSE);
3792 * gdk_drag_drop_succeeded:
3793 * @context: a #GdkDragContext
3795 * Returns wether the dropped data has been successfully
3796 * transferred. This function is intended to be used while
3797 * handling a %GDK_DROP_FINISHED event, its return value is
3798 * meaningless at other times.
3800 * Return value: %TRUE if the drop was successful.
3805 gdk_drag_drop_succeeded (GdkDragContext *context)
3807 GdkDragContextPrivateX11 *private;
3809 g_return_val_if_fail (context != NULL, FALSE);
3811 private = PRIVATE_DATA (context);
3813 return !private->drop_failed;
3816 #define __GDK_DND_X11_C__
3817 #include "gdkaliasdef.c"