]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkdnd-x11.c
gdk: Only use XComposite if it is available
[~andy/gtk] / gdk / x11 / gdkdnd-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /*
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/. 
25  */
26
27 #include "config.h"
28
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/Xatom.h>
32 #include <X11/extensions/shape.h>
33 #include <X11/extensions/Xcomposite.h>
34
35 #include <string.h>
36
37 #include "gdk.h"          /* For gdk_flush() */
38 #include "gdkx.h"
39 #include "gdkasync.h"
40 #include "gdkdnd.h"
41 #include "gdkproperty.h"
42 #include "gdkprivate-x11.h"
43 #include "gdkinternals.h"
44 #include "gdkscreen-x11.h"
45 #include "gdkdisplay-x11.h"
46
47 typedef struct _GdkDragContextPrivateX11 GdkDragContextPrivateX11;
48
49 typedef enum {
50   GDK_DRAG_STATUS_DRAG,
51   GDK_DRAG_STATUS_MOTION_WAIT,
52   GDK_DRAG_STATUS_ACTION_WAIT,
53   GDK_DRAG_STATUS_DROP
54 } GtkDragStatus;
55
56 typedef struct {
57   guint32 xid;
58   gint x, y, width, height;
59   gboolean mapped;
60   gboolean shape_selected;
61   gboolean shape_valid;
62   cairo_region_t *shape;
63 } GdkCacheChild;
64
65 typedef struct {
66   GList *children;
67   GHashTable *child_hash;
68   guint old_event_mask;
69   GdkScreen *screen;
70 } GdkWindowCache;
71
72 /* Structure that holds information about a drag in progress.
73  * this is used on both source and destination sides.
74  */
75 struct _GdkDragContextPrivateX11 {
76   GdkDragContext context;
77
78   Atom motif_selection;
79   guint   ref_count;
80
81   guint16 last_x;               /* Coordinates from last event */
82   guint16 last_y;
83   GdkDragAction old_action;       /* The last action we sent to the source */
84   GdkDragAction old_actions;      /* The last actions we sent to the source */
85   GdkDragAction xdnd_actions;     /* What is currently set in XdndActionList */
86
87   Window dest_xid;              /* The last window we looked up */
88   Window drop_xid;            /* The (non-proxied) window that is receiving drops */
89   guint xdnd_targets_set : 1;   /* Whether we've already set XdndTypeList */
90   guint xdnd_actions_set : 1;   /* Whether we've already set XdndActionList */
91   guint xdnd_have_actions : 1;  /* Whether an XdndActionList was provided */
92   guint motif_targets_set : 1;  /* Whether we've already set motif initiator info */
93   guint drag_status : 4;        /* current status of drag */
94   
95   guint drop_failed : 1;        /* Whether the drop was unsuccessful */
96   guint version;                /* Xdnd protocol version */
97
98   GSList *window_caches;
99   GdkDevice *device;
100 };
101
102 #define PRIVATE_DATA(context) ((GdkDragContextPrivateX11 *) GDK_DRAG_CONTEXT (context)->windowing_data)
103
104 /* Forward declarations */
105
106 static void gdk_window_cache_destroy (GdkWindowCache *cache);
107
108 static void motif_read_target_table (GdkDisplay *display);
109
110 static GdkFilterReturn motif_dnd_filter (GdkXEvent *xev,
111                                          GdkEvent  *event,
112                                          gpointer   data);
113
114 static GdkFilterReturn xdnd_enter_filter    (GdkXEvent *xev,
115                                              GdkEvent  *event,
116                                              gpointer   data);
117 static GdkFilterReturn xdnd_leave_filter    (GdkXEvent *xev,
118                                              GdkEvent  *event,
119                                              gpointer   data);
120 static GdkFilterReturn xdnd_position_filter (GdkXEvent *xev,
121                                              GdkEvent  *event,
122                                              gpointer   data);
123 static GdkFilterReturn xdnd_status_filter   (GdkXEvent *xev,
124                                              GdkEvent  *event,
125                                              gpointer   data);
126 static GdkFilterReturn xdnd_finished_filter (GdkXEvent *xev,
127                                              GdkEvent  *event,
128                                              gpointer   data);
129 static GdkFilterReturn xdnd_drop_filter     (GdkXEvent *xev,
130                                              GdkEvent  *event,
131                                              gpointer   data);
132
133 static void   xdnd_manage_source_filter (GdkDragContext *context,
134                                          GdkWindow      *window,
135                                          gboolean        add_filter);
136
137 static void gdk_drag_context_finalize   (GObject              *object);
138
139 static GList *contexts;
140
141 static const struct {
142   const char *atom_name;
143   GdkFilterFunc func;
144 } xdnd_filters[] = {
145   { "XdndEnter",    xdnd_enter_filter },
146   { "XdndLeave",    xdnd_leave_filter },
147   { "XdndPosition", xdnd_position_filter },
148   { "XdndStatus",   xdnd_status_filter },
149   { "XdndFinished", xdnd_finished_filter },
150   { "XdndDrop",     xdnd_drop_filter },
151 };
152               
153 G_DEFINE_TYPE (GdkDragContext, gdk_drag_context, G_TYPE_OBJECT)
154
155 static void
156 gdk_drag_context_init (GdkDragContext *dragcontext)
157 {
158   GdkDragContextPrivateX11 *private;
159
160   private = G_TYPE_INSTANCE_GET_PRIVATE (dragcontext, 
161                                          GDK_TYPE_DRAG_CONTEXT, 
162                                          GdkDragContextPrivateX11);
163   
164   dragcontext->windowing_data = private;
165
166   contexts = g_list_prepend (contexts, dragcontext);
167 }
168
169 static void
170 gdk_drag_context_class_init (GdkDragContextClass *klass)
171 {
172   GObjectClass *object_class = G_OBJECT_CLASS (klass);
173
174   object_class->finalize = gdk_drag_context_finalize;
175
176   g_type_class_add_private (object_class, sizeof (GdkDragContextPrivateX11));
177 }
178
179 static void
180 gdk_drag_context_finalize (GObject *object)
181 {
182   GdkDragContext *context = GDK_DRAG_CONTEXT (object);
183   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
184   GSList *tmp_list;
185   
186   g_list_free (context->targets);
187
188   if (context->source_window)
189     {
190       if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
191           !context->is_source)
192         xdnd_manage_source_filter (context, context->source_window, FALSE);
193       
194       g_object_unref (context->source_window);
195     }
196   
197   if (context->dest_window)
198     g_object_unref (context->dest_window);
199
200   for (tmp_list = private->window_caches; tmp_list; tmp_list = tmp_list->next)
201     gdk_window_cache_destroy (tmp_list->data);
202   g_slist_free (private->window_caches);
203   
204   contexts = g_list_remove (contexts, context);
205
206   G_OBJECT_CLASS (gdk_drag_context_parent_class)->finalize (object);
207 }
208
209 /* Drag Contexts */
210
211 /**
212  * gdk_drag_context_new:
213  * 
214  * Creates a new #GdkDragContext.
215  * 
216  * Return value: the newly created #GdkDragContext.
217  **/
218 GdkDragContext *
219 gdk_drag_context_new (void)
220 {
221   return g_object_new (GDK_TYPE_DRAG_CONTEXT, NULL);
222 }
223
224 /**
225  * gdk_drag_context_set_device:
226  * @context: a #GdkDragContext
227  * @device: a #GdkDevice
228  *
229  * Associates a #GdkDevice to @context, so all Drag and Drop events
230  * for @context are emitted as if they came from this device.
231  **/
232 void
233 gdk_drag_context_set_device (GdkDragContext *context,
234                              GdkDevice      *device)
235 {
236   GdkDragContextPrivateX11 *private;
237
238   g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
239   g_return_if_fail (GDK_IS_DEVICE (device));
240
241   private = PRIVATE_DATA (context);
242
243   if (private->device)
244     {
245       g_object_unref (private->device);
246       private->device = NULL;
247     }
248
249   if (device)
250     private->device = g_object_ref (device);
251 }
252
253 /**
254  * gdk_drag_context_get_device:
255  * @context: a #GdkDragContext
256  *
257  * Returns the #GdkDevice associated to the drag context.
258  *
259  * Returns: The #GdkDevice associated to @context.
260  **/
261 GdkDevice *
262 gdk_drag_context_get_device (GdkDragContext *context)
263 {
264   GdkDragContextPrivateX11 *private;
265
266   g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), NULL);
267
268   private = PRIVATE_DATA (context);
269
270   return private->device;
271 }
272
273 static GdkDragContext *
274 gdk_drag_context_find (GdkDisplay *display,
275                        gboolean    is_source,
276                        Window      source_xid,
277                        Window      dest_xid)
278 {
279   GList *tmp_list = contexts;
280   GdkDragContext *context;
281   GdkDragContextPrivateX11 *private;
282   Window context_dest_xid;
283
284   while (tmp_list)
285     {
286       context = (GdkDragContext *)tmp_list->data;
287       private = PRIVATE_DATA (context);
288
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))
291         continue;
292
293       context_dest_xid = context->dest_window ? 
294                             (private->drop_xid ?
295                               private->drop_xid :
296                               GDK_DRAWABLE_XID (context->dest_window)) :
297                              None;
298
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)))
303         return context;
304       
305       tmp_list = tmp_list->next;
306     }
307   
308   return NULL;
309 }
310
311 static void
312 precache_target_list (GdkDragContext *context)
313 {
314   if (context->targets)
315     {
316       GPtrArray *targets = g_ptr_array_new ();
317       GList *tmp_list;
318       int i;
319
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)));
322
323       _gdk_x11_precache_atoms (GDK_WINDOW_DISPLAY (context->source_window),
324                                (const gchar **)targets->pdata,
325                                targets->len);
326
327       for (i =0; i < targets->len; i++)
328         g_free (targets->pdata[i]);
329
330       g_ptr_array_free (targets, TRUE);
331     }
332 }
333
334 /* Utility functions */
335
336 static void
337 free_cache_child (GdkCacheChild *child,
338                   GdkDisplay    *display)
339 {
340   if (child->shape)
341     cairo_region_destroy (child->shape);
342
343   if (child->shape_selected && display)
344     {
345       GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
346
347       XShapeSelectInput (display_x11->xdisplay, child->xid, 0);
348     }
349
350   g_free (child);
351 }
352
353 static void
354 gdk_window_cache_add (GdkWindowCache *cache,
355                       guint32 xid,
356                       gint x, gint y, gint width, gint height, 
357                       gboolean mapped)
358 {
359   GdkCacheChild *child = g_new (GdkCacheChild, 1);
360
361   child->xid = xid;
362   child->x = x;
363   child->y = y;
364   child->width = width;
365   child->height = height;
366   child->mapped = mapped;
367   child->shape_selected = FALSE;
368   child->shape_valid = FALSE;
369   child->shape = NULL;
370
371   cache->children = g_list_prepend (cache->children, child);
372   g_hash_table_insert (cache->child_hash, GUINT_TO_POINTER (xid), 
373                        cache->children);
374 }
375
376 static GdkFilterReturn
377 gdk_window_cache_shape_filter (GdkXEvent *xev,
378                                GdkEvent  *event,
379                                gpointer   data)
380 {
381   XEvent *xevent = (XEvent *)xev;
382   GdkWindowCache *cache = data;
383
384   GdkDisplayX11 *display = GDK_DISPLAY_X11 (gdk_screen_get_display (cache->screen));
385
386   if (display->have_shapes &&
387       xevent->type == display->shape_event_base + ShapeNotify)
388     {
389       XShapeEvent *xse = (XShapeEvent*)xevent;
390       GList *node;
391
392       node = g_hash_table_lookup (cache->child_hash,
393                                   GUINT_TO_POINTER (xse->window));
394       if (node)
395         {
396           GdkCacheChild *child = node->data;
397           child->shape_valid = FALSE;
398           if (child->shape)
399             {
400               cairo_region_destroy (child->shape);
401               child->shape = NULL;
402             }
403         }
404
405       return GDK_FILTER_REMOVE;
406     }
407
408   return GDK_FILTER_CONTINUE;
409 }
410
411 static GdkFilterReturn
412 gdk_window_cache_filter (GdkXEvent *xev,
413                          GdkEvent  *event,
414                          gpointer   data)
415 {
416   XEvent *xevent = (XEvent *)xev;
417   GdkWindowCache *cache = data;
418
419   switch (xevent->type)
420     {
421     case CirculateNotify:
422       break;
423     case ConfigureNotify:
424       {
425         XConfigureEvent *xce = &xevent->xconfigure;
426         GList *node;
427
428         node = g_hash_table_lookup (cache->child_hash, 
429                                     GUINT_TO_POINTER (xce->window));
430         if (node) 
431           {
432             GdkCacheChild *child = node->data;
433             child->x = xce->x; 
434             child->y = xce->y;
435             child->width = xce->width; 
436             child->height = xce->height;
437             if (xce->above == None && (node->next))
438               {
439                 GList *last = g_list_last (cache->children);
440                 cache->children = g_list_remove_link (cache->children, node);
441                 last->next = node;
442                 node->next = NULL;
443                 node->prev = last;
444               }
445             else
446               {
447                 GList *above_node = g_hash_table_lookup (cache->child_hash, 
448                                                          GUINT_TO_POINTER (xce->above));
449                 if (above_node && node->next != above_node)
450                   {
451                     /* Put the window above (before in the list) above_node
452                      */
453                     cache->children = g_list_remove_link (cache->children, node);
454                     node->prev = above_node->prev;
455                     if (node->prev)
456                       node->prev->next = node;
457                     else
458                       cache->children = node;
459                     node->next = above_node;
460                     above_node->prev = node;
461                   }
462               }
463           }
464         break;
465       }
466     case CreateNotify:
467       {
468         XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
469
470         if (!g_hash_table_lookup (cache->child_hash, 
471                                   GUINT_TO_POINTER (xcwe->window))) 
472           gdk_window_cache_add (cache, xcwe->window, 
473                                 xcwe->x, xcwe->y, xcwe->width, xcwe->height,
474                                 FALSE);
475         break;
476       }
477     case DestroyNotify:
478       {
479         XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
480         GList *node;
481
482         node = g_hash_table_lookup (cache->child_hash, 
483                                     GUINT_TO_POINTER (xdwe->window));
484         if (node) 
485           {
486             GdkCacheChild *child = node->data;
487
488             g_hash_table_remove (cache->child_hash,
489                                  GUINT_TO_POINTER (xdwe->window));
490             cache->children = g_list_remove_link (cache->children, node);
491             /* window is destroyed, no need to disable ShapeNotify */
492             free_cache_child (child, NULL);
493             g_list_free_1 (node);
494           }
495         break;
496       }
497     case MapNotify:
498       {
499         XMapEvent *xme = &xevent->xmap;
500         GList *node;
501
502         node = g_hash_table_lookup (cache->child_hash, 
503                                     GUINT_TO_POINTER (xme->window));
504         if (node) 
505           {
506             GdkCacheChild *child = node->data;
507             child->mapped = TRUE;
508           }
509         break;
510       }
511     case ReparentNotify:
512       break;
513     case UnmapNotify:
514       {
515         XMapEvent *xume = &xevent->xmap;
516         GList *node;
517
518         node = g_hash_table_lookup (cache->child_hash, 
519                                     GUINT_TO_POINTER (xume->window));
520         if (node)
521           {
522             GdkCacheChild *child = node->data;
523             child->mapped = FALSE;
524           }
525         break;
526       }
527     default:
528       return GDK_FILTER_CONTINUE;
529     }
530   return GDK_FILTER_REMOVE;
531 }
532
533 static GdkWindowCache *
534 gdk_window_cache_new (GdkScreen *screen)
535 {
536   XWindowAttributes xwa;
537   Display *xdisplay = GDK_SCREEN_XDISPLAY (screen);
538   GdkWindow *root_window = gdk_screen_get_root_window (screen);
539   GdkChildInfoX11 *children;
540   guint nchildren, i;
541   Window cow;
542   
543   GdkWindowCache *result = g_new (GdkWindowCache, 1);
544
545   result->children = NULL;
546   result->child_hash = g_hash_table_new (g_direct_hash, NULL);
547   result->screen = screen;
548
549   XGetWindowAttributes (xdisplay, GDK_WINDOW_XWINDOW (root_window), &xwa);
550   result->old_event_mask = xwa.your_event_mask;
551
552   if (G_UNLIKELY (!GDK_DISPLAY_X11 (GDK_SCREEN_X11 (screen)->display)->trusted_client)) 
553     {
554       GList *toplevel_windows, *list;
555       GdkWindow *window;
556       gint x, y, width, height;
557       
558       toplevel_windows = gdk_screen_get_toplevel_windows (screen);
559       for (list = toplevel_windows; list; list = list->next) {
560         window = GDK_WINDOW (list->data);
561         gdk_window_get_geometry (window, &x, &y, &width, &height, NULL);
562         gdk_window_cache_add (result, GDK_WINDOW_XID (window), 
563                               x, y, width, height, 
564                               gdk_window_is_visible (window));
565       }
566       g_list_free (toplevel_windows);
567       return result;
568     }
569
570   XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
571                 result->old_event_mask | SubstructureNotifyMask);
572   gdk_window_add_filter (root_window, gdk_window_cache_filter, result);
573   gdk_window_add_filter (NULL, gdk_window_cache_shape_filter, result);
574
575   if (!_gdk_x11_get_window_child_info (gdk_screen_get_display (screen),
576                                        GDK_WINDOW_XWINDOW (root_window),
577                                        FALSE, NULL,
578                                        &children, &nchildren))
579     return result;
580
581   for (i = 0; i < nchildren ; i++)
582     {
583       gdk_window_cache_add (result, children[i].window,
584                             children[i].x, children[i].y, children[i].width, children[i].height,
585                             children[i].is_mapped);
586     }
587
588   g_free (children);
589
590 #ifdef HAVE_XCOMPOSITE
591   /*
592    * Add the composite overlay window to the cache, as this can be a reasonable
593    * Xdnd proxy as well.
594    * This is only done when the screen is composited in order to avoid mapping
595    * the COW. We assume that the CM is using the COW (which is true for pretty
596    * much any CM currently in use).
597    */
598   if (gdk_screen_is_composited (screen))
599     {
600       cow = XCompositeGetOverlayWindow (xdisplay, GDK_WINDOW_XWINDOW (root_window));
601       gdk_window_cache_add (result, cow, 0, 0, gdk_screen_get_width (screen), gdk_screen_get_height (screen), TRUE);
602       XCompositeReleaseOverlayWindow (xdisplay, GDK_WINDOW_XWINDOW (root_window));
603     }
604 #endif
605
606   return result;
607 }
608
609 static void
610 gdk_window_cache_destroy (GdkWindowCache *cache)
611 {
612   GdkWindow *root_window = gdk_screen_get_root_window (cache->screen);
613
614   XSelectInput (GDK_WINDOW_XDISPLAY (root_window),
615                 GDK_WINDOW_XWINDOW (root_window),
616                 cache->old_event_mask);
617   gdk_window_remove_filter (root_window, gdk_window_cache_filter, cache);
618   gdk_window_remove_filter (NULL, gdk_window_cache_shape_filter, cache);
619
620   gdk_error_trap_push ();
621
622   g_list_foreach (cache->children, (GFunc)free_cache_child,
623       gdk_screen_get_display (cache->screen));
624
625   gdk_flush ();
626   gdk_error_trap_pop ();
627
628   g_list_free (cache->children);
629   g_hash_table_destroy (cache->child_hash);
630
631   g_free (cache);
632 }
633
634 static gboolean
635 is_pointer_within_shape (GdkDisplay    *display,
636                          GdkCacheChild *child,
637                          gint           x_pos,
638                          gint           y_pos)
639 {
640   if (!child->shape_selected)
641     {
642       GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
643
644       XShapeSelectInput (display_x11->xdisplay, child->xid, ShapeNotifyMask);
645       child->shape_selected = TRUE;
646     }
647   if (!child->shape_valid)
648     {
649       GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
650       cairo_region_t *input_shape;
651
652       child->shape = _xwindow_get_shape (display_x11->xdisplay,
653                                          child->xid, ShapeBounding);
654 #ifdef ShapeInput
655       input_shape = _xwindow_get_shape (display_x11->xdisplay,
656                                         child->xid, ShapeInput);
657       if (child->shape && input_shape)
658         {
659           cairo_region_intersect (child->shape, input_shape);
660           cairo_region_destroy (input_shape);
661         }
662       else if (input_shape)
663         {
664           child->shape = input_shape;
665         }
666 #endif
667
668       child->shape_valid = TRUE;
669     }
670
671   return child->shape == NULL ||
672          cairo_region_contains_point (child->shape, x_pos, y_pos);
673 }
674
675 static Window
676 get_client_window_at_coords_recurse (GdkDisplay *display,
677                                      Window      win,
678                                      gboolean    is_toplevel,
679                                      gint        x,
680                                      gint        y)
681 {
682   GdkChildInfoX11 *children;
683   unsigned int nchildren;
684   int i;
685   gboolean found_child = FALSE;
686   GdkChildInfoX11 child = { 0, };
687   gboolean has_wm_state = FALSE;
688
689   if (!_gdk_x11_get_window_child_info (display, win, TRUE,
690                                        is_toplevel? &has_wm_state : NULL,
691                                        &children, &nchildren))
692     return None;
693
694   if (has_wm_state)
695     {
696       g_free (children);
697
698       return win;
699     }
700
701   for (i = nchildren - 1; (i >= 0) && !found_child; i--)
702     {
703       GdkChildInfoX11 *cur_child = &children[i];
704        
705       if ((cur_child->is_mapped) && (cur_child->window_class == InputOutput) &&
706           (x >= cur_child->x) && (x < cur_child->x + cur_child->width) &&
707           (y >= cur_child->y) && (y < cur_child->y + cur_child->height))
708         {
709           x -= cur_child->x;
710           y -= cur_child->y;
711           child = *cur_child;
712           found_child = TRUE;
713         }
714     }
715    
716   g_free (children);
717  
718   if (found_child)
719     {
720       if (child.has_wm_state)
721         return child.window;
722       else
723         return get_client_window_at_coords_recurse (display, child.window, FALSE, x, y);
724     }
725   else
726     return None;
727 }
728
729 static Window 
730 get_client_window_at_coords (GdkWindowCache *cache,
731                              Window          ignore,
732                              gint            x_root,
733                              gint            y_root)
734 {
735   GList *tmp_list;
736   Window retval = None;
737
738   gdk_error_trap_push ();
739   
740   tmp_list = cache->children;
741
742   while (tmp_list && !retval)
743     {
744       GdkCacheChild *child = tmp_list->data;
745
746       if ((child->xid != ignore) && (child->mapped))
747         {
748           if ((x_root >= child->x) && (x_root < child->x + child->width) &&
749               (y_root >= child->y) && (y_root < child->y + child->height))
750             {
751               GdkDisplay *display = gdk_screen_get_display (cache->screen);
752
753               if (!is_pointer_within_shape (display, child,
754                                             x_root - child->x,
755                                             y_root - child->y))
756                 {
757                   tmp_list = tmp_list->next;
758                   continue;
759                 }
760
761               retval = get_client_window_at_coords_recurse (display,
762                   child->xid, TRUE,
763                   x_root - child->x,
764                   y_root - child->y);
765               if (!retval)
766                 retval = child->xid;
767             }
768         }
769       tmp_list = tmp_list->next;
770     }
771
772   gdk_error_trap_pop ();
773   
774   if (retval)
775     return retval;
776   else
777     return GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (cache->screen));
778 }
779
780 /*************************************************************
781  ***************************** MOTIF *************************
782  *************************************************************/
783
784 /* values used in the message type for Motif DND */
785 enum {
786     XmTOP_LEVEL_ENTER,
787     XmTOP_LEVEL_LEAVE,
788     XmDRAG_MOTION,
789     XmDROP_SITE_ENTER,
790     XmDROP_SITE_LEAVE,
791     XmDROP_START,
792     XmDROP_FINISH,
793     XmDRAG_DROP_FINISH,
794     XmOPERATION_CHANGED
795 };
796
797 /* Values used to specify type of protocol to use */
798 enum {
799     XmDRAG_NONE,
800     XmDRAG_DROP_ONLY,
801     XmDRAG_PREFER_PREREGISTER,
802     XmDRAG_PREREGISTER,
803     XmDRAG_PREFER_DYNAMIC,
804     XmDRAG_DYNAMIC,
805     XmDRAG_PREFER_RECEIVER
806 };
807
808 /* Operation codes */
809 enum {
810   XmDROP_NOOP,
811   XmDROP_MOVE = 0x01,
812   XmDROP_COPY = 0x02,
813   XmDROP_LINK = 0x04
814 };
815
816 /* Drop site status */
817 enum {
818   XmNO_DROP_SITE = 0x01,
819   XmDROP_SITE_INVALID = 0x02,
820   XmDROP_SITE_VALID = 0x03
821 };
822
823 /* completion status */
824 enum {
825   XmDROP,
826   XmDROP_HELP,
827   XmDROP_CANCEL,
828   XmDROP_INTERRUPT
829 };
830
831 /* Byte swapping routines. The motif specification leaves it
832  * up to us to save a few bytes in the client messages
833  */
834 static gchar local_byte_order = '\0';
835
836 #ifdef G_ENABLE_DEBUG
837 static void
838 print_target_list (GList *targets)
839 {
840   while (targets)
841     {
842       gchar *name = gdk_atom_name (GDK_POINTER_TO_ATOM (targets->data));
843       g_message ("\t%s", name);
844       g_free (name);
845       targets = targets->next;
846     }
847 }
848 #endif /* G_ENABLE_DEBUG */
849
850 static void
851 init_byte_order (void)
852 {
853   guint32 myint = 0x01020304;
854   local_byte_order = (*(gchar *)&myint == 1) ? 'B' : 'l';
855 }
856
857 static guint16
858 card16_to_host (guint16 x, gchar byte_order) {
859   if (byte_order == local_byte_order)
860     return x;
861   else
862     return (x << 8) | (x >> 8);
863 }
864
865 static guint32
866 card32_to_host (guint32 x, gchar byte_order) {
867   if (byte_order == local_byte_order)
868     return x;
869   else
870     return (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
871 }
872
873 /* Motif packs together fields of varying length into the
874  * client message. We can't rely on accessing these
875  * through data.s[], data.l[], etc, because on some architectures
876  * (i.e., Alpha) these won't be valid for format == 8. 
877  */
878
879 #define MOTIF_XCLIENT_BYTE(xevent,i) \
880   (xevent)->xclient.data.b[i]
881 #define MOTIF_XCLIENT_SHORT(xevent,i) \
882   ((gint16 *)&((xevent)->xclient.data.b[0]))[i]
883 #define MOTIF_XCLIENT_LONG(xevent,i) \
884   ((gint32 *)&((xevent)->xclient.data.b[0]))[i]
885
886 #define MOTIF_UNPACK_BYTE(xevent,i) MOTIF_XCLIENT_BYTE(xevent,i)
887 #define MOTIF_UNPACK_SHORT(xevent,i) \
888   card16_to_host (MOTIF_XCLIENT_SHORT(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
889 #define MOTIF_UNPACK_LONG(xevent,i) \
890   card32_to_host (MOTIF_XCLIENT_LONG(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
891
892 /***** Dest side ***********/
893
894 /* Property placed on source windows */
895 typedef struct _MotifDragInitiatorInfo {
896   guint8 byte_order;
897   guint8 protocol_version;
898   guint16 targets_index;
899   guint32 selection_atom;
900 } MotifDragInitiatorInfo;
901
902 /* Header for target table on the drag window */
903 typedef struct _MotifTargetTableHeader {
904   guchar byte_order;
905   guchar protocol_version;
906   guint16 n_lists;
907   guint32 total_size;
908 } MotifTargetTableHeader;
909
910 /* Property placed on target windows */
911 typedef struct _MotifDragReceiverInfo {
912   guint8 byte_order;
913   guint8 protocol_version;
914   guint8 protocol_style;
915   guint8 pad;
916   guint32 proxy_window;
917   guint16 num_drop_sites;
918   guint16 padding;
919   guint32 total_size;
920 } MotifDragReceiverInfo;
921
922 /* Target table handling */
923
924 static GdkFilterReturn
925 motif_drag_window_filter (GdkXEvent *xevent,
926                           GdkEvent  *event,
927                           gpointer data)
928 {
929   XEvent *xev = (XEvent *)xevent;
930   GdkDisplay *display = GDK_WINDOW_DISPLAY (event->any.window); 
931   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
932
933   switch (xev->xany.type)
934     {
935     case DestroyNotify:
936       display_x11->motif_drag_window = None;
937       display_x11->motif_drag_gdk_window = NULL;
938       break;
939     case PropertyNotify:
940       if (display_x11->motif_target_lists &&
941           (xev->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS")))
942         motif_read_target_table (display);
943       break;
944     }
945   return GDK_FILTER_REMOVE;
946 }
947
948 static Window
949 motif_lookup_drag_window (GdkDisplay *display,
950                           Display    *lookup_xdisplay)
951 {
952   Window retval = None;
953   gulong bytes_after, nitems;
954   Atom type;
955   gint format;
956   guchar *data;
957
958   XGetWindowProperty (lookup_xdisplay, RootWindow (lookup_xdisplay, 0),
959                       gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW"),
960                       0, 1, FALSE,
961                       XA_WINDOW, &type, &format, &nitems, &bytes_after,
962                       &data);
963   
964   if ((format == 32) && (nitems == 1) && (bytes_after == 0))
965     {
966       retval = *(Window *)data;
967       GDK_NOTE (DND, 
968                 g_message ("Found drag window %#lx\n", GDK_DISPLAY_X11 (display)->motif_drag_window));
969     }
970
971   if (type != None)
972     XFree (data);
973
974   return retval;
975 }
976
977 /* Finds the window where global Motif drag information is stored.
978  * If it doesn't exist and 'create' is TRUE, create one.
979  */
980 static Window 
981 motif_find_drag_window (GdkDisplay *display,
982                         gboolean    create)
983 {
984   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
985   
986   if (!display_x11->motif_drag_window)
987     {
988       Atom motif_drag_window_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW");
989       display_x11->motif_drag_window = motif_lookup_drag_window (display, display_x11->xdisplay);
990       
991       if (!display_x11->motif_drag_window && create)
992         {
993           /* Create a persistant window. (Copied from LessTif) */
994           
995           Display *persistant_xdisplay;
996           XSetWindowAttributes attr;
997           persistant_xdisplay = XOpenDisplay (gdk_display_get_name (display));
998           XSetCloseDownMode (persistant_xdisplay, RetainPermanent);
999
1000           XGrabServer (persistant_xdisplay);
1001           
1002           display_x11->motif_drag_window = motif_lookup_drag_window (display, persistant_xdisplay);
1003
1004           if (!display_x11->motif_drag_window)
1005             {
1006               attr.override_redirect = True;
1007               attr.event_mask = PropertyChangeMask;
1008               
1009                display_x11->motif_drag_window = 
1010                 XCreateWindow (persistant_xdisplay, 
1011                                RootWindow (persistant_xdisplay, 0),
1012                               -100, -100, 10, 10, 0, 0,
1013                               InputOnly, (Visual *)CopyFromParent,
1014                               (CWOverrideRedirect | CWEventMask), &attr);
1015               
1016               GDK_NOTE (DND,
1017                         g_message ("Created drag window %#lx\n", display_x11->motif_drag_window));
1018               
1019               XChangeProperty (persistant_xdisplay, 
1020                                RootWindow (persistant_xdisplay, 0),
1021                                motif_drag_window_atom, XA_WINDOW,
1022                                32, PropModeReplace,
1023                                (guchar *)&motif_drag_window_atom, 1);
1024
1025             }
1026           XUngrabServer (persistant_xdisplay);
1027           XCloseDisplay (persistant_xdisplay);
1028         }
1029
1030       /* There is a miniscule race condition here if the drag window
1031        * gets destroyed exactly now.
1032        */
1033       if (display_x11->motif_drag_window)
1034         {
1035           display_x11->motif_drag_gdk_window = 
1036             gdk_window_foreign_new_for_display (display, display_x11->motif_drag_window);
1037           gdk_window_add_filter (display_x11->motif_drag_gdk_window,
1038                                  motif_drag_window_filter,
1039                                  NULL);
1040         }
1041     }
1042
1043   return display_x11->motif_drag_window;
1044 }
1045
1046 static void 
1047 motif_read_target_table (GdkDisplay *display)
1048 {
1049   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1050   gulong bytes_after, nitems;
1051   Atom type;
1052   gint format;
1053   gint i, j;
1054   
1055   Atom motif_drag_targets_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS");
1056
1057   if (display_x11->motif_target_lists)
1058     {
1059       for (i=0; i<display_x11->motif_n_target_lists; i++)
1060         g_list_free (display_x11->motif_target_lists[i]);
1061       
1062       g_free (display_x11->motif_target_lists);
1063       display_x11->motif_target_lists = NULL;
1064       display_x11->motif_n_target_lists = 0;
1065     }
1066
1067   if (motif_find_drag_window (display, FALSE))
1068     {
1069       guchar *data;
1070       MotifTargetTableHeader *header = NULL;
1071       guchar *target_bytes = NULL;
1072       guchar *p;
1073       gboolean success = FALSE;
1074
1075       gdk_error_trap_push ();
1076       XGetWindowProperty (display_x11->xdisplay, 
1077                           display_x11->motif_drag_window, 
1078                           motif_drag_targets_atom,
1079                           0, (sizeof(MotifTargetTableHeader)+3)/4, FALSE,
1080                           motif_drag_targets_atom, 
1081                           &type, &format, &nitems, &bytes_after,
1082                           &data);
1083
1084       if (gdk_error_trap_pop () || (format != 8) || (nitems < sizeof (MotifTargetTableHeader)))
1085         goto error;
1086
1087       header = (MotifTargetTableHeader *)data;
1088
1089       header->n_lists = card16_to_host (header->n_lists, header->byte_order);
1090       header->total_size = card32_to_host (header->total_size, header->byte_order);
1091
1092       gdk_error_trap_push ();
1093       XGetWindowProperty (display_x11->xdisplay, 
1094                           display_x11->motif_drag_window, 
1095                           motif_drag_targets_atom,
1096                           (sizeof(MotifTargetTableHeader)+3)/4, 
1097                           (header->total_size + 3)/4 - (sizeof(MotifTargetTableHeader) + 3)/4,
1098                           FALSE,
1099                           motif_drag_targets_atom, &type, &format, &nitems, 
1100                           &bytes_after, &target_bytes);
1101       
1102       if (gdk_error_trap_pop () || (format != 8) || (bytes_after != 0) || 
1103           (nitems != header->total_size - sizeof(MotifTargetTableHeader)))
1104           goto error;
1105
1106       display_x11->motif_n_target_lists = header->n_lists;
1107       display_x11->motif_target_lists = g_new0 (GList *, display_x11->motif_n_target_lists);
1108
1109       p = target_bytes;
1110       for (i=0; i<header->n_lists; i++)
1111         {
1112           gint n_targets;
1113           guint32 *targets;
1114           
1115           if (p + sizeof(guint16) - target_bytes > nitems)
1116             goto error;
1117
1118           n_targets = card16_to_host (*(gushort *)p, header->byte_order);
1119
1120           /* We need to make a copy of the targets, since it may
1121            * be unaligned
1122            */
1123           targets = g_new (guint32, n_targets);
1124           memcpy (targets, p + sizeof(guint16), sizeof(guint32) * n_targets);
1125
1126           p +=  sizeof(guint16) + n_targets * sizeof(guint32);
1127           if (p - target_bytes > nitems)
1128             goto error;
1129
1130           for (j=0; j<n_targets; j++)
1131             display_x11->motif_target_lists[i] = 
1132               g_list_prepend (display_x11->motif_target_lists[i],
1133                               GUINT_TO_POINTER (card32_to_host (targets[j],
1134                                                                 header->byte_order)));
1135           g_free (targets);
1136           display_x11->motif_target_lists[i] = g_list_reverse (display_x11->motif_target_lists[i]);
1137         }
1138
1139       success = TRUE;
1140       
1141     error:
1142       if (header)
1143         XFree (header);
1144       
1145       if (target_bytes)
1146         XFree (target_bytes);
1147
1148       if (!success)
1149         {
1150           if (display_x11->motif_target_lists)
1151             {
1152               g_free (display_x11->motif_target_lists);
1153               display_x11->motif_target_lists = NULL;
1154               display_x11->motif_n_target_lists = 0;
1155             }
1156           g_warning ("Error reading Motif target table\n");
1157         }
1158     }
1159 }
1160
1161 static gint
1162 targets_sort_func (gconstpointer a, gconstpointer b)
1163 {
1164   return (GPOINTER_TO_UINT (a) < GPOINTER_TO_UINT (b)) ?
1165     -1 : ((GPOINTER_TO_UINT (a) > GPOINTER_TO_UINT (b)) ? 1 : 0);
1166 }
1167
1168 /* Check if given (sorted) list is in the targets table */
1169 static gint
1170 motif_target_table_check (GdkDisplay *display,
1171                           GList      *sorted)
1172 {
1173   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1174   GList *tmp_list1, *tmp_list2;
1175   gint i;
1176
1177   for (i=0; i<display_x11->motif_n_target_lists; i++)
1178     {
1179       tmp_list1 = display_x11->motif_target_lists[i];
1180       tmp_list2 = sorted;
1181       
1182       while (tmp_list1 && tmp_list2)
1183         {
1184           if (tmp_list1->data != tmp_list2->data)
1185             break;
1186
1187           tmp_list1 = tmp_list1->next;
1188           tmp_list2 = tmp_list2->next;
1189         }
1190       if (!tmp_list1 && !tmp_list2)     /* Found it */
1191         return i;
1192     }
1193
1194   return -1;
1195 }
1196
1197 static gint
1198 motif_add_to_target_table (GdkDisplay *display,
1199                            GList      *targets) /* targets is list of GdkAtom */
1200 {
1201   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1202   GList *sorted = NULL;
1203   gint index = -1;
1204   gint i;
1205   GList *tmp_list;
1206   
1207   /* make a sorted copy of the list */
1208   
1209   while (targets)
1210     {
1211       Atom xatom = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (targets->data));
1212       sorted = g_list_insert_sorted (sorted, GUINT_TO_POINTER (xatom), targets_sort_func);
1213       targets = targets->next;
1214     }
1215
1216   /* First check if it is there already */
1217
1218   if (display_x11->motif_target_lists)
1219     index = motif_target_table_check (display, sorted);
1220
1221   /* We need to grab the server while doing this, to ensure
1222    * atomiticity. Ugh
1223    */
1224
1225   if (index < 0)
1226     {
1227       /* We need to make sure that it exists _before_ we grab the
1228        * server, since we can't open a new connection after we
1229        * grab the server. 
1230        */
1231       motif_find_drag_window (display, TRUE);
1232
1233       gdk_x11_display_grab (display);
1234       motif_read_target_table (display);
1235     
1236       /* Check again, in case it was added in the meantime */
1237       
1238       if (display_x11->motif_target_lists)
1239         index = motif_target_table_check (display, sorted);
1240
1241       if (index < 0)
1242         {
1243           guint32 total_size = 0;
1244           guchar *data;
1245           guchar *p;
1246           guint16 *p16;
1247           MotifTargetTableHeader *header;
1248           
1249           if (!display_x11->motif_target_lists)
1250             {
1251               display_x11->motif_target_lists = g_new (GList *, 1);
1252               display_x11->motif_n_target_lists = 1;
1253             }
1254           else
1255             {
1256               display_x11->motif_n_target_lists++;
1257               display_x11->motif_target_lists = g_realloc (display_x11->motif_target_lists,
1258                                                            sizeof(GList *) * display_x11->motif_n_target_lists);
1259             }
1260           display_x11->motif_target_lists[display_x11->motif_n_target_lists - 1] = sorted;
1261           sorted = NULL;
1262           index = display_x11->motif_n_target_lists - 1;
1263
1264           total_size = sizeof (MotifTargetTableHeader);
1265           for (i = 0; i < display_x11->motif_n_target_lists ; i++)
1266             total_size += sizeof(guint16) + sizeof(guint32) * g_list_length (display_x11->motif_target_lists[i]);
1267
1268           data = g_malloc (total_size);
1269
1270           header = (MotifTargetTableHeader *)data;
1271           p = data + sizeof(MotifTargetTableHeader);
1272
1273           header->byte_order = local_byte_order;
1274           header->protocol_version = 0;
1275           header->n_lists = display_x11->motif_n_target_lists;
1276           header->total_size = total_size;
1277
1278           for (i = 0; i < display_x11->motif_n_target_lists ; i++)
1279             {
1280               guint16 n_targets = g_list_length (display_x11->motif_target_lists[i]);
1281               guint32 *targets = g_new (guint32, n_targets);
1282               guint32 *p32 = targets;
1283               
1284               tmp_list = display_x11->motif_target_lists[i];
1285               while (tmp_list)
1286                 {
1287                   *p32 = GPOINTER_TO_UINT (tmp_list->data);
1288                   
1289                   tmp_list = tmp_list->next;
1290                   p32++;
1291                 }
1292
1293               p16 = (guint16 *)p;
1294               p += sizeof(guint16);
1295
1296               memcpy (p, targets, n_targets * sizeof(guint32));
1297
1298               *p16 = n_targets;
1299               p += sizeof(guint32) * n_targets;
1300               g_free (targets);
1301             }
1302
1303           XChangeProperty (display_x11->xdisplay,
1304                            display_x11->motif_drag_window,
1305                            gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
1306                            gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
1307                            8, PropModeReplace,
1308                            data, total_size);
1309         }
1310       gdk_x11_display_ungrab (display);
1311     }
1312
1313   g_list_free (sorted);
1314   return index;
1315 }
1316
1317 /* Translate flags */
1318
1319 static void
1320 motif_dnd_translate_flags (GdkDragContext *context, guint16 flags)
1321 {
1322   guint recommended_op = flags & 0x000f;
1323   guint possible_ops = (flags & 0x0f0) >> 4;
1324   
1325   switch (recommended_op)
1326     {
1327     case XmDROP_MOVE:
1328       context->suggested_action = GDK_ACTION_MOVE;
1329       break;
1330     case XmDROP_COPY:
1331       context->suggested_action = GDK_ACTION_COPY;
1332       break;
1333     case XmDROP_LINK:
1334       context->suggested_action = GDK_ACTION_LINK;
1335       break;
1336     default:
1337       context->suggested_action = GDK_ACTION_COPY;
1338       break;
1339     }
1340
1341   context->actions = 0;
1342   if (possible_ops & XmDROP_MOVE)
1343     context->actions |= GDK_ACTION_MOVE;
1344   if (possible_ops & XmDROP_COPY)
1345     context->actions |= GDK_ACTION_COPY;
1346   if (possible_ops & XmDROP_LINK)
1347     context->actions |= GDK_ACTION_LINK;
1348 }
1349
1350 static guint16
1351 motif_dnd_get_flags (GdkDragContext *context)
1352 {
1353   guint16 flags = 0;
1354   
1355   switch (context->suggested_action)
1356     {
1357     case GDK_ACTION_MOVE:
1358       flags = XmDROP_MOVE;
1359       break;
1360     case GDK_ACTION_COPY:
1361       flags = XmDROP_COPY;
1362       break;
1363     case GDK_ACTION_LINK:
1364       flags = XmDROP_LINK;
1365       break;
1366     default:
1367       flags = XmDROP_NOOP;
1368       break;
1369     }
1370   
1371   if (context->actions & GDK_ACTION_MOVE)
1372     flags |= XmDROP_MOVE << 8;
1373   if (context->actions & GDK_ACTION_COPY)
1374     flags |= XmDROP_COPY << 8;
1375   if (context->actions & GDK_ACTION_LINK)
1376     flags |= XmDROP_LINK << 8;
1377
1378   return flags;
1379 }
1380
1381 /* Source Side */
1382
1383 static void
1384 motif_set_targets (GdkDragContext *context)
1385 {
1386   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1387   MotifDragInitiatorInfo info;
1388   gint i;
1389   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1390   
1391   info.byte_order = local_byte_order;
1392   info.protocol_version = 0;
1393   
1394   info.targets_index = motif_add_to_target_table (display, context->targets);
1395
1396   for (i=0; ; i++)
1397     {
1398       gchar buf[20];
1399       g_snprintf(buf, 20, "_GDK_SELECTION_%d", i);
1400       
1401       private->motif_selection = gdk_x11_get_xatom_by_name_for_display (display, buf);
1402       if (!XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), private->motif_selection))
1403         break;
1404     }
1405
1406   info.selection_atom = private->motif_selection;
1407
1408   XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
1409                    GDK_DRAWABLE_XID (context->source_window),
1410                    private->motif_selection,
1411                    gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
1412                    8, PropModeReplace,
1413                    (guchar *)&info, sizeof (info));
1414
1415   private->motif_targets_set = 1;
1416 }
1417
1418 static guint32
1419 motif_check_dest (GdkDisplay *display,
1420                   Window      win)
1421 {
1422   gboolean retval = FALSE;
1423   guchar *data;
1424   MotifDragReceiverInfo *info;
1425   Atom type = None;
1426   int format;
1427   unsigned long nitems, after;
1428   Atom motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO");
1429
1430   gdk_error_trap_push ();
1431   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win, 
1432                       motif_drag_receiver_info_atom, 
1433                       0, (sizeof(*info)+3)/4, False, AnyPropertyType,
1434                       &type, &format, &nitems, &after, 
1435                       &data);
1436
1437   if (gdk_error_trap_pop() == 0)
1438     {
1439       if (type != None)
1440         {
1441           info = (MotifDragReceiverInfo *)data;
1442           
1443           if ((format == 8) && (nitems == sizeof(*info)))
1444             {
1445               if ((info->protocol_version == 0) &&
1446                   ((info->protocol_style == XmDRAG_PREFER_PREREGISTER) ||
1447                    (info->protocol_style == XmDRAG_PREFER_DYNAMIC) ||
1448                    (info->protocol_style == XmDRAG_DYNAMIC)))
1449                 retval = TRUE;
1450             }
1451           else
1452             {
1453               GDK_NOTE (DND, 
1454                         g_warning ("Invalid Motif drag receiver property on window %ld\n", win));
1455             }
1456           
1457           XFree (info);
1458         }
1459     }
1460
1461   return retval ? win : None;
1462 }
1463
1464 static void
1465 motif_send_enter (GdkDragContext  *context,
1466                   guint32          time)
1467 {
1468   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1469   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1470   XEvent xev;
1471
1472   if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
1473     return; /* Motif Dnd requires getting properties on the root window */
1474
1475   xev.xclient.type = ClientMessage;
1476   xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1477   xev.xclient.format = 8;
1478   xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1479
1480   MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_ENTER;
1481   MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1482   MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
1483   MOTIF_XCLIENT_LONG (&xev, 1) = time;
1484   MOTIF_XCLIENT_LONG (&xev, 2) = GDK_DRAWABLE_XID (context->source_window);
1485
1486   if (!private->motif_targets_set)
1487     motif_set_targets (context);
1488
1489   MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection;
1490   MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1491
1492   if (!_gdk_send_xevent (display,
1493                          GDK_DRAWABLE_XID (context->dest_window),
1494                          FALSE, 0, &xev))
1495     GDK_NOTE (DND, 
1496               g_message ("Send event to %lx failed",
1497                          GDK_DRAWABLE_XID (context->dest_window)));
1498 }
1499
1500 static void
1501 motif_send_leave (GdkDragContext  *context,
1502                   guint32          time)
1503 {
1504   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1505   XEvent xev;
1506
1507   xev.xclient.type = ClientMessage;
1508   xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1509   xev.xclient.format = 8;
1510   xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1511
1512   MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_LEAVE;
1513   MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1514   MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
1515   MOTIF_XCLIENT_LONG (&xev, 1) = time;
1516   MOTIF_XCLIENT_LONG (&xev, 2) = 0;
1517   MOTIF_XCLIENT_LONG (&xev, 3) = 0;
1518   MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1519
1520   if (!_gdk_send_xevent (display,
1521                          GDK_DRAWABLE_XID (context->dest_window),
1522                          FALSE, 0, &xev))
1523     GDK_NOTE (DND, 
1524               g_message ("Send event to %lx failed",
1525                          GDK_DRAWABLE_XID (context->dest_window)));
1526 }
1527
1528 static gboolean
1529 motif_send_motion (GdkDragContext  *context,
1530                     gint            x_root, 
1531                     gint            y_root,
1532                     GdkDragAction   action,
1533                     guint32         time)
1534 {
1535   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1536   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1537   gboolean retval;
1538   XEvent xev;
1539
1540   xev.xclient.type = ClientMessage;
1541   xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1542   xev.xclient.format = 8;
1543   xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1544
1545   MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1546   MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
1547   MOTIF_XCLIENT_LONG (&xev, 1) = time;
1548   MOTIF_XCLIENT_LONG (&xev, 3) = 0;
1549   MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1550
1551   if ((context->suggested_action != private->old_action) ||
1552       (context->actions != private->old_actions))
1553     {
1554       MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
1555
1556       /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
1557       retval = TRUE;
1558     }
1559   else
1560     {
1561       MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION;
1562
1563       MOTIF_XCLIENT_SHORT (&xev, 4) = x_root;
1564       MOTIF_XCLIENT_SHORT (&xev, 5) = y_root;
1565       
1566       private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
1567       retval = FALSE;
1568     }
1569
1570   if (!_gdk_send_xevent (display,
1571                          GDK_DRAWABLE_XID (context->dest_window),
1572                          FALSE, 0, &xev))
1573     GDK_NOTE (DND, 
1574               g_message ("Send event to %lx failed",
1575                          GDK_DRAWABLE_XID (context->dest_window)));
1576
1577   return retval;
1578 }
1579
1580 static void
1581 motif_send_drop (GdkDragContext *context, guint32 time)
1582 {
1583   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1584   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1585   XEvent xev;
1586
1587   xev.xclient.type = ClientMessage;
1588   xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1589   xev.xclient.format = 8;
1590   xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1591
1592   MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START;
1593   MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1594   MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
1595   MOTIF_XCLIENT_LONG (&xev, 1)  = time;
1596
1597   MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
1598   MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
1599
1600   MOTIF_XCLIENT_LONG (&xev, 3)  = private->motif_selection;
1601   MOTIF_XCLIENT_LONG (&xev, 4)  = GDK_DRAWABLE_XID (context->source_window);
1602
1603   if (!_gdk_send_xevent (display,
1604                          GDK_DRAWABLE_XID (context->dest_window),
1605                          FALSE, 0, &xev))
1606     GDK_NOTE (DND, 
1607               g_message ("Send event to %lx failed",
1608                          GDK_DRAWABLE_XID (context->dest_window)));
1609 }
1610
1611 /* Target Side */
1612
1613 static gboolean
1614 motif_read_initiator_info (GdkDisplay *display,
1615                            Window      source_window, 
1616                            Atom        atom,
1617                            GList     **targets,
1618                            Atom       *selection)
1619 {
1620   GList *tmp_list;
1621   Atom type;
1622   gint format;
1623   gulong nitems;
1624   gulong bytes_after;
1625   guchar *data;
1626   MotifDragInitiatorInfo *initiator_info;
1627   
1628   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1629   
1630   gdk_error_trap_push ();
1631   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), source_window, atom,
1632                       0, sizeof(*initiator_info), FALSE,
1633                       gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
1634                       &type, &format, &nitems, &bytes_after,
1635                       &data);
1636
1637   if (gdk_error_trap_pop () || (format != 8) || (nitems != sizeof (MotifDragInitiatorInfo)) || (bytes_after != 0))
1638     {
1639       g_warning ("Error reading initiator info\n");
1640       return FALSE;
1641     }
1642
1643   initiator_info = (MotifDragInitiatorInfo *)data;
1644
1645   motif_read_target_table (display);
1646
1647   initiator_info->targets_index = 
1648     card16_to_host (initiator_info->targets_index, initiator_info->byte_order);
1649   initiator_info->selection_atom = 
1650     card32_to_host (initiator_info->selection_atom, initiator_info->byte_order);
1651   
1652   if (initiator_info->targets_index >= display_x11->motif_n_target_lists)
1653     {
1654       g_warning ("Invalid target index in TOP_LEVEL_ENTER MESSAGE");
1655       XFree (initiator_info);
1656       return FALSE;
1657     }
1658
1659   tmp_list = g_list_last (display_x11->motif_target_lists[initiator_info->targets_index]);
1660
1661   *targets = NULL;
1662   while (tmp_list)
1663     {
1664       GdkAtom atom = gdk_x11_xatom_to_atom_for_display (display, GPOINTER_TO_UINT (tmp_list->data));
1665       *targets = g_list_prepend (*targets, GDK_ATOM_TO_POINTER (atom));
1666       tmp_list = tmp_list->prev;
1667     }
1668
1669 #ifdef G_ENABLE_DEBUG
1670   if (_gdk_debug_flags & GDK_DEBUG_DND)
1671     print_target_list (*targets);
1672 #endif /* G_ENABLE_DEBUG */
1673
1674   *selection = initiator_info->selection_atom;
1675
1676   XFree (initiator_info);
1677
1678   return TRUE;
1679 }
1680
1681 static GdkDragContext *
1682 motif_drag_context_new (GdkWindow *dest_window,
1683                         guint32    timestamp,
1684                         guint32    source_window,
1685                         guint32    atom)
1686 {
1687   GdkDragContext *new_context;
1688   GdkDragContextPrivateX11 *private;
1689   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (dest_window);
1690   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1691
1692   /* FIXME, current_dest_drag really shouldn't be NULL'd
1693    * if we error below.
1694    */
1695   if (display_x11->current_dest_drag != NULL)
1696     {
1697       if (timestamp >= display_x11->current_dest_drag->start_time)
1698         {
1699           g_object_unref (display_x11->current_dest_drag);
1700           display_x11->current_dest_drag = NULL;
1701         }
1702       else
1703         return NULL;
1704     }
1705
1706   new_context = gdk_drag_context_new ();
1707   private = PRIVATE_DATA (new_context);
1708
1709   new_context->protocol = GDK_DRAG_PROTO_MOTIF;
1710   new_context->is_source = FALSE;
1711
1712   new_context->source_window = gdk_window_lookup_for_display (display, source_window);
1713   if (new_context->source_window)
1714     g_object_ref (new_context->source_window);
1715   else
1716     {
1717       new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
1718       if (!new_context->source_window)
1719         {
1720           g_object_unref (new_context);
1721           return NULL;
1722         }
1723     }
1724
1725   new_context->dest_window = dest_window;
1726   g_object_ref (dest_window);
1727   new_context->start_time = timestamp;
1728
1729   if (!motif_read_initiator_info (GDK_WINDOW_DISPLAY (dest_window),
1730                                   source_window,
1731                                   atom,
1732                                   &new_context->targets,
1733                                   &private->motif_selection))
1734     {
1735       g_object_unref (new_context);
1736       return NULL;
1737     }
1738
1739   return new_context;
1740 }
1741
1742 /*
1743  * The MOTIF drag protocol has no real provisions for distinguishing
1744  * multiple simultaneous drops. If the sources grab the pointer
1745  * when doing drags, that shouldn't happen, in any case. If it
1746  * does, we can't do much except hope for the best.
1747  */
1748
1749 static GdkFilterReturn
1750 motif_top_level_enter (GdkEvent *event,
1751                        guint16   flags, 
1752                        guint32   timestamp, 
1753                        guint32   source_window, 
1754                        guint32   atom)
1755 {
1756   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1757   GdkDragContext *new_context;
1758
1759   GDK_NOTE(DND, g_message ("Motif DND top level enter: flags: %#4x time: %d source_widow: %#4x atom: %d",
1760                            flags, timestamp, source_window, atom));
1761
1762   new_context = motif_drag_context_new (event->any.window, timestamp, source_window, atom);
1763   if (!new_context)
1764     return GDK_FILTER_REMOVE;
1765
1766   event->dnd.type = GDK_DRAG_ENTER;
1767   event->dnd.context = new_context;
1768   g_object_ref (new_context);
1769
1770   display_x11->current_dest_drag = new_context;
1771
1772   return GDK_FILTER_TRANSLATE;
1773 }
1774
1775 static GdkFilterReturn
1776 motif_top_level_leave (GdkEvent *event,
1777                        guint16   flags, 
1778                        guint32   timestamp)
1779 {
1780   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1781
1782   GDK_NOTE(DND, g_message ("Motif DND top level leave: flags: %#4x time: %d",
1783                            flags, timestamp));
1784
1785   if ((display_x11->current_dest_drag != NULL) &&
1786       (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1787       (timestamp >= display_x11->current_dest_drag->start_time))
1788     {
1789       event->dnd.type = GDK_DRAG_LEAVE;
1790       /* Pass ownership of context to the event */
1791       event->dnd.context = display_x11->current_dest_drag;
1792
1793       display_x11->current_dest_drag = NULL;
1794
1795       return GDK_FILTER_TRANSLATE;
1796     }
1797   else
1798     return GDK_FILTER_REMOVE;
1799 }
1800
1801 static GdkFilterReturn
1802 motif_motion (GdkEvent *event,
1803               guint16   flags, 
1804               guint32   timestamp,
1805               gint16    x_root,
1806               gint16    y_root)
1807 {
1808   GdkDragContextPrivateX11 *private;
1809   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1810   
1811   GDK_NOTE(DND, g_message ("Motif DND motion: flags: %#4x time: %d (%d, %d)",
1812                            flags, timestamp, x_root, y_root));
1813
1814   if ((display_x11->current_dest_drag != NULL) &&
1815       (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1816       (timestamp >= display_x11->current_dest_drag->start_time))
1817     {
1818       private = PRIVATE_DATA (display_x11->current_dest_drag);
1819
1820       event->dnd.type = GDK_DRAG_MOTION;
1821       event->dnd.context = display_x11->current_dest_drag;
1822       g_object_ref (display_x11->current_dest_drag);
1823
1824       event->dnd.time = timestamp;
1825
1826       motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
1827
1828       event->dnd.x_root = x_root;
1829       event->dnd.y_root = y_root;
1830
1831       private->last_x = x_root;
1832       private->last_y = y_root;
1833
1834       private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
1835
1836       return GDK_FILTER_TRANSLATE;
1837     }
1838
1839   return GDK_FILTER_REMOVE;
1840 }
1841
1842 static GdkFilterReturn
1843 motif_operation_changed (GdkEvent *event,
1844                          guint16   flags, 
1845                          guint32   timestamp)
1846 {
1847   GdkDragContextPrivateX11 *private;
1848   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1849   GDK_NOTE(DND, g_message ("Motif DND operation changed: flags: %#4x time: %d",
1850                            flags, timestamp));
1851
1852   if ((display_x11->current_dest_drag != NULL) &&
1853       (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1854       (timestamp >= display_x11->current_dest_drag->start_time))
1855     {
1856       event->dnd.type = GDK_DRAG_MOTION;
1857       event->dnd.send_event = FALSE;
1858       event->dnd.context = display_x11->current_dest_drag;
1859       g_object_ref (display_x11->current_dest_drag);
1860
1861       event->dnd.time = timestamp;
1862       private = PRIVATE_DATA (display_x11->current_dest_drag);
1863
1864       motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
1865
1866       event->dnd.x_root = private->last_x;
1867       event->dnd.y_root = private->last_y;
1868
1869       private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
1870
1871       return GDK_FILTER_TRANSLATE;
1872     }
1873
1874   return GDK_FILTER_REMOVE;
1875 }
1876
1877 static GdkFilterReturn
1878 motif_drop_start (GdkEvent *event,
1879                   guint16   flags,
1880                   guint32   timestamp,
1881                   guint32   source_window,
1882                   guint32   atom,
1883                   gint16    x_root,
1884                   gint16    y_root)
1885 {
1886   GdkDragContext *new_context;
1887   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1888
1889   GDK_NOTE(DND, g_message ("Motif DND drop start: flags: %#4x time: %d (%d, %d) source_widow: %#4x atom: %d",
1890                            flags, timestamp, x_root, y_root, source_window, atom));
1891
1892   new_context = motif_drag_context_new (event->any.window, timestamp, source_window, atom);
1893   if (!new_context)
1894     return GDK_FILTER_REMOVE;
1895
1896   motif_dnd_translate_flags (new_context, flags);
1897
1898   event->dnd.type = GDK_DROP_START;
1899   event->dnd.context = new_context;
1900   event->dnd.time = timestamp;
1901   event->dnd.x_root = x_root;
1902   event->dnd.y_root = y_root;
1903
1904   gdk_x11_window_set_user_time (event->any.window, timestamp);
1905
1906   g_object_ref (new_context);
1907   display_x11->current_dest_drag = new_context;
1908
1909   return GDK_FILTER_TRANSLATE;
1910 }  
1911
1912 static GdkFilterReturn
1913 motif_drag_status (GdkEvent *event,
1914                    guint16   flags,
1915                    guint32   timestamp)
1916 {
1917   GdkDragContext *context;
1918   GdkDisplay *display;
1919   
1920   GDK_NOTE (DND, 
1921             g_message ("Motif status message: flags %x", flags));
1922
1923   display = gdk_drawable_get_display (event->any.window);
1924   if (!display)
1925     return GDK_FILTER_REMOVE;
1926   
1927   context = gdk_drag_context_find (display, TRUE, GDK_DRAWABLE_XID (event->any.window), None);
1928
1929   if (context)
1930     {
1931       GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1932       if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
1933           (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
1934         private->drag_status = GDK_DRAG_STATUS_DRAG;
1935       
1936       event->dnd.type = GDK_DRAG_STATUS;
1937       event->dnd.send_event = FALSE;
1938       event->dnd.context = context;
1939       g_object_ref (context);
1940
1941       event->dnd.time = timestamp;
1942
1943       if ((flags & 0x00f0) >> 4 == XmDROP_SITE_VALID)
1944         {
1945           switch (flags & 0x000f)
1946             {
1947             case XmDROP_NOOP:
1948               context->action = 0;
1949               break;
1950             case XmDROP_MOVE:
1951                 context->action = GDK_ACTION_MOVE;
1952                 break;
1953             case XmDROP_COPY:
1954               context->action = GDK_ACTION_COPY;
1955               break;
1956             case XmDROP_LINK:
1957               context->action = GDK_ACTION_LINK;
1958               break;
1959             }
1960         }
1961       else
1962         context->action = 0;
1963
1964       return GDK_FILTER_TRANSLATE;
1965     }
1966   return GDK_FILTER_REMOVE;
1967 }
1968
1969 static GdkFilterReturn
1970 motif_dnd_filter (GdkXEvent *xev,
1971                   GdkEvent  *event,
1972                   gpointer data)
1973 {
1974   XEvent *xevent = (XEvent *)xev;
1975
1976   guint8 reason;
1977   guint16 flags;
1978   guint32 timestamp;
1979   guint32 source_window;
1980   Atom atom;
1981   gint16 x_root, y_root;
1982   gboolean is_reply;
1983
1984   if (!event->any.window ||
1985       gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
1986     return GDK_FILTER_CONTINUE;                 /* Not for us */
1987   
1988   /* First read some fields common to all Motif DND messages */
1989
1990   reason = MOTIF_UNPACK_BYTE (xevent, 0);
1991   flags = MOTIF_UNPACK_SHORT (xevent, 1);
1992   timestamp = MOTIF_UNPACK_LONG (xevent, 1);
1993
1994   is_reply = ((reason & 0x80) != 0);
1995
1996   switch (reason & 0x7f)
1997     {
1998     case XmTOP_LEVEL_ENTER:
1999       source_window = MOTIF_UNPACK_LONG (xevent, 2);
2000       atom = MOTIF_UNPACK_LONG (xevent, 3);
2001       return motif_top_level_enter (event, flags, timestamp, source_window, atom);
2002     case XmTOP_LEVEL_LEAVE:
2003       return motif_top_level_leave (event, flags, timestamp);
2004
2005     case XmDRAG_MOTION:
2006       x_root = MOTIF_UNPACK_SHORT (xevent, 4);
2007       y_root = MOTIF_UNPACK_SHORT (xevent, 5);
2008       
2009       if (!is_reply)
2010         return motif_motion (event, flags, timestamp, x_root, y_root);
2011       else
2012         return motif_drag_status (event, flags, timestamp);
2013
2014     case XmDROP_SITE_ENTER:
2015       return motif_drag_status (event, flags, timestamp);
2016
2017     case XmDROP_SITE_LEAVE:
2018       return motif_drag_status (event,
2019                                 XmNO_DROP_SITE << 8 | XmDROP_NOOP, 
2020                                 timestamp);
2021     case XmDROP_START:
2022       x_root = MOTIF_UNPACK_SHORT (xevent, 4);
2023       y_root = MOTIF_UNPACK_SHORT (xevent, 5);
2024       atom = MOTIF_UNPACK_LONG (xevent, 3);
2025       source_window = MOTIF_UNPACK_LONG (xevent, 4);
2026
2027       if (!is_reply)
2028         return motif_drop_start (event, flags, timestamp, source_window, atom, x_root, y_root);
2029       
2030      break;
2031     case XmOPERATION_CHANGED:
2032       if (!is_reply)
2033         return motif_operation_changed (event, flags, timestamp);
2034       else
2035         return motif_drag_status (event, flags, timestamp);
2036
2037       break;
2038       /* To the best of my knowledge, these next two messages are 
2039        * not part of the protocol, though they are defined in
2040        * the header files.
2041        */
2042     case XmDROP_FINISH:
2043     case XmDRAG_DROP_FINISH:
2044       break;
2045     }
2046
2047   return GDK_FILTER_REMOVE;
2048 }
2049
2050 /*************************************************************
2051  ***************************** XDND **************************
2052  *************************************************************/
2053
2054 /* Utility functions */
2055
2056 static struct {
2057   const gchar *name;
2058   GdkAtom atom;
2059   GdkDragAction action;
2060 } xdnd_actions_table[] = {
2061     { "XdndActionCopy",    None, GDK_ACTION_COPY },
2062     { "XdndActionMove",    None, GDK_ACTION_MOVE },
2063     { "XdndActionLink",    None, GDK_ACTION_LINK },
2064     { "XdndActionAsk",     None, GDK_ACTION_ASK  },
2065     { "XdndActionPrivate", None, GDK_ACTION_COPY },
2066   };
2067
2068 static const gint xdnd_n_actions = sizeof(xdnd_actions_table) / sizeof(xdnd_actions_table[0]);
2069 static gboolean xdnd_actions_initialized = FALSE;
2070
2071 static void
2072 xdnd_initialize_actions (void)
2073 {
2074   gint i;
2075   
2076   xdnd_actions_initialized = TRUE;
2077   for (i=0; i < xdnd_n_actions; i++)
2078     xdnd_actions_table[i].atom = gdk_atom_intern_static_string (xdnd_actions_table[i].name);
2079 }
2080
2081 static GdkDragAction
2082 xdnd_action_from_atom (GdkDisplay *display,
2083                        Atom        xatom)
2084 {
2085   GdkAtom atom;
2086   gint i;
2087
2088   if (xatom == None)
2089     return 0;
2090
2091   atom = gdk_x11_xatom_to_atom_for_display (display, xatom);
2092
2093   if (!xdnd_actions_initialized)
2094     xdnd_initialize_actions();
2095
2096   for (i=0; i<xdnd_n_actions; i++)
2097     if (atom == xdnd_actions_table[i].atom)
2098       return xdnd_actions_table[i].action;
2099
2100   return 0;
2101 }
2102
2103 static Atom
2104 xdnd_action_to_atom (GdkDisplay    *display,
2105                      GdkDragAction  action)
2106 {
2107   gint i;
2108
2109   if (!xdnd_actions_initialized)
2110     xdnd_initialize_actions();
2111
2112   for (i=0; i<xdnd_n_actions; i++)
2113     if (action == xdnd_actions_table[i].action)
2114       return gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
2115
2116   return None;
2117 }
2118
2119 /* Source side */
2120
2121 static GdkFilterReturn 
2122 xdnd_status_filter (GdkXEvent *xev,
2123                     GdkEvent  *event,
2124                     gpointer   data)
2125 {
2126   GdkDisplay *display;
2127   XEvent *xevent = (XEvent *)xev;
2128   guint32 dest_window = xevent->xclient.data.l[0];
2129   guint32 flags = xevent->xclient.data.l[1];
2130   Atom action = xevent->xclient.data.l[4];
2131   GdkDragContext *context;
2132
2133   if (!event->any.window ||
2134       gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2135     return GDK_FILTER_CONTINUE;                 /* Not for us */
2136   
2137   GDK_NOTE (DND, 
2138             g_message ("XdndStatus: dest_window: %#x  action: %ld",
2139                        dest_window, action));
2140
2141   display = gdk_drawable_get_display (event->any.window);
2142   context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
2143   
2144   if (context)
2145     {
2146       GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2147       if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
2148         private->drag_status = GDK_DRAG_STATUS_DRAG;
2149       
2150       event->dnd.send_event = FALSE;
2151       event->dnd.type = GDK_DRAG_STATUS;
2152       event->dnd.context = context;
2153       gdk_event_set_device (event, gdk_drag_context_get_device (context));
2154       g_object_ref (context);
2155
2156       event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
2157       if (!(action != 0) != !(flags & 1))
2158         {
2159           GDK_NOTE (DND,
2160                     g_warning ("Received status event with flags not corresponding to action!\n"));
2161           action = 0;
2162         }
2163
2164       context->action = xdnd_action_from_atom (display, action);
2165
2166       return GDK_FILTER_TRANSLATE;
2167     }
2168
2169   return GDK_FILTER_REMOVE;
2170 }
2171
2172 static GdkFilterReturn 
2173 xdnd_finished_filter (GdkXEvent *xev,
2174                       GdkEvent  *event,
2175                       gpointer   data)
2176 {
2177   GdkDisplay *display;
2178   XEvent *xevent = (XEvent *)xev;
2179   guint32 dest_window = xevent->xclient.data.l[0];
2180   GdkDragContext *context;
2181   GdkDragContextPrivateX11 *private;
2182
2183   if (!event->any.window ||
2184       gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2185     return GDK_FILTER_CONTINUE;                 /* Not for us */
2186   
2187   GDK_NOTE (DND, 
2188             g_message ("XdndFinished: dest_window: %#x", dest_window));
2189
2190   display = gdk_drawable_get_display (event->any.window);
2191   context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
2192   
2193   if (context)
2194     {
2195       private = PRIVATE_DATA (context);
2196       if (private->version == 5)
2197         private->drop_failed = xevent->xclient.data.l[1] == 0;
2198       
2199       event->dnd.type = GDK_DROP_FINISHED;
2200       event->dnd.context = context;
2201       gdk_event_set_device (event, gdk_drag_context_get_device (context));
2202       g_object_ref (context);
2203
2204       event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
2205
2206       return GDK_FILTER_TRANSLATE;
2207     }
2208
2209   return GDK_FILTER_REMOVE;
2210 }
2211
2212 static void
2213 xdnd_set_targets (GdkDragContext *context)
2214 {
2215   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2216   Atom *atomlist;
2217   GList *tmp_list = context->targets;
2218   gint i;
2219   gint n_atoms = g_list_length (context->targets);
2220   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2221
2222   atomlist = g_new (Atom, n_atoms);
2223   i = 0;
2224   while (tmp_list)
2225     {
2226       atomlist[i] = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (tmp_list->data));
2227       tmp_list = tmp_list->next;
2228       i++;
2229     }
2230
2231   XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
2232                    GDK_DRAWABLE_XID (context->source_window),
2233                    gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
2234                    XA_ATOM, 32, PropModeReplace,
2235                    (guchar *)atomlist, n_atoms);
2236
2237   g_free (atomlist);
2238
2239   private->xdnd_targets_set = 1;
2240 }
2241
2242 static void
2243 xdnd_set_actions (GdkDragContext *context)
2244 {
2245   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2246   Atom *atomlist;
2247   gint i;
2248   gint n_atoms;
2249   guint actions;
2250   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2251
2252   if (!xdnd_actions_initialized)
2253     xdnd_initialize_actions();
2254   
2255   actions = context->actions;
2256   n_atoms = 0;
2257   for (i=0; i<xdnd_n_actions; i++)
2258     {
2259       if (actions & xdnd_actions_table[i].action)
2260         {
2261           actions &= ~xdnd_actions_table[i].action;
2262           n_atoms++;
2263         }
2264     }
2265
2266   atomlist = g_new (Atom, n_atoms);
2267
2268   actions = context->actions;
2269   n_atoms = 0;
2270   for (i=0; i<xdnd_n_actions; i++)
2271     {
2272       if (actions & xdnd_actions_table[i].action)
2273         {
2274           actions &= ~xdnd_actions_table[i].action;
2275           atomlist[n_atoms] = gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
2276           n_atoms++;
2277         }
2278     }
2279
2280   XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
2281                    GDK_DRAWABLE_XID (context->source_window),
2282                    gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
2283                    XA_ATOM, 32, PropModeReplace,
2284                    (guchar *)atomlist, n_atoms);
2285
2286   g_free (atomlist);
2287
2288   private->xdnd_actions_set = TRUE;
2289   private->xdnd_actions = context->actions;
2290 }
2291
2292 static void
2293 send_client_message_async_cb (Window   window,
2294                               gboolean success,
2295                               gpointer data)
2296 {
2297   GdkDragContext *context = data;
2298   GDK_NOTE (DND,
2299             g_message ("Got async callback for #%lx, success = %d",
2300                        window, success));
2301
2302   /* On failure, we immediately continue with the protocol
2303    * so we don't end up blocking for a timeout
2304    */
2305   if (!success &&
2306       context->dest_window &&
2307       window == GDK_WINDOW_XID (context->dest_window))
2308     {
2309       GdkEvent *temp_event;
2310       GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2311
2312       g_object_unref (context->dest_window);
2313       context->dest_window = NULL;
2314       context->action = 0;
2315
2316       private->drag_status = GDK_DRAG_STATUS_DRAG;
2317
2318       temp_event = gdk_event_new (GDK_DRAG_STATUS);
2319       temp_event->dnd.window = g_object_ref (context->source_window);
2320       temp_event->dnd.send_event = TRUE;
2321       temp_event->dnd.context = g_object_ref (context);
2322       temp_event->dnd.time = GDK_CURRENT_TIME;
2323       gdk_event_set_device (temp_event, gdk_drag_context_get_device (context));
2324
2325       gdk_event_put (temp_event);
2326
2327       gdk_event_free (temp_event);
2328     }
2329
2330   g_object_unref (context);
2331 }
2332
2333
2334 static GdkDisplay *
2335 gdk_drag_context_get_display (GdkDragContext *context)
2336 {
2337   if (context->source_window)
2338     return GDK_DRAWABLE_DISPLAY (context->source_window);
2339   else if (context->dest_window)
2340     return GDK_DRAWABLE_DISPLAY (context->dest_window);
2341
2342   g_assert_not_reached ();
2343   return NULL;
2344 }
2345
2346 static void
2347 send_client_message_async (GdkDragContext      *context,
2348                            Window               window, 
2349                            gboolean             propagate,
2350                            glong                event_mask,
2351                            XClientMessageEvent *event_send)
2352 {
2353   GdkDisplay *display = gdk_drag_context_get_display (context);
2354   
2355   g_object_ref (context);
2356
2357   _gdk_x11_send_client_message_async (display, window,
2358                                       propagate, event_mask, event_send,
2359                                       send_client_message_async_cb, context);
2360 }
2361
2362 static gboolean
2363 xdnd_send_xevent (GdkDragContext *context,
2364                   GdkWindow      *window, 
2365                   gboolean        propagate,
2366                   XEvent         *event_send)
2367 {
2368   GdkDisplay *display = gdk_drag_context_get_display (context);
2369   Window xwindow;
2370   glong event_mask;
2371
2372   g_assert (event_send->xany.type == ClientMessage);
2373
2374   /* We short-circuit messages to ourselves */
2375   if (gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
2376     {
2377       gint i;
2378       
2379       for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
2380         {
2381           if (gdk_x11_get_xatom_by_name_for_display (display, xdnd_filters[i].atom_name) ==
2382               event_send->xclient.message_type)
2383             {
2384               GdkEvent *temp_event;
2385
2386               temp_event = gdk_event_new (GDK_NOTHING);
2387               temp_event->any.window = g_object_ref (window);
2388
2389               if ((*xdnd_filters[i].func) (event_send, temp_event, NULL) == GDK_FILTER_TRANSLATE)
2390                 {
2391                   gdk_event_put (temp_event);
2392                   gdk_event_free (temp_event);
2393                 }
2394               
2395               return TRUE;
2396             }
2397         }
2398     }
2399
2400   xwindow = GDK_WINDOW_XWINDOW (window);
2401   
2402   if (_gdk_x11_display_is_root_window (display, xwindow))
2403     event_mask = ButtonPressMask;
2404   else
2405     event_mask = 0;
2406   
2407   send_client_message_async (context, xwindow, propagate, event_mask,
2408                              &event_send->xclient);
2409
2410   return TRUE;
2411 }
2412  
2413 static void
2414 xdnd_send_enter (GdkDragContext *context)
2415 {
2416   XEvent xev;
2417   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2418   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->dest_window);
2419
2420   xev.xclient.type = ClientMessage;
2421   xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndEnter");
2422   xev.xclient.format = 32;
2423   xev.xclient.window = private->drop_xid ? 
2424                            private->drop_xid : 
2425                            GDK_DRAWABLE_XID (context->dest_window);
2426   xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2427   xev.xclient.data.l[1] = (private->version << 24); /* version */
2428   xev.xclient.data.l[2] = 0;
2429   xev.xclient.data.l[3] = 0;
2430   xev.xclient.data.l[4] = 0;
2431
2432   GDK_NOTE(DND,
2433            g_message ("Sending enter source window %#lx XDND protocol version %d\n",
2434                       GDK_DRAWABLE_XID (context->source_window), private->version));
2435   if (g_list_length (context->targets) > 3)
2436     {
2437       if (!private->xdnd_targets_set)
2438         xdnd_set_targets (context);
2439       xev.xclient.data.l[1] |= 1;
2440     }
2441   else
2442     {
2443       GList *tmp_list = context->targets;
2444       gint i = 2;
2445
2446       while (tmp_list)
2447         {
2448           xev.xclient.data.l[i] = gdk_x11_atom_to_xatom_for_display (display,
2449                                                                      GDK_POINTER_TO_ATOM (tmp_list->data));
2450           tmp_list = tmp_list->next;
2451           i++;
2452         }
2453     }
2454
2455   if (!xdnd_send_xevent (context, context->dest_window,
2456                          FALSE, &xev))
2457     {
2458       GDK_NOTE (DND, 
2459                 g_message ("Send event to %lx failed",
2460                            GDK_DRAWABLE_XID (context->dest_window)));
2461       g_object_unref (context->dest_window);
2462       context->dest_window = NULL;
2463     }
2464 }
2465
2466 static void
2467 xdnd_send_leave (GdkDragContext *context)
2468 {
2469   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2470   XEvent xev;
2471
2472   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2473
2474   xev.xclient.type = ClientMessage;
2475   xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndLeave");
2476   xev.xclient.format = 32;
2477   xev.xclient.window = private->drop_xid ? 
2478                            private->drop_xid : 
2479                            GDK_DRAWABLE_XID (context->dest_window);
2480   xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2481   xev.xclient.data.l[1] = 0;
2482   xev.xclient.data.l[2] = 0;
2483   xev.xclient.data.l[3] = 0;
2484   xev.xclient.data.l[4] = 0;
2485
2486   if (!xdnd_send_xevent (context, context->dest_window,
2487                          FALSE, &xev))
2488     {
2489       GDK_NOTE (DND, 
2490                 g_message ("Send event to %lx failed",
2491                            GDK_DRAWABLE_XID (context->dest_window)));
2492       g_object_unref (context->dest_window);
2493       context->dest_window = NULL;
2494     }
2495 }
2496
2497 static void
2498 xdnd_send_drop (GdkDragContext *context, guint32 time)
2499 {
2500   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2501   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2502   XEvent xev;
2503
2504   xev.xclient.type = ClientMessage;
2505   xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndDrop");
2506   xev.xclient.format = 32;
2507   xev.xclient.window = private->drop_xid ? 
2508                            private->drop_xid : 
2509                            GDK_DRAWABLE_XID (context->dest_window);
2510   xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2511   xev.xclient.data.l[1] = 0;
2512   xev.xclient.data.l[2] = time;
2513   xev.xclient.data.l[3] = 0;
2514   xev.xclient.data.l[4] = 0;
2515
2516   if (!xdnd_send_xevent (context, context->dest_window,
2517                          FALSE, &xev))
2518     {
2519       GDK_NOTE (DND, 
2520                 g_message ("Send event to %lx failed",
2521                            GDK_DRAWABLE_XID (context->dest_window)));
2522       g_object_unref (context->dest_window);
2523       context->dest_window = NULL;
2524     }
2525 }
2526
2527 static void
2528 xdnd_send_motion (GdkDragContext *context,
2529                   gint            x_root, 
2530                   gint            y_root,
2531                   GdkDragAction   action,
2532                   guint32         time)
2533 {
2534   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2535   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2536   XEvent xev;
2537
2538   xev.xclient.type = ClientMessage;
2539   xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndPosition");
2540   xev.xclient.format = 32;
2541   xev.xclient.window = private->drop_xid ? 
2542                            private->drop_xid : 
2543                            GDK_DRAWABLE_XID (context->dest_window);
2544   xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2545   xev.xclient.data.l[1] = 0;
2546   xev.xclient.data.l[2] = (x_root << 16) | y_root;
2547   xev.xclient.data.l[3] = time;
2548   xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
2549
2550   if (!xdnd_send_xevent (context, context->dest_window,
2551                          FALSE, &xev))
2552     {
2553       GDK_NOTE (DND, 
2554                 g_message ("Send event to %lx failed",
2555                            GDK_DRAWABLE_XID (context->dest_window)));
2556       g_object_unref (context->dest_window);
2557       context->dest_window = NULL;
2558     }
2559   private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
2560 }
2561
2562 static guint32
2563 xdnd_check_dest (GdkDisplay *display,
2564                  Window      win,
2565                  guint      *xdnd_version)
2566 {
2567   gboolean retval = FALSE;
2568   Atom type = None;
2569   int format;
2570   unsigned long nitems, after;
2571   guchar *data;
2572   Atom *version;
2573   Window *proxy_data;
2574   Window proxy;
2575   Atom xdnd_proxy_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndProxy");
2576   Atom xdnd_aware_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndAware");
2577
2578   proxy = None;
2579
2580   gdk_error_trap_push ();
2581   
2582   if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win, 
2583                           xdnd_proxy_atom, 0, 
2584                           1, False, AnyPropertyType,
2585                           &type, &format, &nitems, &after, 
2586                           &data) == Success)
2587     {
2588       if (type != None)
2589         {
2590           proxy_data = (Window *)data;
2591           
2592           if ((format == 32) && (nitems == 1))
2593             {
2594               proxy = *proxy_data;
2595             }
2596           else
2597             GDK_NOTE (DND, 
2598                       g_warning ("Invalid XdndProxy "
2599                                  "property on window %ld\n", win));
2600           
2601           XFree (proxy_data);
2602         }
2603       
2604       if ((XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), proxy ? proxy : win,
2605                                xdnd_aware_atom, 0, 
2606                                1, False, AnyPropertyType,
2607                                &type, &format, &nitems, &after, 
2608                                &data) == Success) &&
2609           type != None)
2610         {
2611           version = (Atom *)data;
2612           
2613           if ((format == 32) && (nitems == 1))
2614             {
2615               if (*version >= 3)
2616                 retval = TRUE;
2617               if (xdnd_version)
2618                 *xdnd_version = *version;
2619             }
2620           else
2621             GDK_NOTE (DND, 
2622                       g_warning ("Invalid XdndAware "
2623                                  "property on window %ld\n", win));
2624           
2625           XFree (version);
2626         }
2627     }
2628
2629   gdk_error_trap_pop ();
2630   
2631   return retval ? (proxy ? proxy : win) : None;
2632 }
2633
2634 /* Target side */
2635
2636 static void
2637 xdnd_read_actions (GdkDragContext *context)
2638 {
2639   GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
2640   Atom type;
2641   int format;
2642   gulong nitems, after;
2643   guchar *data;
2644   Atom *atoms;
2645
2646   gint i;
2647   
2648   PRIVATE_DATA (context)->xdnd_have_actions = FALSE;
2649
2650   if (gdk_window_get_window_type (context->source_window) == GDK_WINDOW_FOREIGN)
2651     {
2652       /* Get the XdndActionList, if set */
2653       
2654       gdk_error_trap_push ();
2655       
2656       if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
2657                               GDK_DRAWABLE_XID (context->source_window),
2658                               gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
2659                               0, 65536,
2660                               False, XA_ATOM, &type, &format, &nitems,
2661                               &after, &data) == Success &&
2662           type == XA_ATOM)
2663         {
2664           atoms = (Atom *)data;
2665           
2666           context->actions = 0;
2667           
2668           for (i=0; i<nitems; i++)
2669             context->actions |= xdnd_action_from_atom (display, atoms[i]);
2670           
2671           PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
2672           
2673 #ifdef G_ENABLE_DEBUG
2674           if (_gdk_debug_flags & GDK_DEBUG_DND)
2675             {
2676               GString *action_str = g_string_new (NULL);
2677               if (context->actions & GDK_ACTION_MOVE)
2678                 g_string_append(action_str, "MOVE ");
2679               if (context->actions & GDK_ACTION_COPY)
2680                 g_string_append(action_str, "COPY ");
2681               if (context->actions & GDK_ACTION_LINK)
2682                 g_string_append(action_str, "LINK ");
2683               if (context->actions & GDK_ACTION_ASK)
2684                 g_string_append(action_str, "ASK ");
2685               
2686               g_message("Xdnd actions = %s", action_str->str);
2687               g_string_free (action_str, TRUE);
2688             }
2689 #endif /* G_ENABLE_DEBUG */
2690           
2691         }
2692
2693       if (data)
2694         XFree (data);
2695       
2696       gdk_error_trap_pop ();
2697     }
2698   else
2699     {
2700       /* Local drag
2701        */
2702       GdkDragContext *source_context;
2703
2704       source_context = gdk_drag_context_find (display, TRUE,
2705                                               GDK_DRAWABLE_XID (context->source_window),
2706                                               GDK_DRAWABLE_XID (context->dest_window));
2707
2708       if (source_context)
2709         {
2710           context->actions = source_context->actions;
2711           PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
2712         }
2713     }
2714 }
2715
2716 /* We have to make sure that the XdndActionList we keep internally
2717  * is up to date with the XdndActionList on the source window
2718  * because we get no notification, because Xdnd wasn't meant
2719  * to continually send actions. So we select on PropertyChangeMask
2720  * and add this filter.
2721  */
2722 static GdkFilterReturn 
2723 xdnd_source_window_filter (GdkXEvent *xev,
2724                            GdkEvent  *event,
2725                            gpointer   cb_data)
2726 {
2727   XEvent *xevent = (XEvent *)xev;
2728   GdkDragContext *context = cb_data;
2729   GdkDisplay *display = GDK_WINDOW_DISPLAY(event->any.window);
2730
2731   if ((xevent->xany.type == PropertyNotify) &&
2732       (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList")))
2733     {
2734       xdnd_read_actions (context);
2735
2736       return GDK_FILTER_REMOVE;
2737     }
2738
2739   return GDK_FILTER_CONTINUE;
2740 }
2741
2742 static void
2743 xdnd_manage_source_filter (GdkDragContext *context,
2744                            GdkWindow      *window,
2745                            gboolean        add_filter)
2746 {
2747   if (!GDK_WINDOW_DESTROYED (window) &&
2748       gdk_window_get_window_type (window) == GDK_WINDOW_FOREIGN)
2749     {
2750       gdk_error_trap_push ();
2751
2752       if (add_filter)
2753         {
2754           gdk_window_set_events (window,
2755                                  gdk_window_get_events (window) |
2756                                  GDK_PROPERTY_CHANGE_MASK);
2757           gdk_window_add_filter (window, xdnd_source_window_filter, context);
2758         }
2759       else
2760         {
2761           gdk_window_remove_filter (window,
2762                                     xdnd_source_window_filter,
2763                                     context);
2764           /* Should we remove the GDK_PROPERTY_NOTIFY mask?
2765            * but we might want it for other reasons. (Like
2766            * INCR selection transactions).
2767            */
2768         }
2769       
2770       gdk_display_sync (gdk_drawable_get_display (window));
2771       gdk_error_trap_pop ();  
2772     }
2773 }
2774
2775 static void
2776 base_precache_atoms (GdkDisplay *display)
2777 {
2778   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
2779
2780   if (!display_x11->base_dnd_atoms_precached)
2781     {
2782       static const char *const precache_atoms[] = {
2783         "ENLIGHTENMENT_DESKTOP",
2784         "WM_STATE",
2785         "XdndAware",
2786         "XdndProxy",
2787         "_MOTIF_DRAG_RECEIVER_INFO"
2788       };
2789
2790       _gdk_x11_precache_atoms (display,
2791                                precache_atoms, G_N_ELEMENTS (precache_atoms));
2792
2793       display_x11->base_dnd_atoms_precached = TRUE;
2794     }
2795 }
2796
2797 static void
2798 xdnd_precache_atoms (GdkDisplay *display)
2799 {
2800   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
2801
2802   if (!display_x11->xdnd_atoms_precached)
2803     {
2804       static const char *const precache_atoms[] = {
2805         "XdndActionAsk",
2806         "XdndActionCopy",
2807         "XdndActionLink",
2808         "XdndActionList",
2809         "XdndActionMove",
2810         "XdndActionPrivate",
2811         "XdndDrop",
2812         "XdndEnter",
2813         "XdndFinished",
2814         "XdndLeave",
2815         "XdndPosition",
2816         "XdndSelection",
2817         "XdndStatus",
2818         "XdndTypeList"
2819       };
2820
2821       _gdk_x11_precache_atoms (display,
2822                                precache_atoms, G_N_ELEMENTS (precache_atoms));
2823
2824       display_x11->xdnd_atoms_precached = TRUE;
2825     }
2826 }
2827
2828 static GdkFilterReturn 
2829 xdnd_enter_filter (GdkXEvent *xev,
2830                    GdkEvent  *event,
2831                    gpointer   cb_data)
2832 {
2833   GdkDisplay *display;
2834   GdkDisplayX11 *display_x11;
2835   XEvent *xevent = (XEvent *)xev;
2836   GdkDragContext *new_context;
2837   gint i;
2838   
2839   Atom type;
2840   int format;
2841   gulong nitems, after;
2842   guchar *data;
2843   Atom *atoms;
2844
2845   guint32 source_window;
2846   gboolean get_types;
2847   gint version;
2848
2849   if (!event->any.window ||
2850       gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2851     return GDK_FILTER_CONTINUE;                 /* Not for us */
2852
2853   source_window = xevent->xclient.data.l[0];
2854   get_types = ((xevent->xclient.data.l[1] & 1) != 0);
2855   version = (xevent->xclient.data.l[1] & 0xff000000) >> 24;
2856   
2857   display = GDK_DRAWABLE_DISPLAY (event->any.window);
2858   display_x11 = GDK_DISPLAY_X11 (display);
2859
2860   xdnd_precache_atoms (display);
2861
2862   GDK_NOTE (DND, 
2863             g_message ("XdndEnter: source_window: %#x, version: %#x",
2864                        source_window, version));
2865
2866   if (version < 3)
2867     {
2868       /* Old source ignore */
2869       GDK_NOTE (DND, g_message ("Ignored old XdndEnter message"));
2870       return GDK_FILTER_REMOVE;
2871     }
2872   
2873   if (display_x11->current_dest_drag != NULL)
2874     {
2875       g_object_unref (display_x11->current_dest_drag);
2876       display_x11->current_dest_drag = NULL;
2877     }
2878
2879   new_context = gdk_drag_context_new ();
2880   new_context->protocol = GDK_DRAG_PROTO_XDND;
2881   PRIVATE_DATA(new_context)->version = version;
2882
2883   /* FIXME: Should extend DnD protocol to have device info */
2884   gdk_drag_context_set_device (new_context, gdk_display_get_core_pointer (display));
2885
2886   new_context->source_window = gdk_window_lookup_for_display (display, source_window);
2887   if (new_context->source_window)
2888     g_object_ref (new_context->source_window);
2889   else
2890     {
2891       new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
2892       if (!new_context->source_window)
2893         {
2894           g_object_unref (new_context);
2895           return GDK_FILTER_REMOVE;
2896         }
2897     }
2898   new_context->dest_window = event->any.window;
2899   g_object_ref (new_context->dest_window);
2900
2901   new_context->targets = NULL;
2902   if (get_types)
2903     {
2904       gdk_error_trap_push ();
2905       XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (event->any.window), 
2906                           source_window, 
2907                           gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
2908                           0, 65536,
2909                           False, XA_ATOM, &type, &format, &nitems,
2910                           &after, &data);
2911
2912       if (gdk_error_trap_pop () || (format != 32) || (type != XA_ATOM))
2913         {
2914           g_object_unref (new_context);
2915
2916           if (data)
2917             XFree (data);
2918
2919           return GDK_FILTER_REMOVE;
2920         }
2921
2922       atoms = (Atom *)data;
2923
2924       for (i=0; i<nitems; i++)
2925         new_context->targets = 
2926           g_list_append (new_context->targets,
2927                          GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display,
2928                                                                                  atoms[i])));
2929
2930       XFree(atoms);
2931     }
2932   else
2933     {
2934       for (i=0; i<3; i++)
2935         if (xevent->xclient.data.l[2+i])
2936           new_context->targets =
2937             g_list_append (new_context->targets,
2938                            GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display, 
2939                                                                                    xevent->xclient.data.l[2+i])));
2940     }
2941
2942 #ifdef G_ENABLE_DEBUG
2943   if (_gdk_debug_flags & GDK_DEBUG_DND)
2944     print_target_list (new_context->targets);
2945 #endif /* G_ENABLE_DEBUG */
2946
2947   xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
2948   xdnd_read_actions (new_context);
2949
2950   event->dnd.type = GDK_DRAG_ENTER;
2951   event->dnd.context = new_context;
2952   gdk_event_set_device (event, gdk_drag_context_get_device (new_context));
2953   g_object_ref (new_context);
2954
2955   display_x11->current_dest_drag = new_context;
2956
2957   return GDK_FILTER_TRANSLATE;
2958 }
2959
2960 static GdkFilterReturn 
2961 xdnd_leave_filter (GdkXEvent *xev,
2962                    GdkEvent  *event,
2963                    gpointer   data)
2964 {
2965   XEvent *xevent = (XEvent *)xev;
2966   guint32 source_window = xevent->xclient.data.l[0];
2967   GdkDisplay *display;
2968   GdkDisplayX11 *display_x11;
2969
2970   if (!event->any.window ||
2971       gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2972     return GDK_FILTER_CONTINUE;                 /* Not for us */
2973  
2974   GDK_NOTE (DND, 
2975             g_message ("XdndLeave: source_window: %#x",
2976                        source_window));
2977
2978   display = GDK_DRAWABLE_DISPLAY (event->any.window);
2979   display_x11 = GDK_DISPLAY_X11 (display);
2980
2981   xdnd_precache_atoms (display);
2982
2983   if ((display_x11->current_dest_drag != NULL) &&
2984       (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
2985       (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
2986     {
2987       event->dnd.type = GDK_DRAG_LEAVE;
2988       /* Pass ownership of context to the event */
2989       event->dnd.context = display_x11->current_dest_drag;
2990       gdk_event_set_device (event, gdk_drag_context_get_device (event->dnd.context));
2991
2992       display_x11->current_dest_drag = NULL;
2993
2994       return GDK_FILTER_TRANSLATE;
2995     }
2996   else
2997     return GDK_FILTER_REMOVE;
2998 }
2999
3000 static GdkFilterReturn 
3001 xdnd_position_filter (GdkXEvent *xev,
3002                       GdkEvent  *event,
3003                       gpointer   data)
3004 {
3005   XEvent *xevent = (XEvent *)xev;
3006   guint32 source_window = xevent->xclient.data.l[0];
3007   gint16 x_root = xevent->xclient.data.l[2] >> 16;
3008   gint16 y_root = xevent->xclient.data.l[2] & 0xffff;
3009   guint32 time = xevent->xclient.data.l[3];
3010   Atom action = xevent->xclient.data.l[4];
3011
3012   GdkDisplay *display;
3013   GdkDisplayX11 *display_x11;
3014
3015    if (!event->any.window ||
3016        gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
3017      return GDK_FILTER_CONTINUE;                        /* Not for us */
3018    
3019   GDK_NOTE (DND, 
3020             g_message ("XdndPosition: source_window: %#x position: (%d, %d)  time: %d  action: %ld",
3021                        source_window, x_root, y_root, time, action));
3022
3023   display = GDK_DRAWABLE_DISPLAY (event->any.window);
3024   display_x11 = GDK_DISPLAY_X11 (display);
3025   
3026   xdnd_precache_atoms (display);
3027
3028   if ((display_x11->current_dest_drag != NULL) &&
3029       (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
3030       (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
3031     {
3032       event->dnd.type = GDK_DRAG_MOTION;
3033       event->dnd.context = display_x11->current_dest_drag;
3034       gdk_event_set_device (event, gdk_drag_context_get_device (event->dnd.context));
3035       g_object_ref (display_x11->current_dest_drag);
3036
3037       event->dnd.time = time;
3038
3039       display_x11->current_dest_drag->suggested_action = xdnd_action_from_atom (display, action);
3040       
3041       if (!(PRIVATE_DATA (display_x11->current_dest_drag))->xdnd_have_actions)
3042         display_x11->current_dest_drag->actions = display_x11->current_dest_drag->suggested_action;
3043
3044       event->dnd.x_root = x_root;
3045       event->dnd.y_root = y_root;
3046
3047       (PRIVATE_DATA (display_x11->current_dest_drag))->last_x = x_root;
3048       (PRIVATE_DATA (display_x11->current_dest_drag))->last_y = y_root;
3049       
3050       return GDK_FILTER_TRANSLATE;
3051     }
3052
3053   return GDK_FILTER_REMOVE;
3054 }
3055
3056 static GdkFilterReturn 
3057 xdnd_drop_filter (GdkXEvent *xev,
3058                   GdkEvent  *event,
3059                   gpointer   data)
3060 {
3061   XEvent *xevent = (XEvent *)xev;
3062   guint32 source_window = xevent->xclient.data.l[0];
3063   guint32 time = xevent->xclient.data.l[2];
3064   GdkDisplay *display;
3065   GdkDisplayX11 *display_x11;
3066   
3067   if (!event->any.window ||
3068       gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
3069     return GDK_FILTER_CONTINUE;                 /* Not for us */
3070   
3071   GDK_NOTE (DND, 
3072             g_message ("XdndDrop: source_window: %#x  time: %d",
3073                        source_window, time));
3074
3075   display = GDK_DRAWABLE_DISPLAY (event->any.window);
3076   display_x11 = GDK_DISPLAY_X11 (display);
3077
3078   xdnd_precache_atoms (display);
3079
3080   if ((display_x11->current_dest_drag != NULL) &&
3081       (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
3082       (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
3083     {
3084       GdkDragContextPrivateX11 *private;
3085       private = PRIVATE_DATA (display_x11->current_dest_drag);
3086
3087       event->dnd.type = GDK_DROP_START;
3088
3089       event->dnd.context = display_x11->current_dest_drag;
3090       gdk_event_set_device (event, gdk_drag_context_get_device (event->dnd.context));
3091       g_object_ref (display_x11->current_dest_drag);
3092
3093       event->dnd.time = time;
3094       event->dnd.x_root = private->last_x;
3095       event->dnd.y_root = private->last_y;
3096
3097       gdk_x11_window_set_user_time (event->any.window, time);
3098       
3099       return GDK_FILTER_TRANSLATE;
3100     }
3101
3102   return GDK_FILTER_REMOVE;
3103 }
3104
3105 /*************************************************************
3106  ************************** Public API ***********************
3107  *************************************************************/
3108 void
3109 _gdk_dnd_init (GdkDisplay *display)
3110 {
3111   int i;
3112   init_byte_order ();
3113
3114   gdk_display_add_client_message_filter (
3115         display,
3116         gdk_atom_intern_static_string ("_MOTIF_DRAG_AND_DROP_MESSAGE"),
3117         motif_dnd_filter, NULL);
3118   
3119   for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
3120     {
3121       gdk_display_add_client_message_filter (
3122         display,
3123         gdk_atom_intern_static_string (xdnd_filters[i].atom_name),
3124         xdnd_filters[i].func, NULL);
3125     }
3126 }                     
3127
3128 /* Source side */
3129
3130 static void
3131 gdk_drag_do_leave (GdkDragContext *context, guint32 time)
3132 {
3133   if (context->dest_window)
3134     {
3135       switch (context->protocol)
3136         {
3137         case GDK_DRAG_PROTO_MOTIF:
3138           motif_send_leave (context, time);
3139           break;
3140         case GDK_DRAG_PROTO_XDND:
3141           xdnd_send_leave (context);
3142           break;
3143         case GDK_DRAG_PROTO_ROOTWIN:
3144         case GDK_DRAG_PROTO_NONE:
3145         default:
3146           break;
3147         }
3148
3149       g_object_unref (context->dest_window);
3150       context->dest_window = NULL;
3151     }
3152 }
3153
3154 /**
3155  * gdk_drag_begin:
3156  * @window: the source window for this drag.
3157  * @targets: the offered targets, as list of #GdkAtom<!-- -->s
3158  * 
3159  * Starts a drag and creates a new drag context for it.
3160  *
3161  * This function is called by the drag source.
3162  * 
3163  * Return value: a newly created #GdkDragContext.
3164  **/
3165 GdkDragContext * 
3166 gdk_drag_begin (GdkWindow     *window,
3167                 GList         *targets)
3168 {
3169   GdkDragContext *new_context;
3170   GdkDisplay *display;
3171   GdkDevice *device;
3172   
3173   g_return_val_if_fail (window != NULL, NULL);
3174   g_return_val_if_fail (GDK_WINDOW_IS_X11 (window), NULL);
3175
3176   new_context = gdk_drag_context_new ();
3177   new_context->is_source = TRUE;
3178   new_context->source_window = window;
3179   g_object_ref (window);
3180
3181   new_context->targets = g_list_copy (targets);
3182   precache_target_list (new_context);
3183   
3184   new_context->actions = 0;
3185
3186   display = gdk_drawable_get_display (GDK_DRAWABLE (window));
3187   device = gdk_display_get_core_pointer (display);
3188   gdk_drag_context_set_device (new_context, device);
3189
3190   return new_context;
3191 }
3192
3193 static GdkNativeWindow
3194 _gdk_drag_get_protocol_for_display (GdkDisplay      *display,
3195                                     GdkNativeWindow  xid,
3196                                     GdkDragProtocol *protocol,
3197                                     guint           *version)
3198
3199 {
3200   GdkWindow *window;
3201   GdkNativeWindow retval;
3202   g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
3203
3204   base_precache_atoms (display);
3205
3206   /* Check for a local drag
3207    */
3208   window = gdk_window_lookup_for_display (display, xid);
3209   if (window &&
3210       gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
3211     {
3212       if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
3213         {
3214           *protocol = GDK_DRAG_PROTO_XDND;
3215           *version = 5;
3216           xdnd_precache_atoms (display);
3217           GDK_NOTE (DND, g_message ("Entering local Xdnd window %#x\n", xid));
3218           return xid;
3219         }
3220       else if (_gdk_x11_display_is_root_window (display, (Window) xid))
3221         {
3222           *protocol = GDK_DRAG_PROTO_ROOTWIN;
3223           GDK_NOTE (DND, g_message ("Entering root window\n"));
3224           return xid;
3225         }
3226     }
3227   else if ((retval = xdnd_check_dest (display, xid, version)))
3228     {
3229       *protocol = GDK_DRAG_PROTO_XDND;
3230       xdnd_precache_atoms (display);
3231       GDK_NOTE (DND, g_message ("Entering Xdnd window %#x\n", xid));
3232       return retval;
3233     }
3234   else if ((retval = motif_check_dest (display, xid)))
3235     {
3236       *protocol = GDK_DRAG_PROTO_MOTIF;
3237       GDK_NOTE (DND, g_message ("Entering motif window %#x\n", xid));
3238       return retval;
3239     }
3240   else
3241     {
3242       /* Check if this is a root window */
3243
3244       gboolean rootwin = FALSE;
3245       Atom type = None;
3246       int format;
3247       unsigned long nitems, after;
3248       unsigned char *data;
3249
3250       if (_gdk_x11_display_is_root_window (display, (Window) xid))
3251         rootwin = TRUE;
3252
3253       gdk_error_trap_push ();
3254       
3255       if (!rootwin)
3256         {
3257           if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid,
3258                                   gdk_x11_get_xatom_by_name_for_display (display, "ENLIGHTENMENT_DESKTOP"),
3259                                   0, 0, False, AnyPropertyType,
3260                                   &type, &format, &nitems, &after, &data) == Success &&
3261               type != None)
3262             {
3263               XFree (data);
3264               rootwin = TRUE;
3265             }
3266         }
3267
3268       /* Until I find out what window manager the next one is for,
3269        * I'm leaving it commented out. It's supported in the
3270        * xscreensaver sources, though.
3271        */
3272 #if 0
3273       if (!rootwin)
3274         {
3275           if (XGetWindowProperty (gdk_display, win,
3276                                   gdk_x11_get_xatom_by_name ("__SWM_VROOT"),
3277                                   0, 0, False, AnyPropertyType,
3278                                   &type, &format, &nitems, &data) &&
3279               type != None)
3280             {
3281               XFree (data);
3282               rootwin = TRUE;
3283             }
3284         }
3285 #endif      
3286
3287       gdk_error_trap_pop ();
3288
3289       if (rootwin)
3290         {
3291           GDK_NOTE (DND, g_message ("Entering root window\n"));
3292           *protocol = GDK_DRAG_PROTO_ROOTWIN;
3293           return xid;
3294         }
3295     }
3296
3297   *protocol = GDK_DRAG_PROTO_NONE;
3298
3299   return 0; /* a.k.a. None */
3300 }
3301
3302 /**
3303  * gdk_drag_get_protocol_for_display:
3304  * @display: the #GdkDisplay where the destination window resides
3305  * @xid: the windowing system id of the destination window.
3306  * @protocol: location where the supported DND protocol is returned.
3307  * @returns: the windowing system id of the window where the drop should happen. This 
3308  *     may be @xid or the id of a proxy window, or zero if @xid doesn't
3309  *     support Drag and Drop.
3310  *
3311  * Finds out the DND protocol supported by a window.
3312  *
3313  * Since: 2.2
3314  */ 
3315 GdkNativeWindow
3316 gdk_drag_get_protocol_for_display (GdkDisplay      *display,
3317                                    GdkNativeWindow  xid,
3318                                    GdkDragProtocol *protocol)
3319 {
3320   return _gdk_drag_get_protocol_for_display (display, xid, protocol, NULL);
3321 }
3322
3323 static GdkWindowCache *
3324 drag_context_find_window_cache (GdkDragContext  *context,
3325                                 GdkScreen       *screen)
3326 {
3327   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3328   GSList *tmp_list;
3329   GdkWindowCache *cache;
3330
3331   for (tmp_list = private->window_caches; tmp_list; tmp_list = tmp_list->next)
3332     {
3333       cache = tmp_list->data;
3334       if (cache->screen == screen)
3335         return cache;
3336     }
3337
3338   cache = gdk_window_cache_new (screen);
3339   private->window_caches = g_slist_prepend (private->window_caches, cache);
3340   
3341   return cache;
3342 }
3343
3344 /**
3345  * gdk_drag_find_window_for_screen:
3346  * @context: a #GdkDragContext
3347  * @drag_window: a window which may be at the pointer position, but
3348  * should be ignored, since it is put up by the drag source as an icon.
3349  * @screen: the screen where the destination window is sought. 
3350  * @x_root: the x position of the pointer in root coordinates.
3351  * @y_root: the y position of the pointer in root coordinates.
3352  * @dest_window: (out): location to store the destination window in.
3353  * @protocol: (out): location to store the DND protocol in.
3354  *
3355  * Finds the destination window and DND protocol to use at the
3356  * given pointer position.
3357  *
3358  * This function is called by the drag source to obtain the 
3359  * @dest_window and @protocol parameters for gdk_drag_motion().
3360  *
3361  * Since: 2.2
3362  **/
3363 void
3364 gdk_drag_find_window_for_screen (GdkDragContext  *context,
3365                                  GdkWindow       *drag_window,
3366                                  GdkScreen       *screen,
3367                                  gint             x_root,
3368                                  gint             y_root,
3369                                  GdkWindow      **dest_window,
3370                                  GdkDragProtocol *protocol)
3371 {
3372   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3373   GdkWindowCache *window_cache;
3374   GdkDisplay *display;
3375   Window dest;
3376
3377   g_return_if_fail (context != NULL);
3378
3379   display = GDK_WINDOW_DISPLAY (context->source_window);
3380
3381   window_cache = drag_context_find_window_cache (context, screen);
3382
3383   dest = get_client_window_at_coords (window_cache,
3384                                       drag_window && GDK_WINDOW_IS_X11 (drag_window) ? 
3385                                       GDK_DRAWABLE_XID (drag_window) : None,
3386                                       x_root, y_root);
3387
3388   if (private->dest_xid != dest)
3389     {
3390       Window recipient;
3391       private->dest_xid = dest;
3392
3393       /* Check if new destination accepts drags, and which protocol */
3394
3395       /* There is some ugliness here. We actually need to pass
3396        * _three_ pieces of information to drag_motion - dest_window,
3397        * protocol, and the XID of the unproxied window. The first
3398        * two are passed explicitely, the third implicitly through
3399        * protocol->dest_xid.
3400        */
3401       if ((recipient = _gdk_drag_get_protocol_for_display (display, dest, 
3402                                                            protocol, &private->version)))
3403         {
3404           *dest_window = gdk_window_lookup_for_display (display, recipient);
3405           if (*dest_window)
3406             g_object_ref (*dest_window);
3407           else
3408             *dest_window = gdk_window_foreign_new_for_display (display, recipient);
3409         }
3410       else
3411         *dest_window = NULL;
3412     }
3413   else
3414     {
3415       *dest_window = context->dest_window;
3416       if (*dest_window)
3417         g_object_ref (*dest_window);
3418       *protocol = context->protocol;
3419     }
3420 }
3421
3422 /**
3423  * gdk_drag_motion:
3424  * @context: a #GdkDragContext.
3425  * @dest_window: the new destination window, obtained by 
3426  *     gdk_drag_find_window().
3427  * @protocol: the DND protocol in use, obtained by gdk_drag_find_window().
3428  * @x_root: the x position of the pointer in root coordinates.
3429  * @y_root: the y position of the pointer in root coordinates.
3430  * @suggested_action: the suggested action.
3431  * @possible_actions: the possible actions.
3432  * @time_: the timestamp for this operation.
3433  * 
3434  * Updates the drag context when the pointer moves or the 
3435  * set of actions changes.
3436  *
3437  * This function is called by the drag source.
3438  * 
3439  * Return value: FIXME
3440  **/
3441 gboolean        
3442 gdk_drag_motion (GdkDragContext *context,
3443                  GdkWindow      *dest_window,
3444                  GdkDragProtocol protocol,
3445                  gint            x_root, 
3446                  gint            y_root,
3447                  GdkDragAction   suggested_action,
3448                  GdkDragAction   possible_actions,
3449                  guint32         time)
3450 {
3451   GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3452
3453   g_return_val_if_fail (context != NULL, FALSE);
3454   g_return_val_if_fail (dest_window == NULL || GDK_WINDOW_IS_X11 (dest_window), FALSE);
3455
3456   private->old_actions = context->actions;
3457   context->actions = possible_actions;
3458   
3459   if (private->old_actions != possible_actions)
3460     private->xdnd_actions_set = FALSE;
3461   
3462   if (protocol == GDK_DRAG_PROTO_XDND && private->version == 0)
3463     {
3464       /* This ugly hack is necessary since GTK+ doesn't know about
3465        * the XDND protocol version, and in particular doesn't know 
3466        * that gdk_drag_find_window_for_screen() has the side-effect 
3467        * of setting private->version, and therefore sometimes call
3468        * gdk_drag_motion() without a prior call to 
3469        * gdk_drag_find_window_for_screen(). This happens, e.g.
3470        * when GTK+ is proxying DND events to embedded windows.
3471        */ 
3472       if (dest_window)
3473         {
3474           GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
3475           
3476           xdnd_check_dest (display, 
3477                            GDK_DRAWABLE_XID (dest_window), 
3478                            &private->version);
3479         }
3480     }
3481
3482   /* When we have a Xdnd target, make sure our XdndActionList
3483    * matches the current actions;
3484    */
3485   if (protocol == GDK_DRAG_PROTO_XDND && !private->xdnd_actions_set)
3486     {
3487       if (dest_window)
3488         {
3489           if (gdk_window_get_window_type (dest_window) == GDK_WINDOW_FOREIGN)
3490             xdnd_set_actions (context);
3491           else if (context->dest_window == dest_window)
3492             {
3493               GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
3494               GdkDragContext *dest_context;
3495                     
3496               dest_context = gdk_drag_context_find (display, FALSE,
3497                                                     GDK_DRAWABLE_XID (context->source_window),
3498                                                     GDK_DRAWABLE_XID (dest_window));
3499
3500               if (dest_context)
3501                 {
3502                   dest_context->actions = context->actions;
3503                   PRIVATE_DATA (dest_context)->xdnd_have_actions = TRUE;
3504                 }
3505             }
3506         }
3507     }
3508
3509   if (context->dest_window != dest_window)
3510     {
3511       GdkEvent *temp_event;
3512
3513       /* Send a leave to the last destination */
3514       gdk_drag_do_leave (context, time);
3515       private->drag_status = GDK_DRAG_STATUS_DRAG;
3516
3517       /* Check if new destination accepts drags, and which protocol */
3518
3519       if (dest_window)
3520         {
3521           context->dest_window = dest_window;
3522           private->drop_xid = private->dest_xid;
3523           g_object_ref (context->dest_window);
3524           context->protocol = protocol;
3525
3526           switch (protocol)
3527             {
3528             case GDK_DRAG_PROTO_MOTIF:
3529               motif_send_enter (context, time);
3530               break;
3531
3532             case GDK_DRAG_PROTO_XDND:
3533               xdnd_send_enter (context);
3534               break;
3535
3536             case GDK_DRAG_PROTO_ROOTWIN:
3537             case GDK_DRAG_PROTO_NONE:
3538             default:
3539               break;
3540             }
3541           private->old_action = suggested_action;
3542           context->suggested_action = suggested_action;
3543           private->old_actions = possible_actions;
3544         }
3545       else
3546         {
3547           context->dest_window = NULL;
3548           private->drop_xid = None;
3549           context->action = 0;
3550         }
3551
3552       /* Push a status event, to let the client know that
3553        * the drag changed 
3554        */
3555       temp_event = gdk_event_new (GDK_DRAG_STATUS);
3556       temp_event->dnd.window = g_object_ref (context->source_window);
3557       /* We use this to signal a synthetic status. Perhaps
3558        * we should use an extra field...
3559        */
3560       temp_event->dnd.send_event = TRUE;
3561
3562       temp_event->dnd.context = g_object_ref (context);
3563       temp_event->dnd.time = time;
3564       gdk_event_set_device (temp_event, gdk_drag_context_get_device (context));
3565
3566       gdk_event_put (temp_event);
3567       gdk_event_free (temp_event);
3568     }
3569   else
3570     {
3571       private->old_action = context->suggested_action;
3572       context->suggested_action = suggested_action;
3573     }
3574
3575   /* Send a drag-motion event */
3576
3577   private->last_x = x_root;
3578   private->last_y = y_root;
3579       
3580   if (context->dest_window)
3581     {
3582       if (private->drag_status == GDK_DRAG_STATUS_DRAG)
3583         {
3584           switch (context->protocol)
3585             {
3586             case GDK_DRAG_PROTO_MOTIF:
3587               motif_send_motion (context, x_root, y_root, suggested_action, time);
3588               break;
3589               
3590             case GDK_DRAG_PROTO_XDND:
3591               xdnd_send_motion (context, x_root, y_root, suggested_action, time);
3592               break;
3593
3594             case GDK_DRAG_PROTO_ROOTWIN:
3595               {
3596                 GdkEvent *temp_event;
3597                 /* GTK+ traditionally has used application/x-rootwin-drop,
3598                  * but the XDND spec specifies x-rootwindow-drop.
3599                  */
3600                 GdkAtom target1 = gdk_atom_intern_static_string ("application/x-rootwindow-drop");
3601                 GdkAtom target2 = gdk_atom_intern_static_string ("application/x-rootwin-drop");
3602
3603                 if (g_list_find (context->targets,
3604                                  GDK_ATOM_TO_POINTER (target1)) ||
3605                     g_list_find (context->targets,
3606                                  GDK_ATOM_TO_POINTER (target2)))
3607                   context->action = context->suggested_action;
3608                 else
3609                   context->action = 0;
3610
3611                 temp_event = gdk_event_new (GDK_DRAG_STATUS);
3612                 temp_event->dnd.window = g_object_ref (context->source_window);
3613                 temp_event->dnd.send_event = FALSE;
3614                 temp_event->dnd.context = g_object_ref (context);
3615                 temp_event->dnd.time = time;
3616                 gdk_event_set_device (temp_event, gdk_drag_context_get_device (context));
3617
3618                 gdk_event_put (temp_event);
3619                 gdk_event_free (temp_event);
3620               }
3621               break;
3622             case GDK_DRAG_PROTO_NONE:
3623               g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
3624               break;
3625             default:
3626               break;
3627             }
3628         }
3629       else
3630         return TRUE;
3631     }
3632
3633   return FALSE;
3634 }
3635
3636 /**
3637  * gdk_drag_drop:
3638  * @context: a #GdkDragContext.
3639  * @time_: the timestamp for this operation.
3640  * 
3641  * Drops on the current destination.
3642  * 
3643  * This function is called by the drag source.
3644  **/
3645 void
3646 gdk_drag_drop (GdkDragContext *context,
3647                guint32         time)
3648 {
3649   g_return_if_fail (context != NULL);
3650
3651   if (context->dest_window)
3652     {
3653       switch (context->protocol)
3654         {
3655         case GDK_DRAG_PROTO_MOTIF:
3656           motif_send_leave (context, time);
3657           motif_send_drop (context, time);
3658           break;
3659           
3660         case GDK_DRAG_PROTO_XDND:
3661           xdnd_send_drop (context, time);
3662           break;
3663
3664         case GDK_DRAG_PROTO_ROOTWIN:
3665           g_warning ("Drops for GDK_DRAG_PROTO_ROOTWIN must be handled internally");
3666           break;
3667         case GDK_DRAG_PROTO_NONE:
3668           g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
3669           break;
3670         default:
3671           break;
3672         }
3673     }
3674 }
3675
3676 /**
3677  * gdk_drag_abort:
3678  * @context: a #GdkDragContext.
3679  * @time_: the timestamp for this operation.
3680  * 
3681  * Aborts a drag without dropping. 
3682  *
3683  * This function is called by the drag source.
3684  **/
3685 void
3686 gdk_drag_abort (GdkDragContext *context,
3687                 guint32         time)
3688 {
3689   g_return_if_fail (context != NULL);
3690
3691   gdk_drag_do_leave (context, time);
3692 }
3693
3694 /* Destination side */
3695
3696 /**
3697  * gdk_drag_status:
3698  * @context: a #GdkDragContext.
3699  * @action: the selected action which will be taken when a drop happens, 
3700  *    or 0 to indicate that a drop will not be accepted.
3701  * @time_: the timestamp for this operation.
3702  * 
3703  * Selects one of the actions offered by the drag source.
3704  *
3705  * This function is called by the drag destination in response to
3706  * gdk_drag_motion() called by the drag source.
3707  **/
3708 void             
3709 gdk_drag_status (GdkDragContext   *context,
3710                  GdkDragAction     action,
3711                  guint32           time)
3712 {
3713   GdkDragContextPrivateX11 *private;
3714   XEvent xev;
3715   GdkDisplay *display;
3716
3717   g_return_if_fail (context != NULL);
3718
3719   private = PRIVATE_DATA (context);
3720   display = GDK_DRAWABLE_DISPLAY (context->source_window);
3721   
3722   context->action = action;
3723
3724   if (context->protocol == GDK_DRAG_PROTO_MOTIF)
3725     {
3726       gboolean need_coords = FALSE;
3727       
3728       xev.xclient.type = ClientMessage;
3729       xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
3730                                                                         "_MOTIF_DRAG_AND_DROP_MESSAGE");
3731       xev.xclient.format = 8;
3732       xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3733
3734       if (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT)
3735         {
3736           MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED | 0x80;
3737         }
3738       else
3739         {
3740           if ((action != 0) != (private->old_action != 0))
3741             {
3742               if (action != 0)
3743                 {
3744                   MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_ENTER | 0x80;
3745                   need_coords = TRUE;
3746                 }
3747               else
3748                 MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_LEAVE | 0x80;
3749             }
3750           else
3751             {
3752               MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION | 0x80;
3753               need_coords = TRUE;
3754             }
3755         }
3756
3757       MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
3758
3759       switch (action)
3760         {
3761         case GDK_ACTION_MOVE:
3762           MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_MOVE;
3763           break;
3764         case GDK_ACTION_COPY:
3765           MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY;
3766           break;
3767         case GDK_ACTION_LINK:
3768           MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_LINK;
3769           break;
3770         default:
3771           MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP;
3772           break;
3773         }
3774
3775       if (action)
3776         MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmDROP_SITE_VALID << 4);
3777       else
3778         MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmNO_DROP_SITE << 4);
3779
3780       MOTIF_XCLIENT_LONG (&xev, 1) = time;
3781       
3782       if (need_coords)
3783         {
3784           MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
3785           MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
3786         }
3787       else
3788         MOTIF_XCLIENT_LONG (&xev, 2) = 0;
3789       
3790       MOTIF_XCLIENT_LONG (&xev, 3) = 0;
3791       MOTIF_XCLIENT_LONG (&xev, 4) = 0;
3792
3793       if (!_gdk_send_xevent (display,
3794                              GDK_DRAWABLE_XID (context->source_window),
3795                              FALSE, 0, &xev))
3796         GDK_NOTE (DND, 
3797                   g_message ("Send event to %lx failed",
3798                              GDK_DRAWABLE_XID (context->source_window)));
3799     }
3800   else if (context->protocol == GDK_DRAG_PROTO_XDND)
3801     {
3802       xev.xclient.type = ClientMessage;
3803       xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndStatus");
3804       xev.xclient.format = 32;
3805       xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3806
3807       xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
3808       xev.xclient.data.l[1] = (action != 0) ? (2 | 1) : 0;
3809       xev.xclient.data.l[2] = 0;
3810       xev.xclient.data.l[3] = 0;
3811       xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
3812       
3813       if (!xdnd_send_xevent (context, context->source_window,
3814                              FALSE, &xev))
3815         GDK_NOTE (DND, 
3816                   g_message ("Send event to %lx failed",
3817                              GDK_DRAWABLE_XID (context->source_window)));
3818     }
3819
3820   private->old_action = action;
3821 }
3822
3823 /**
3824  * gdk_drop_reply:
3825  * @context: a #GdkDragContext.
3826  * @ok: %TRUE if the drop is accepted.
3827  * @time_: the timestamp for this operation.
3828  * 
3829  * Accepts or rejects a drop. 
3830  *
3831  * This function is called by the drag destination in response
3832  * to a drop initiated by the drag source.
3833  **/
3834 void 
3835 gdk_drop_reply (GdkDragContext   *context,
3836                 gboolean          ok,
3837                 guint32           time)
3838 {
3839   GdkDragContextPrivateX11 *private;
3840
3841   g_return_if_fail (context != NULL);
3842
3843   private = PRIVATE_DATA (context);
3844   
3845   if (context->protocol == GDK_DRAG_PROTO_MOTIF)
3846     {
3847       GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
3848       XEvent xev;
3849
3850       xev.xclient.type = ClientMessage;
3851       xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
3852                                                                         "_MOTIF_DRAG_AND_DROP_MESSAGE");
3853       xev.xclient.format = 8;
3854
3855       MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START | 0x80;
3856       MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
3857       if (ok)
3858         MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY | 
3859                                        (XmDROP_SITE_VALID << 4) |
3860                                        (XmDROP_NOOP << 8) |
3861                                        (XmDROP << 12);
3862       else
3863         MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP | 
3864                                        (XmNO_DROP_SITE << 4) |
3865                                        (XmDROP_NOOP << 8) |
3866                                        (XmDROP_CANCEL << 12);
3867       MOTIF_XCLIENT_SHORT (&xev, 2) = private->last_x;
3868       MOTIF_XCLIENT_SHORT (&xev, 3) = private->last_y;
3869       MOTIF_XCLIENT_LONG (&xev, 2) = 0;
3870       MOTIF_XCLIENT_LONG (&xev, 3) = 0;
3871       MOTIF_XCLIENT_LONG (&xev, 4) = 0;
3872       
3873       _gdk_send_xevent (display,
3874                         GDK_DRAWABLE_XID (context->source_window),
3875                         FALSE, 0, &xev);
3876     }
3877 }
3878
3879 /**
3880  * gdk_drop_finish:
3881  * @context: a #GtkDragContext.
3882  * @success: %TRUE if the data was successfully received.
3883  * @time_: the timestamp for this operation.
3884  * 
3885  * Ends the drag operation after a drop.
3886  *
3887  * This function is called by the drag destination.
3888  **/
3889 void             
3890 gdk_drop_finish (GdkDragContext   *context,
3891                  gboolean          success,
3892                  guint32           time)
3893 {
3894   g_return_if_fail (context != NULL);
3895
3896   if (context->protocol == GDK_DRAG_PROTO_XDND)
3897     {
3898       GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
3899       XEvent xev;
3900
3901       xev.xclient.type = ClientMessage;
3902       xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndFinished");
3903       xev.xclient.format = 32;
3904       xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3905       
3906       xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
3907       if (success)
3908         {
3909           xev.xclient.data.l[1] = 1;
3910           xev.xclient.data.l[2] = xdnd_action_to_atom (display, 
3911                                                        context->action);
3912         }
3913       else
3914         {
3915           xev.xclient.data.l[1] = 0;
3916           xev.xclient.data.l[2] = None;
3917         }
3918       xev.xclient.data.l[3] = 0;
3919       xev.xclient.data.l[4] = 0;
3920
3921       if (!xdnd_send_xevent (context, context->source_window,
3922                              FALSE, &xev))
3923         GDK_NOTE (DND, 
3924                   g_message ("Send event to %lx failed",
3925                              GDK_DRAWABLE_XID (context->source_window)));
3926     }
3927 }
3928
3929
3930 /**
3931  * gdk_window_register_dnd:
3932  * @window: a #GdkWindow.
3933  *
3934  * Registers a window as a potential drop destination.
3935  */
3936 void            
3937 gdk_window_register_dnd (GdkWindow      *window)
3938 {
3939   static const gulong xdnd_version = 5;
3940   MotifDragReceiverInfo info;
3941   Atom motif_drag_receiver_info_atom;
3942   GdkDisplay *display = gdk_drawable_get_display (window);
3943
3944   g_return_if_fail (window != NULL);
3945
3946   if (gdk_window_get_window_type (window) == GDK_WINDOW_OFFSCREEN)
3947     return;
3948
3949   base_precache_atoms (display);
3950
3951   if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
3952     return;
3953   else
3954     g_object_set_data (G_OBJECT (window), "gdk-dnd-registered", GINT_TO_POINTER (TRUE));
3955   
3956   /* Set Motif drag receiver information property */
3957
3958   motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display,
3959                                                                          "_MOTIF_DRAG_RECEIVER_INFO");
3960   /* initialize to zero to avoid writing uninitialized data to socket */
3961   memset(&info, 0, sizeof(info));
3962   info.byte_order = local_byte_order;
3963   info.protocol_version = 0;
3964   info.protocol_style = XmDRAG_DYNAMIC;
3965   info.proxy_window = None;
3966   info.num_drop_sites = 0;
3967   info.total_size = sizeof(info);
3968
3969   XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_DRAWABLE_XID (window),
3970                    motif_drag_receiver_info_atom,
3971                    motif_drag_receiver_info_atom,
3972                    8, PropModeReplace,
3973                    (guchar *)&info,
3974                    sizeof (info));
3975
3976   /* Set XdndAware */
3977
3978   /* The property needs to be of type XA_ATOM, not XA_INTEGER. Blech */
3979   XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
3980                    GDK_DRAWABLE_XID (window),
3981                    gdk_x11_get_xatom_by_name_for_display (display, "XdndAware"),
3982                    XA_ATOM, 32, PropModeReplace,
3983                    (guchar *)&xdnd_version, 1);
3984 }
3985
3986 /**
3987  * gdk_drag_get_selection:
3988  * @context: a #GdkDragContext.
3989  * 
3990  * Returns the selection atom for the current source window.
3991  * 
3992  * Return value: the selection atom.
3993  **/
3994 GdkAtom
3995 gdk_drag_get_selection (GdkDragContext *context)
3996 {
3997   g_return_val_if_fail (context != NULL, GDK_NONE);
3998
3999   if (context->protocol == GDK_DRAG_PROTO_MOTIF)
4000     return gdk_x11_xatom_to_atom_for_display (GDK_DRAWABLE_DISPLAY (context->source_window),
4001                                               (PRIVATE_DATA (context))->motif_selection);
4002   else if (context->protocol == GDK_DRAG_PROTO_XDND)
4003     return gdk_atom_intern_static_string ("XdndSelection");
4004   else
4005     return GDK_NONE;
4006 }
4007
4008 /**
4009  * gdk_drag_drop_succeeded:
4010  * @context: a #GdkDragContext
4011  * 
4012  * Returns whether the dropped data has been successfully 
4013  * transferred. This function is intended to be used while 
4014  * handling a %GDK_DROP_FINISHED event, its return value is
4015  * meaningless at other times.
4016  * 
4017  * Return value: %TRUE if the drop was successful.
4018  *
4019  * Since: 2.6
4020  **/
4021 gboolean 
4022 gdk_drag_drop_succeeded (GdkDragContext *context)
4023 {
4024   GdkDragContextPrivateX11 *private;
4025
4026   g_return_val_if_fail (context != NULL, FALSE);
4027
4028   private = PRIVATE_DATA (context);
4029
4030   return !private->drop_failed;
4031 }