1
/* GDK - The GIMP Drawing Kit
2
* Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the
16
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
* Boston, MA 02111-1307, USA.
21
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22
* file for a list of people on the GTK+ Team. See the ChangeLog
23
* files for a list of changes. These files are distributed with
24
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30
#include <X11/Xutil.h>
31
#include <X11/Xatom.h>
32
#include <X11/extensions/shape.h>
33
#ifdef HAVE_XCOMPOSITE
34
#include <X11/extensions/Xcomposite.h>
39
#include "gdk.h" /* For gdk_flush() */
43
#include "gdkproperty.h"
44
#include "gdkprivate-x11.h"
45
#include "gdkinternals.h"
46
#include "gdkscreen-x11.h"
47
#include "gdkdisplay-x11.h"
50
typedef struct _GdkDragContextPrivateX11 GdkDragContextPrivateX11;
54
GDK_DRAG_STATUS_MOTION_WAIT,
55
GDK_DRAG_STATUS_ACTION_WAIT,
61
gint x, y, width, height;
63
gboolean shape_selected;
70
GHashTable *child_hash;
76
/* Structure that holds information about a drag in progress.
77
* this is used on both source and destination sides.
79
struct _GdkDragContextPrivateX11 {
80
GdkDragContext context;
85
guint16 last_x; /* Coordinates from last event */
87
GdkDragAction old_action; /* The last action we sent to the source */
88
GdkDragAction old_actions; /* The last actions we sent to the source */
89
GdkDragAction xdnd_actions; /* What is currently set in XdndActionList */
91
Window dest_xid; /* The last window we looked up */
92
Window drop_xid; /* The (non-proxied) window that is receiving drops */
93
guint xdnd_targets_set : 1; /* Whether we've already set XdndTypeList */
94
guint xdnd_actions_set : 1; /* Whether we've already set XdndActionList */
95
guint xdnd_have_actions : 1; /* Whether an XdndActionList was provided */
96
guint motif_targets_set : 1; /* Whether we've already set motif initiator info */
97
guint drag_status : 4; /* current status of drag */
99
guint drop_failed : 1; /* Whether the drop was unsuccessful */
100
guint version; /* Xdnd protocol version */
102
GSList *window_caches;
105
#define PRIVATE_DATA(context) ((GdkDragContextPrivateX11 *) GDK_DRAG_CONTEXT (context)->windowing_data)
107
/* Forward declarations */
109
static GdkWindowCache *gdk_window_cache_get (GdkScreen *screen);
110
static GdkWindowCache *gdk_window_cache_ref (GdkWindowCache *cache);
111
static void gdk_window_cache_unref (GdkWindowCache *cache);
113
static void motif_read_target_table (GdkDisplay *display);
115
static GdkFilterReturn motif_dnd_filter (GdkXEvent *xev,
119
static GdkFilterReturn xdnd_enter_filter (GdkXEvent *xev,
122
static GdkFilterReturn xdnd_leave_filter (GdkXEvent *xev,
125
static GdkFilterReturn xdnd_position_filter (GdkXEvent *xev,
128
static GdkFilterReturn xdnd_status_filter (GdkXEvent *xev,
131
static GdkFilterReturn xdnd_finished_filter (GdkXEvent *xev,
134
static GdkFilterReturn xdnd_drop_filter (GdkXEvent *xev,
138
static void xdnd_manage_source_filter (GdkDragContext *context,
140
gboolean add_filter);
142
static void gdk_drag_context_finalize (GObject *object);
144
static GList *contexts;
145
static GSList *window_caches;
147
static const struct {
148
const char *atom_name;
151
{ "XdndEnter", xdnd_enter_filter },
152
{ "XdndLeave", xdnd_leave_filter },
153
{ "XdndPosition", xdnd_position_filter },
154
{ "XdndStatus", xdnd_status_filter },
155
{ "XdndFinished", xdnd_finished_filter },
156
{ "XdndDrop", xdnd_drop_filter },
159
G_DEFINE_TYPE (GdkDragContext, gdk_drag_context, G_TYPE_OBJECT)
162
gdk_drag_context_init (GdkDragContext *dragcontext)
164
GdkDragContextPrivateX11 *private;
166
private = G_TYPE_INSTANCE_GET_PRIVATE (dragcontext,
167
GDK_TYPE_DRAG_CONTEXT,
168
GdkDragContextPrivateX11);
170
dragcontext->windowing_data = private;
172
contexts = g_list_prepend (contexts, dragcontext);
176
gdk_drag_context_class_init (GdkDragContextClass *klass)
178
GObjectClass *object_class = G_OBJECT_CLASS (klass);
180
object_class->finalize = gdk_drag_context_finalize;
182
g_type_class_add_private (object_class, sizeof (GdkDragContextPrivateX11));
186
gdk_drag_context_finalize (GObject *object)
188
GdkDragContext *context = GDK_DRAG_CONTEXT (object);
189
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
191
g_list_free (context->targets);
193
if (context->source_window)
195
if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
197
xdnd_manage_source_filter (context, context->source_window, FALSE);
199
g_object_unref (context->source_window);
202
if (context->dest_window)
203
g_object_unref (context->dest_window);
205
g_slist_free_full (private->window_caches, (GDestroyNotify)gdk_window_cache_unref);
206
private->window_caches = NULL;
208
contexts = g_list_remove (contexts, context);
210
G_OBJECT_CLASS (gdk_drag_context_parent_class)->finalize (object);
216
* gdk_drag_context_new:
218
* Creates a new #GdkDragContext.
220
* Return value: the newly created #GdkDragContext.
222
* Deprecated: 2.24: This function is not useful, you always
223
* obtain drag contexts by gdk_drag_begin() or similar.
226
gdk_drag_context_new (void)
228
return g_object_new (GDK_TYPE_DRAG_CONTEXT, NULL);
232
* gdk_drag_context_ref:
233
* @context: a #GdkDragContext.
235
* Deprecated function; use g_object_ref() instead.
237
* Deprecated: 2.2: Use g_object_ref() instead.
240
gdk_drag_context_ref (GdkDragContext *context)
242
g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
244
g_object_ref (context);
248
* gdk_drag_context_unref:
249
* @context: a #GdkDragContext.
251
* Deprecated function; use g_object_unref() instead.
253
* Deprecated: 2.2: Use g_object_unref() instead.
256
gdk_drag_context_unref (GdkDragContext *context)
258
g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
260
g_object_unref (context);
263
static GdkDragContext *
264
gdk_drag_context_find (GdkDisplay *display,
269
GList *tmp_list = contexts;
270
GdkDragContext *context;
271
GdkDragContextPrivateX11 *private;
272
Window context_dest_xid;
276
context = (GdkDragContext *)tmp_list->data;
277
private = PRIVATE_DATA (context);
279
if ((context->source_window && gdk_drawable_get_display (context->source_window) != display) ||
280
(context->dest_window && gdk_drawable_get_display (context->dest_window) != display))
283
context_dest_xid = context->dest_window ?
286
GDK_DRAWABLE_XID (context->dest_window)) :
289
if ((!context->is_source == !is_source) &&
290
((source_xid == None) || (context->source_window &&
291
(GDK_DRAWABLE_XID (context->source_window) == source_xid))) &&
292
((dest_xid == None) || (context_dest_xid == dest_xid)))
295
tmp_list = tmp_list->next;
302
precache_target_list (GdkDragContext *context)
304
if (context->targets)
306
GPtrArray *targets = g_ptr_array_new ();
310
for (tmp_list = context->targets; tmp_list; tmp_list = tmp_list->next)
311
g_ptr_array_add (targets, gdk_atom_name (GDK_POINTER_TO_ATOM (tmp_list->data)));
313
_gdk_x11_precache_atoms (GDK_WINDOW_DISPLAY (context->source_window),
314
(const gchar **)targets->pdata,
317
for (i =0; i < targets->len; i++)
318
g_free (targets->pdata[i]);
320
g_ptr_array_free (targets, TRUE);
324
/* Utility functions */
327
free_cache_child (GdkCacheChild *child,
331
gdk_region_destroy (child->shape);
333
if (child->shape_selected && display)
335
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
337
XShapeSelectInput (display_x11->xdisplay, child->xid, 0);
344
gdk_window_cache_add (GdkWindowCache *cache,
346
gint x, gint y, gint width, gint height,
349
GdkCacheChild *child = g_new (GdkCacheChild, 1);
354
child->width = width;
355
child->height = height;
356
child->mapped = mapped;
357
child->shape_selected = FALSE;
358
child->shape_valid = FALSE;
361
cache->children = g_list_prepend (cache->children, child);
362
g_hash_table_insert (cache->child_hash, GUINT_TO_POINTER (xid),
366
static GdkFilterReturn
367
gdk_window_cache_shape_filter (GdkXEvent *xev,
371
XEvent *xevent = (XEvent *)xev;
372
GdkWindowCache *cache = data;
374
GdkDisplayX11 *display = GDK_DISPLAY_X11 (gdk_screen_get_display (cache->screen));
376
if (display->have_shapes &&
377
xevent->type == display->shape_event_base + ShapeNotify)
379
XShapeEvent *xse = (XShapeEvent*)xevent;
382
node = g_hash_table_lookup (cache->child_hash,
383
GUINT_TO_POINTER (xse->window));
386
GdkCacheChild *child = node->data;
387
child->shape_valid = FALSE;
390
gdk_region_destroy (child->shape);
395
return GDK_FILTER_REMOVE;
398
return GDK_FILTER_CONTINUE;
401
static GdkFilterReturn
402
gdk_window_cache_filter (GdkXEvent *xev,
406
XEvent *xevent = (XEvent *)xev;
407
GdkWindowCache *cache = data;
409
switch (xevent->type)
411
case CirculateNotify:
413
case ConfigureNotify:
415
XConfigureEvent *xce = &xevent->xconfigure;
418
node = g_hash_table_lookup (cache->child_hash,
419
GUINT_TO_POINTER (xce->window));
422
GdkCacheChild *child = node->data;
425
child->width = xce->width;
426
child->height = xce->height;
427
if (xce->above == None && (node->next))
429
GList *last = g_list_last (cache->children);
430
cache->children = g_list_remove_link (cache->children, node);
437
GList *above_node = g_hash_table_lookup (cache->child_hash,
438
GUINT_TO_POINTER (xce->above));
439
if (above_node && node->next != above_node)
441
/* Put the window above (before in the list) above_node
443
cache->children = g_list_remove_link (cache->children, node);
444
node->prev = above_node->prev;
446
node->prev->next = node;
448
cache->children = node;
449
node->next = above_node;
450
above_node->prev = node;
458
XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
460
if (!g_hash_table_lookup (cache->child_hash,
461
GUINT_TO_POINTER (xcwe->window)))
462
gdk_window_cache_add (cache, xcwe->window,
463
xcwe->x, xcwe->y, xcwe->width, xcwe->height,
469
XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
472
node = g_hash_table_lookup (cache->child_hash,
473
GUINT_TO_POINTER (xdwe->window));
476
GdkCacheChild *child = node->data;
478
g_hash_table_remove (cache->child_hash,
479
GUINT_TO_POINTER (xdwe->window));
480
cache->children = g_list_remove_link (cache->children, node);
481
/* window is destroyed, no need to disable ShapeNotify */
482
free_cache_child (child, NULL);
483
g_list_free_1 (node);
489
XMapEvent *xme = &xevent->xmap;
492
node = g_hash_table_lookup (cache->child_hash,
493
GUINT_TO_POINTER (xme->window));
496
GdkCacheChild *child = node->data;
497
child->mapped = TRUE;
505
XMapEvent *xume = &xevent->xmap;
508
node = g_hash_table_lookup (cache->child_hash,
509
GUINT_TO_POINTER (xume->window));
512
GdkCacheChild *child = node->data;
513
child->mapped = FALSE;
518
return GDK_FILTER_CONTINUE;
520
return GDK_FILTER_REMOVE;
523
static GdkWindowCache *
524
gdk_window_cache_new (GdkScreen *screen)
526
XWindowAttributes xwa;
527
Display *xdisplay = GDK_SCREEN_XDISPLAY (screen);
528
GdkWindow *root_window = gdk_screen_get_root_window (screen);
529
GdkChildInfoX11 *children;
533
GdkWindowCache *result = g_new (GdkWindowCache, 1);
535
result->children = NULL;
536
result->child_hash = g_hash_table_new (g_direct_hash, NULL);
537
result->screen = screen;
538
result->ref_count = 1;
540
XGetWindowAttributes (xdisplay, GDK_WINDOW_XWINDOW (root_window), &xwa);
541
result->old_event_mask = xwa.your_event_mask;
543
if (G_UNLIKELY (!GDK_DISPLAY_X11 (GDK_SCREEN_X11 (screen)->display)->trusted_client))
545
GList *toplevel_windows, *list;
547
gint x, y, width, height;
549
toplevel_windows = gdk_screen_get_toplevel_windows (screen);
550
for (list = toplevel_windows; list; list = list->next) {
551
window = GDK_WINDOW (list->data);
552
gdk_window_get_geometry (window, &x, &y, &width, &height, NULL);
553
gdk_window_cache_add (result, GDK_WINDOW_XID (window),
555
gdk_window_is_visible (window));
557
g_list_free (toplevel_windows);
561
XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
562
result->old_event_mask | SubstructureNotifyMask);
563
gdk_window_add_filter (root_window, gdk_window_cache_filter, result);
564
gdk_window_add_filter (NULL, gdk_window_cache_shape_filter, result);
566
if (!_gdk_x11_get_window_child_info (gdk_screen_get_display (screen),
567
GDK_WINDOW_XWINDOW (root_window),
569
&children, &nchildren))
572
for (i = 0; i < nchildren ; i++)
574
gdk_window_cache_add (result, children[i].window,
575
children[i].x, children[i].y, children[i].width, children[i].height,
576
children[i].is_mapped);
581
#ifdef HAVE_XCOMPOSITE
583
* Add the composite overlay window to the cache, as this can be a reasonable
584
* Xdnd proxy as well.
585
* This is only done when the screen is composited in order to avoid mapping
586
* the COW. We assume that the CM is using the COW (which is true for pretty
587
* much any CM currently in use).
589
if (gdk_screen_is_composited (screen))
591
cow = XCompositeGetOverlayWindow (xdisplay, GDK_WINDOW_XWINDOW (root_window));
592
gdk_window_cache_add (result, cow, 0, 0, gdk_screen_get_width (screen), gdk_screen_get_height (screen), TRUE);
593
XCompositeReleaseOverlayWindow (xdisplay, GDK_WINDOW_XWINDOW (root_window));
601
gdk_window_cache_destroy (GdkWindowCache *cache)
603
GdkWindow *root_window = gdk_screen_get_root_window (cache->screen);
605
XSelectInput (GDK_WINDOW_XDISPLAY (root_window),
606
GDK_WINDOW_XWINDOW (root_window),
607
cache->old_event_mask);
608
gdk_window_remove_filter (root_window, gdk_window_cache_filter, cache);
609
gdk_window_remove_filter (NULL, gdk_window_cache_shape_filter, cache);
611
gdk_error_trap_push ();
613
g_list_foreach (cache->children, (GFunc)free_cache_child,
614
gdk_screen_get_display (cache->screen));
617
gdk_error_trap_pop ();
619
g_list_free (cache->children);
620
g_hash_table_destroy (cache->child_hash);
625
static GdkWindowCache *
626
gdk_window_cache_ref (GdkWindowCache *cache)
628
cache->ref_count += 1;
634
gdk_window_cache_unref (GdkWindowCache *cache)
636
g_assert (cache->ref_count > 0);
638
cache->ref_count -= 1;
640
if (cache->ref_count == 0)
642
window_caches = g_slist_remove (window_caches, cache);
643
gdk_window_cache_destroy (cache);
648
gdk_window_cache_get (GdkScreen *screen)
651
GdkWindowCache *cache;
653
for (list = window_caches; list; list = list->next)
656
if (cache->screen == screen)
657
return gdk_window_cache_ref (cache);
660
cache = gdk_window_cache_new (screen);
662
window_caches = g_slist_prepend (window_caches, cache);
669
is_pointer_within_shape (GdkDisplay *display,
670
GdkCacheChild *child,
674
if (!child->shape_selected)
676
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
678
XShapeSelectInput (display_x11->xdisplay, child->xid, ShapeNotifyMask);
679
child->shape_selected = TRUE;
681
if (!child->shape_valid)
683
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
684
GdkRegion *input_shape;
686
child->shape = _xwindow_get_shape (display_x11->xdisplay,
687
child->xid, ShapeBounding);
689
input_shape = _xwindow_get_shape (display_x11->xdisplay,
690
child->xid, ShapeInput);
691
if (child->shape && input_shape)
693
gdk_region_intersect (child->shape, input_shape);
694
gdk_region_destroy (input_shape);
696
else if (input_shape)
698
child->shape = input_shape;
702
child->shape_valid = TRUE;
705
return child->shape == NULL ||
706
gdk_region_point_in (child->shape, x_pos, y_pos);
710
get_client_window_at_coords_recurse (GdkDisplay *display,
712
gboolean is_toplevel,
716
GdkChildInfoX11 *children;
717
unsigned int nchildren;
719
gboolean found_child = FALSE;
720
GdkChildInfoX11 child = { 0, };
721
gboolean has_wm_state = FALSE;
723
if (!_gdk_x11_get_window_child_info (display, win, TRUE,
724
is_toplevel? &has_wm_state : NULL,
725
&children, &nchildren))
735
for (i = nchildren - 1; (i >= 0) && !found_child; i--)
737
GdkChildInfoX11 *cur_child = &children[i];
739
if ((cur_child->is_mapped) && (cur_child->window_class == InputOutput) &&
740
(x >= cur_child->x) && (x < cur_child->x + cur_child->width) &&
741
(y >= cur_child->y) && (y < cur_child->y + cur_child->height))
754
if (child.has_wm_state)
757
return get_client_window_at_coords_recurse (display, child.window, FALSE, x, y);
764
get_client_window_at_coords (GdkWindowCache *cache,
770
Window retval = None;
772
gdk_error_trap_push ();
774
tmp_list = cache->children;
776
while (tmp_list && !retval)
778
GdkCacheChild *child = tmp_list->data;
780
if ((child->xid != ignore) && (child->mapped))
782
if ((x_root >= child->x) && (x_root < child->x + child->width) &&
783
(y_root >= child->y) && (y_root < child->y + child->height))
785
GdkDisplay *display = gdk_screen_get_display (cache->screen);
787
if (!is_pointer_within_shape (display, child,
791
tmp_list = tmp_list->next;
795
retval = get_client_window_at_coords_recurse (display,
803
tmp_list = tmp_list->next;
806
gdk_error_trap_pop ();
811
return GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (cache->screen));
814
/*************************************************************
815
***************************** MOTIF *************************
816
*************************************************************/
818
/* values used in the message type for Motif DND */
831
/* Values used to specify type of protocol to use */
835
XmDRAG_PREFER_PREREGISTER,
837
XmDRAG_PREFER_DYNAMIC,
839
XmDRAG_PREFER_RECEIVER
842
/* Operation codes */
850
/* Drop site status */
852
XmNO_DROP_SITE = 0x01,
853
XmDROP_SITE_INVALID = 0x02,
854
XmDROP_SITE_VALID = 0x03
857
/* completion status */
865
/* Byte swapping routines. The motif specification leaves it
866
* up to us to save a few bytes in the client messages
868
static gchar local_byte_order = '\0';
870
#ifdef G_ENABLE_DEBUG
872
print_target_list (GList *targets)
876
gchar *name = gdk_atom_name (GDK_POINTER_TO_ATOM (targets->data));
877
g_message ("\t%s", name);
879
targets = targets->next;
882
#endif /* G_ENABLE_DEBUG */
885
init_byte_order (void)
887
guint32 myint = 0x01020304;
888
local_byte_order = (*(gchar *)&myint == 1) ? 'B' : 'l';
892
card16_to_host (guint16 x, gchar byte_order) {
893
if (byte_order == local_byte_order)
896
return (x << 8) | (x >> 8);
900
card32_to_host (guint32 x, gchar byte_order) {
901
if (byte_order == local_byte_order)
904
return (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
907
/* Motif packs together fields of varying length into the
908
* client message. We can't rely on accessing these
909
* through data.s[], data.l[], etc, because on some architectures
910
* (i.e., Alpha) these won't be valid for format == 8.
913
#define MOTIF_XCLIENT_BYTE(xevent,i) \
914
(xevent)->xclient.data.b[i]
915
#define MOTIF_XCLIENT_SHORT(xevent,i) \
916
((gint16 *)&((xevent)->xclient.data.b[0]))[i]
917
#define MOTIF_XCLIENT_LONG(xevent,i) \
918
((gint32 *)&((xevent)->xclient.data.b[0]))[i]
920
#define MOTIF_UNPACK_BYTE(xevent,i) MOTIF_XCLIENT_BYTE(xevent,i)
921
#define MOTIF_UNPACK_SHORT(xevent,i) \
922
card16_to_host (MOTIF_XCLIENT_SHORT(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
923
#define MOTIF_UNPACK_LONG(xevent,i) \
924
card32_to_host (MOTIF_XCLIENT_LONG(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
926
/***** Dest side ***********/
928
/* Property placed on source windows */
929
typedef struct _MotifDragInitiatorInfo {
931
guint8 protocol_version;
932
guint16 targets_index;
933
guint32 selection_atom;
934
} MotifDragInitiatorInfo;
936
/* Header for target table on the drag window */
937
typedef struct _MotifTargetTableHeader {
939
guchar protocol_version;
942
} MotifTargetTableHeader;
944
/* Property placed on target windows */
945
typedef struct _MotifDragReceiverInfo {
947
guint8 protocol_version;
948
guint8 protocol_style;
950
guint32 proxy_window;
951
guint16 num_drop_sites;
954
} MotifDragReceiverInfo;
956
/* Target table handling */
958
static GdkFilterReturn
959
motif_drag_window_filter (GdkXEvent *xevent,
963
XEvent *xev = (XEvent *)xevent;
964
GdkDisplay *display = GDK_WINDOW_DISPLAY (event->any.window);
965
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
967
switch (xev->xany.type)
970
display_x11->motif_drag_window = None;
971
display_x11->motif_drag_gdk_window = NULL;
974
if (display_x11->motif_target_lists &&
975
(xev->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS")))
976
motif_read_target_table (display);
979
return GDK_FILTER_REMOVE;
983
motif_lookup_drag_window (GdkDisplay *display,
984
Display *lookup_xdisplay)
986
Window retval = None;
987
gulong bytes_after, nitems;
992
XGetWindowProperty (lookup_xdisplay, RootWindow (lookup_xdisplay, 0),
993
gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW"),
995
XA_WINDOW, &type, &format, &nitems, &bytes_after,
998
if ((format == 32) && (nitems == 1) && (bytes_after == 0))
1000
retval = *(Window *)data;
1002
g_message ("Found drag window %#lx\n", GDK_DISPLAY_X11 (display)->motif_drag_window));
1011
/* Finds the window where global Motif drag information is stored.
1012
* If it doesn't exist and 'create' is TRUE, create one.
1015
motif_find_drag_window (GdkDisplay *display,
1018
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1020
if (!display_x11->motif_drag_window)
1022
Atom motif_drag_window_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW");
1023
display_x11->motif_drag_window = motif_lookup_drag_window (display, display_x11->xdisplay);
1025
if (!display_x11->motif_drag_window && create)
1027
/* Create a persistant window. (Copied from LessTif) */
1029
Display *persistant_xdisplay;
1030
XSetWindowAttributes attr;
1031
persistant_xdisplay = XOpenDisplay (gdk_display_get_name (display));
1032
XSetCloseDownMode (persistant_xdisplay, RetainPermanent);
1034
XGrabServer (persistant_xdisplay);
1036
display_x11->motif_drag_window = motif_lookup_drag_window (display, persistant_xdisplay);
1038
if (!display_x11->motif_drag_window)
1040
attr.override_redirect = True;
1041
attr.event_mask = PropertyChangeMask;
1043
display_x11->motif_drag_window =
1044
XCreateWindow (persistant_xdisplay,
1045
RootWindow (persistant_xdisplay, 0),
1046
-100, -100, 10, 10, 0, 0,
1047
InputOnly, (Visual *)CopyFromParent,
1048
(CWOverrideRedirect | CWEventMask), &attr);
1051
g_message ("Created drag window %#lx\n", display_x11->motif_drag_window));
1053
XChangeProperty (persistant_xdisplay,
1054
RootWindow (persistant_xdisplay, 0),
1055
motif_drag_window_atom, XA_WINDOW,
1056
32, PropModeReplace,
1057
(guchar *)&motif_drag_window_atom, 1);
1060
XUngrabServer (persistant_xdisplay);
1061
XCloseDisplay (persistant_xdisplay);
1064
/* There is a miniscule race condition here if the drag window
1065
* gets destroyed exactly now.
1067
if (display_x11->motif_drag_window)
1069
display_x11->motif_drag_gdk_window =
1070
gdk_window_foreign_new_for_display (display, display_x11->motif_drag_window);
1071
gdk_window_add_filter (display_x11->motif_drag_gdk_window,
1072
motif_drag_window_filter,
1077
return display_x11->motif_drag_window;
1081
motif_read_target_table (GdkDisplay *display)
1083
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1084
gulong bytes_after, nitems;
1089
Atom motif_drag_targets_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS");
1091
if (display_x11->motif_target_lists)
1093
for (i=0; i<display_x11->motif_n_target_lists; i++)
1094
g_list_free (display_x11->motif_target_lists[i]);
1096
g_free (display_x11->motif_target_lists);
1097
display_x11->motif_target_lists = NULL;
1098
display_x11->motif_n_target_lists = 0;
1101
if (motif_find_drag_window (display, FALSE))
1104
MotifTargetTableHeader *header = NULL;
1105
guchar *target_bytes = NULL;
1107
gboolean success = FALSE;
1109
gdk_error_trap_push ();
1110
XGetWindowProperty (display_x11->xdisplay,
1111
display_x11->motif_drag_window,
1112
motif_drag_targets_atom,
1113
0, (sizeof(MotifTargetTableHeader)+3)/4, FALSE,
1114
motif_drag_targets_atom,
1115
&type, &format, &nitems, &bytes_after,
1118
if (gdk_error_trap_pop () || (format != 8) || (nitems < sizeof (MotifTargetTableHeader)))
1121
header = (MotifTargetTableHeader *)data;
1123
header->n_lists = card16_to_host (header->n_lists, header->byte_order);
1124
header->total_size = card32_to_host (header->total_size, header->byte_order);
1126
gdk_error_trap_push ();
1127
XGetWindowProperty (display_x11->xdisplay,
1128
display_x11->motif_drag_window,
1129
motif_drag_targets_atom,
1130
(sizeof(MotifTargetTableHeader)+3)/4,
1131
(header->total_size + 3)/4 - (sizeof(MotifTargetTableHeader) + 3)/4,
1133
motif_drag_targets_atom, &type, &format, &nitems,
1134
&bytes_after, &target_bytes);
1136
if (gdk_error_trap_pop () || (format != 8) || (bytes_after != 0) ||
1137
(nitems != header->total_size - sizeof(MotifTargetTableHeader)))
1140
display_x11->motif_n_target_lists = header->n_lists;
1141
display_x11->motif_target_lists = g_new0 (GList *, display_x11->motif_n_target_lists);
1144
for (i=0; i<header->n_lists; i++)
1149
if (p + sizeof(guint16) - target_bytes > nitems)
1152
n_targets = card16_to_host (*(gushort *)p, header->byte_order);
1154
/* We need to make a copy of the targets, since it may
1157
targets = g_new (guint32, n_targets);
1158
memcpy (targets, p + sizeof(guint16), sizeof(guint32) * n_targets);
1160
p += sizeof(guint16) + n_targets * sizeof(guint32);
1161
if (p - target_bytes > nitems)
1164
for (j=0; j<n_targets; j++)
1165
display_x11->motif_target_lists[i] =
1166
g_list_prepend (display_x11->motif_target_lists[i],
1167
GUINT_TO_POINTER (card32_to_host (targets[j],
1168
header->byte_order)));
1170
display_x11->motif_target_lists[i] = g_list_reverse (display_x11->motif_target_lists[i]);
1180
XFree (target_bytes);
1184
if (display_x11->motif_target_lists)
1186
g_free (display_x11->motif_target_lists);
1187
display_x11->motif_target_lists = NULL;
1188
display_x11->motif_n_target_lists = 0;
1190
g_warning ("Error reading Motif target table\n");
1196
targets_sort_func (gconstpointer a, gconstpointer b)
1198
return (GPOINTER_TO_UINT (a) < GPOINTER_TO_UINT (b)) ?
1199
-1 : ((GPOINTER_TO_UINT (a) > GPOINTER_TO_UINT (b)) ? 1 : 0);
1202
/* Check if given (sorted) list is in the targets table */
1204
motif_target_table_check (GdkDisplay *display,
1207
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1208
GList *tmp_list1, *tmp_list2;
1211
for (i=0; i<display_x11->motif_n_target_lists; i++)
1213
tmp_list1 = display_x11->motif_target_lists[i];
1216
while (tmp_list1 && tmp_list2)
1218
if (tmp_list1->data != tmp_list2->data)
1221
tmp_list1 = tmp_list1->next;
1222
tmp_list2 = tmp_list2->next;
1224
if (!tmp_list1 && !tmp_list2) /* Found it */
1232
motif_add_to_target_table (GdkDisplay *display,
1233
GList *targets) /* targets is list of GdkAtom */
1235
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1236
GList *sorted = NULL;
1241
/* make a sorted copy of the list */
1245
Atom xatom = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (targets->data));
1246
sorted = g_list_insert_sorted (sorted, GUINT_TO_POINTER (xatom), targets_sort_func);
1247
targets = targets->next;
1250
/* First check if it is there already */
1252
if (display_x11->motif_target_lists)
1253
index = motif_target_table_check (display, sorted);
1255
/* We need to grab the server while doing this, to ensure
1261
/* We need to make sure that it exists _before_ we grab the
1262
* server, since we can't open a new connection after we
1265
motif_find_drag_window (display, TRUE);
1267
gdk_x11_display_grab (display);
1268
motif_read_target_table (display);
1270
/* Check again, in case it was added in the meantime */
1272
if (display_x11->motif_target_lists)
1273
index = motif_target_table_check (display, sorted);
1277
guint32 total_size = 0;
1281
MotifTargetTableHeader *header;
1283
if (!display_x11->motif_target_lists)
1285
display_x11->motif_target_lists = g_new (GList *, 1);
1286
display_x11->motif_n_target_lists = 1;
1290
display_x11->motif_n_target_lists++;
1291
display_x11->motif_target_lists = g_realloc (display_x11->motif_target_lists,
1292
sizeof(GList *) * display_x11->motif_n_target_lists);
1294
display_x11->motif_target_lists[display_x11->motif_n_target_lists - 1] = sorted;
1296
index = display_x11->motif_n_target_lists - 1;
1298
total_size = sizeof (MotifTargetTableHeader);
1299
for (i = 0; i < display_x11->motif_n_target_lists ; i++)
1300
total_size += sizeof(guint16) + sizeof(guint32) * g_list_length (display_x11->motif_target_lists[i]);
1302
data = g_malloc (total_size);
1304
header = (MotifTargetTableHeader *)data;
1305
p = data + sizeof(MotifTargetTableHeader);
1307
header->byte_order = local_byte_order;
1308
header->protocol_version = 0;
1309
header->n_lists = display_x11->motif_n_target_lists;
1310
header->total_size = total_size;
1312
for (i = 0; i < display_x11->motif_n_target_lists ; i++)
1314
guint16 n_targets = g_list_length (display_x11->motif_target_lists[i]);
1315
guint32 *targets = g_new (guint32, n_targets);
1316
guint32 *p32 = targets;
1318
tmp_list = display_x11->motif_target_lists[i];
1321
*p32 = GPOINTER_TO_UINT (tmp_list->data);
1323
tmp_list = tmp_list->next;
1328
p += sizeof(guint16);
1330
memcpy (p, targets, n_targets * sizeof(guint32));
1333
p += sizeof(guint32) * n_targets;
1337
XChangeProperty (display_x11->xdisplay,
1338
display_x11->motif_drag_window,
1339
gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
1340
gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
1344
gdk_x11_display_ungrab (display);
1347
g_list_free (sorted);
1351
/* Translate flags */
1354
motif_dnd_translate_flags (GdkDragContext *context, guint16 flags)
1356
guint recommended_op = flags & 0x000f;
1357
guint possible_ops = (flags & 0x0f0) >> 4;
1359
switch (recommended_op)
1362
context->suggested_action = GDK_ACTION_MOVE;
1365
context->suggested_action = GDK_ACTION_COPY;
1368
context->suggested_action = GDK_ACTION_LINK;
1371
context->suggested_action = GDK_ACTION_COPY;
1375
context->actions = 0;
1376
if (possible_ops & XmDROP_MOVE)
1377
context->actions |= GDK_ACTION_MOVE;
1378
if (possible_ops & XmDROP_COPY)
1379
context->actions |= GDK_ACTION_COPY;
1380
if (possible_ops & XmDROP_LINK)
1381
context->actions |= GDK_ACTION_LINK;
1385
motif_dnd_get_flags (GdkDragContext *context)
1389
switch (context->suggested_action)
1391
case GDK_ACTION_MOVE:
1392
flags = XmDROP_MOVE;
1394
case GDK_ACTION_COPY:
1395
flags = XmDROP_COPY;
1397
case GDK_ACTION_LINK:
1398
flags = XmDROP_LINK;
1401
flags = XmDROP_NOOP;
1405
if (context->actions & GDK_ACTION_MOVE)
1406
flags |= XmDROP_MOVE << 8;
1407
if (context->actions & GDK_ACTION_COPY)
1408
flags |= XmDROP_COPY << 8;
1409
if (context->actions & GDK_ACTION_LINK)
1410
flags |= XmDROP_LINK << 8;
1418
motif_set_targets (GdkDragContext *context)
1420
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1421
MotifDragInitiatorInfo info;
1423
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1425
info.byte_order = local_byte_order;
1426
info.protocol_version = 0;
1428
info.targets_index = motif_add_to_target_table (display, context->targets);
1433
g_snprintf(buf, 20, "_GDK_SELECTION_%d", i);
1435
private->motif_selection = gdk_x11_get_xatom_by_name_for_display (display, buf);
1436
if (!XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), private->motif_selection))
1440
info.selection_atom = private->motif_selection;
1442
XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
1443
GDK_DRAWABLE_XID (context->source_window),
1444
private->motif_selection,
1445
gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
1447
(guchar *)&info, sizeof (info));
1449
private->motif_targets_set = 1;
1453
motif_check_dest (GdkDisplay *display,
1456
gboolean retval = FALSE;
1458
MotifDragReceiverInfo *info;
1461
unsigned long nitems, after;
1462
Atom motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO");
1464
gdk_error_trap_push ();
1465
XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win,
1466
motif_drag_receiver_info_atom,
1467
0, (sizeof(*info)+3)/4, False, AnyPropertyType,
1468
&type, &format, &nitems, &after,
1471
if (gdk_error_trap_pop() == 0)
1475
info = (MotifDragReceiverInfo *)data;
1477
if ((format == 8) && (nitems == sizeof(*info)))
1479
if ((info->protocol_version == 0) &&
1480
((info->protocol_style == XmDRAG_PREFER_PREREGISTER) ||
1481
(info->protocol_style == XmDRAG_PREFER_DYNAMIC) ||
1482
(info->protocol_style == XmDRAG_DYNAMIC)))
1488
g_warning ("Invalid Motif drag receiver property on window %ld\n", win));
1495
return retval ? win : None;
1499
motif_send_enter (GdkDragContext *context,
1502
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1503
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1506
if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
1507
return; /* Motif Dnd requires getting properties on the root window */
1509
xev.xclient.type = ClientMessage;
1510
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1511
xev.xclient.format = 8;
1512
xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1514
MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_ENTER;
1515
MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1516
MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
1517
MOTIF_XCLIENT_LONG (&xev, 1) = time;
1518
MOTIF_XCLIENT_LONG (&xev, 2) = GDK_DRAWABLE_XID (context->source_window);
1520
if (!private->motif_targets_set)
1521
motif_set_targets (context);
1523
MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection;
1524
MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1526
if (!_gdk_send_xevent (display,
1527
GDK_DRAWABLE_XID (context->dest_window),
1530
g_message ("Send event to %lx failed",
1531
GDK_DRAWABLE_XID (context->dest_window)));
1535
motif_send_leave (GdkDragContext *context,
1538
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1541
xev.xclient.type = ClientMessage;
1542
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1543
xev.xclient.format = 8;
1544
xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1546
MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_LEAVE;
1547
MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1548
MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
1549
MOTIF_XCLIENT_LONG (&xev, 1) = time;
1550
MOTIF_XCLIENT_LONG (&xev, 2) = 0;
1551
MOTIF_XCLIENT_LONG (&xev, 3) = 0;
1552
MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1554
if (!_gdk_send_xevent (display,
1555
GDK_DRAWABLE_XID (context->dest_window),
1558
g_message ("Send event to %lx failed",
1559
GDK_DRAWABLE_XID (context->dest_window)));
1563
motif_send_motion (GdkDragContext *context,
1566
GdkDragAction action,
1569
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1570
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1574
xev.xclient.type = ClientMessage;
1575
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1576
xev.xclient.format = 8;
1577
xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1579
MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1580
MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
1581
MOTIF_XCLIENT_LONG (&xev, 1) = time;
1582
MOTIF_XCLIENT_LONG (&xev, 3) = 0;
1583
MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1585
if ((context->suggested_action != private->old_action) ||
1586
(context->actions != private->old_actions))
1588
MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
1590
/* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
1595
MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION;
1597
MOTIF_XCLIENT_SHORT (&xev, 4) = x_root;
1598
MOTIF_XCLIENT_SHORT (&xev, 5) = y_root;
1600
private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
1604
if (!_gdk_send_xevent (display,
1605
GDK_DRAWABLE_XID (context->dest_window),
1608
g_message ("Send event to %lx failed",
1609
GDK_DRAWABLE_XID (context->dest_window)));
1615
motif_send_drop (GdkDragContext *context, guint32 time)
1617
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1618
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1621
xev.xclient.type = ClientMessage;
1622
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1623
xev.xclient.format = 8;
1624
xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1626
MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START;
1627
MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1628
MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
1629
MOTIF_XCLIENT_LONG (&xev, 1) = time;
1631
MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
1632
MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
1634
MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection;
1635
MOTIF_XCLIENT_LONG (&xev, 4) = GDK_DRAWABLE_XID (context->source_window);
1637
if (!_gdk_send_xevent (display,
1638
GDK_DRAWABLE_XID (context->dest_window),
1641
g_message ("Send event to %lx failed",
1642
GDK_DRAWABLE_XID (context->dest_window)));
1648
motif_read_initiator_info (GdkDisplay *display,
1649
Window source_window,
1660
MotifDragInitiatorInfo *initiator_info;
1662
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1664
gdk_error_trap_push ();
1665
XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), source_window, atom,
1666
0, sizeof(*initiator_info), FALSE,
1667
gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
1668
&type, &format, &nitems, &bytes_after,
1671
if (gdk_error_trap_pop () || (format != 8) || (nitems != sizeof (MotifDragInitiatorInfo)) || (bytes_after != 0))
1673
g_warning ("Error reading initiator info\n");
1677
initiator_info = (MotifDragInitiatorInfo *)data;
1679
motif_read_target_table (display);
1681
initiator_info->targets_index =
1682
card16_to_host (initiator_info->targets_index, initiator_info->byte_order);
1683
initiator_info->selection_atom =
1684
card32_to_host (initiator_info->selection_atom, initiator_info->byte_order);
1686
if (initiator_info->targets_index >= display_x11->motif_n_target_lists)
1688
g_warning ("Invalid target index in TOP_LEVEL_ENTER MESSAGE");
1689
XFree (initiator_info);
1693
tmp_list = g_list_last (display_x11->motif_target_lists[initiator_info->targets_index]);
1698
GdkAtom atom = gdk_x11_xatom_to_atom_for_display (display, GPOINTER_TO_UINT (tmp_list->data));
1699
*targets = g_list_prepend (*targets, GDK_ATOM_TO_POINTER (atom));
1700
tmp_list = tmp_list->prev;
1703
#ifdef G_ENABLE_DEBUG
1704
if (_gdk_debug_flags & GDK_DEBUG_DND)
1705
print_target_list (*targets);
1706
#endif /* G_ENABLE_DEBUG */
1708
*selection = initiator_info->selection_atom;
1710
XFree (initiator_info);
1715
static GdkDragContext *
1716
motif_drag_context_new (GdkWindow *dest_window,
1718
guint32 source_window,
1721
GdkDragContext *new_context;
1722
GdkDragContextPrivateX11 *private;
1723
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (dest_window);
1724
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1726
/* FIXME, current_dest_drag really shouldn't be NULL'd
1727
* if we error below.
1729
if (display_x11->current_dest_drag != NULL)
1731
if (timestamp >= display_x11->current_dest_drag->start_time)
1733
g_object_unref (display_x11->current_dest_drag);
1734
display_x11->current_dest_drag = NULL;
1740
new_context = gdk_drag_context_new ();
1741
private = PRIVATE_DATA (new_context);
1743
new_context->protocol = GDK_DRAG_PROTO_MOTIF;
1744
new_context->is_source = FALSE;
1746
new_context->source_window = gdk_window_lookup_for_display (display, source_window);
1747
if (new_context->source_window)
1748
g_object_ref (new_context->source_window);
1751
new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
1752
if (!new_context->source_window)
1754
g_object_unref (new_context);
1759
new_context->dest_window = dest_window;
1760
g_object_ref (dest_window);
1761
new_context->start_time = timestamp;
1763
if (!motif_read_initiator_info (GDK_WINDOW_DISPLAY (dest_window),
1766
&new_context->targets,
1767
&private->motif_selection))
1769
g_object_unref (new_context);
1777
* The MOTIF drag protocol has no real provisions for distinguishing
1778
* multiple simultaneous drops. If the sources grab the pointer
1779
* when doing drags, that shouldn't happen, in any case. If it
1780
* does, we can't do much except hope for the best.
1783
static GdkFilterReturn
1784
motif_top_level_enter (GdkEvent *event,
1787
guint32 source_window,
1790
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1791
GdkDragContext *new_context;
1793
GDK_NOTE(DND, g_message ("Motif DND top level enter: flags: %#4x time: %d source_widow: %#4x atom: %d",
1794
flags, timestamp, source_window, atom));
1796
new_context = motif_drag_context_new (event->any.window, timestamp, source_window, atom);
1798
return GDK_FILTER_REMOVE;
1800
event->dnd.type = GDK_DRAG_ENTER;
1801
event->dnd.context = new_context;
1802
g_object_ref (new_context);
1804
display_x11->current_dest_drag = new_context;
1806
return GDK_FILTER_TRANSLATE;
1809
static GdkFilterReturn
1810
motif_top_level_leave (GdkEvent *event,
1814
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1816
GDK_NOTE(DND, g_message ("Motif DND top level leave: flags: %#4x time: %d",
1819
if ((display_x11->current_dest_drag != NULL) &&
1820
(display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1821
(timestamp >= display_x11->current_dest_drag->start_time))
1823
event->dnd.type = GDK_DRAG_LEAVE;
1824
/* Pass ownership of context to the event */
1825
event->dnd.context = display_x11->current_dest_drag;
1827
display_x11->current_dest_drag = NULL;
1829
return GDK_FILTER_TRANSLATE;
1832
return GDK_FILTER_REMOVE;
1835
static GdkFilterReturn
1836
motif_motion (GdkEvent *event,
1842
GdkDragContextPrivateX11 *private;
1843
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1845
GDK_NOTE(DND, g_message ("Motif DND motion: flags: %#4x time: %d (%d, %d)",
1846
flags, timestamp, x_root, y_root));
1848
if ((display_x11->current_dest_drag != NULL) &&
1849
(display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1850
(timestamp >= display_x11->current_dest_drag->start_time))
1852
private = PRIVATE_DATA (display_x11->current_dest_drag);
1854
event->dnd.type = GDK_DRAG_MOTION;
1855
event->dnd.context = display_x11->current_dest_drag;
1856
g_object_ref (display_x11->current_dest_drag);
1858
event->dnd.time = timestamp;
1860
motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
1862
event->dnd.x_root = x_root;
1863
event->dnd.y_root = y_root;
1865
private->last_x = x_root;
1866
private->last_y = y_root;
1868
private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
1870
return GDK_FILTER_TRANSLATE;
1873
return GDK_FILTER_REMOVE;
1876
static GdkFilterReturn
1877
motif_operation_changed (GdkEvent *event,
1881
GdkDragContextPrivateX11 *private;
1882
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1883
GDK_NOTE(DND, g_message ("Motif DND operation changed: flags: %#4x time: %d",
1886
if ((display_x11->current_dest_drag != NULL) &&
1887
(display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1888
(timestamp >= display_x11->current_dest_drag->start_time))
1890
event->dnd.type = GDK_DRAG_MOTION;
1891
event->dnd.send_event = FALSE;
1892
event->dnd.context = display_x11->current_dest_drag;
1893
g_object_ref (display_x11->current_dest_drag);
1895
event->dnd.time = timestamp;
1896
private = PRIVATE_DATA (display_x11->current_dest_drag);
1898
motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
1900
event->dnd.x_root = private->last_x;
1901
event->dnd.y_root = private->last_y;
1903
private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
1905
return GDK_FILTER_TRANSLATE;
1908
return GDK_FILTER_REMOVE;
1911
static GdkFilterReturn
1912
motif_drop_start (GdkEvent *event,
1915
guint32 source_window,
1920
GdkDragContext *new_context;
1921
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1923
GDK_NOTE(DND, g_message ("Motif DND drop start: flags: %#4x time: %d (%d, %d) source_widow: %#4x atom: %d",
1924
flags, timestamp, x_root, y_root, source_window, atom));
1926
new_context = motif_drag_context_new (event->any.window, timestamp, source_window, atom);
1928
return GDK_FILTER_REMOVE;
1930
motif_dnd_translate_flags (new_context, flags);
1932
event->dnd.type = GDK_DROP_START;
1933
event->dnd.context = new_context;
1934
event->dnd.time = timestamp;
1935
event->dnd.x_root = x_root;
1936
event->dnd.y_root = y_root;
1938
gdk_x11_window_set_user_time (event->any.window, timestamp);
1940
g_object_ref (new_context);
1941
display_x11->current_dest_drag = new_context;
1943
return GDK_FILTER_TRANSLATE;
1946
static GdkFilterReturn
1947
motif_drag_status (GdkEvent *event,
1951
GdkDragContext *context;
1952
GdkDisplay *display;
1955
g_message ("Motif status message: flags %x", flags));
1957
display = gdk_drawable_get_display (event->any.window);
1959
return GDK_FILTER_REMOVE;
1961
context = gdk_drag_context_find (display, TRUE, GDK_DRAWABLE_XID (event->any.window), None);
1965
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1966
if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
1967
(private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
1968
private->drag_status = GDK_DRAG_STATUS_DRAG;
1970
event->dnd.type = GDK_DRAG_STATUS;
1971
event->dnd.send_event = FALSE;
1972
event->dnd.context = context;
1973
g_object_ref (context);
1975
event->dnd.time = timestamp;
1977
if ((flags & 0x00f0) >> 4 == XmDROP_SITE_VALID)
1979
switch (flags & 0x000f)
1982
context->action = 0;
1985
context->action = GDK_ACTION_MOVE;
1988
context->action = GDK_ACTION_COPY;
1991
context->action = GDK_ACTION_LINK;
1996
context->action = 0;
1998
return GDK_FILTER_TRANSLATE;
2000
return GDK_FILTER_REMOVE;
2003
static GdkFilterReturn
2004
motif_dnd_filter (GdkXEvent *xev,
2008
XEvent *xevent = (XEvent *)xev;
2013
guint32 source_window;
2015
gint16 x_root, y_root;
2018
if (!event->any.window ||
2019
gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2020
return GDK_FILTER_CONTINUE; /* Not for us */
2022
/* First read some fields common to all Motif DND messages */
2024
reason = MOTIF_UNPACK_BYTE (xevent, 0);
2025
flags = MOTIF_UNPACK_SHORT (xevent, 1);
2026
timestamp = MOTIF_UNPACK_LONG (xevent, 1);
2028
is_reply = ((reason & 0x80) != 0);
2030
switch (reason & 0x7f)
2032
case XmTOP_LEVEL_ENTER:
2033
source_window = MOTIF_UNPACK_LONG (xevent, 2);
2034
atom = MOTIF_UNPACK_LONG (xevent, 3);
2035
return motif_top_level_enter (event, flags, timestamp, source_window, atom);
2036
case XmTOP_LEVEL_LEAVE:
2037
return motif_top_level_leave (event, flags, timestamp);
2040
x_root = MOTIF_UNPACK_SHORT (xevent, 4);
2041
y_root = MOTIF_UNPACK_SHORT (xevent, 5);
2044
return motif_motion (event, flags, timestamp, x_root, y_root);
2046
return motif_drag_status (event, flags, timestamp);
2048
case XmDROP_SITE_ENTER:
2049
return motif_drag_status (event, flags, timestamp);
2051
case XmDROP_SITE_LEAVE:
2052
return motif_drag_status (event,
2053
XmNO_DROP_SITE << 8 | XmDROP_NOOP,
2056
x_root = MOTIF_UNPACK_SHORT (xevent, 4);
2057
y_root = MOTIF_UNPACK_SHORT (xevent, 5);
2058
atom = MOTIF_UNPACK_LONG (xevent, 3);
2059
source_window = MOTIF_UNPACK_LONG (xevent, 4);
2062
return motif_drop_start (event, flags, timestamp, source_window, atom, x_root, y_root);
2065
case XmOPERATION_CHANGED:
2067
return motif_operation_changed (event, flags, timestamp);
2069
return motif_drag_status (event, flags, timestamp);
2072
/* To the best of my knowledge, these next two messages are
2073
* not part of the protocol, though they are defined in
2077
case XmDRAG_DROP_FINISH:
2081
return GDK_FILTER_REMOVE;
2084
/*************************************************************
2085
***************************** XDND **************************
2086
*************************************************************/
2088
/* Utility functions */
2093
GdkDragAction action;
2094
} xdnd_actions_table[] = {
2095
{ "XdndActionCopy", None, GDK_ACTION_COPY },
2096
{ "XdndActionMove", None, GDK_ACTION_MOVE },
2097
{ "XdndActionLink", None, GDK_ACTION_LINK },
2098
{ "XdndActionAsk", None, GDK_ACTION_ASK },
2099
{ "XdndActionPrivate", None, GDK_ACTION_COPY },
2102
static const gint xdnd_n_actions = sizeof(xdnd_actions_table) / sizeof(xdnd_actions_table[0]);
2103
static gboolean xdnd_actions_initialized = FALSE;
2106
xdnd_initialize_actions (void)
2110
xdnd_actions_initialized = TRUE;
2111
for (i=0; i < xdnd_n_actions; i++)
2112
xdnd_actions_table[i].atom = gdk_atom_intern_static_string (xdnd_actions_table[i].name);
2115
static GdkDragAction
2116
xdnd_action_from_atom (GdkDisplay *display,
2125
atom = gdk_x11_xatom_to_atom_for_display (display, xatom);
2127
if (!xdnd_actions_initialized)
2128
xdnd_initialize_actions();
2130
for (i=0; i<xdnd_n_actions; i++)
2131
if (atom == xdnd_actions_table[i].atom)
2132
return xdnd_actions_table[i].action;
2138
xdnd_action_to_atom (GdkDisplay *display,
2139
GdkDragAction action)
2143
if (!xdnd_actions_initialized)
2144
xdnd_initialize_actions();
2146
for (i=0; i<xdnd_n_actions; i++)
2147
if (action == xdnd_actions_table[i].action)
2148
return gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
2155
static GdkFilterReturn
2156
xdnd_status_filter (GdkXEvent *xev,
2160
GdkDisplay *display;
2161
XEvent *xevent = (XEvent *)xev;
2162
guint32 dest_window = xevent->xclient.data.l[0];
2163
guint32 flags = xevent->xclient.data.l[1];
2164
Atom action = xevent->xclient.data.l[4];
2165
GdkDragContext *context;
2167
if (!event->any.window ||
2168
gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2169
return GDK_FILTER_CONTINUE; /* Not for us */
2172
g_message ("XdndStatus: dest_window: %#x action: %ld",
2173
dest_window, action));
2175
display = gdk_drawable_get_display (event->any.window);
2176
context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
2180
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2181
if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
2182
private->drag_status = GDK_DRAG_STATUS_DRAG;
2184
event->dnd.send_event = FALSE;
2185
event->dnd.type = GDK_DRAG_STATUS;
2186
event->dnd.context = context;
2187
g_object_ref (context);
2189
event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
2190
if (!(action != 0) != !(flags & 1))
2193
g_warning ("Received status event with flags not corresponding to action!\n"));
2197
context->action = xdnd_action_from_atom (display, action);
2199
return GDK_FILTER_TRANSLATE;
2202
return GDK_FILTER_REMOVE;
2205
static GdkFilterReturn
2206
xdnd_finished_filter (GdkXEvent *xev,
2210
GdkDisplay *display;
2211
XEvent *xevent = (XEvent *)xev;
2212
guint32 dest_window = xevent->xclient.data.l[0];
2213
GdkDragContext *context;
2214
GdkDragContextPrivateX11 *private;
2216
if (!event->any.window ||
2217
gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2218
return GDK_FILTER_CONTINUE; /* Not for us */
2221
g_message ("XdndFinished: dest_window: %#x", dest_window));
2223
display = gdk_drawable_get_display (event->any.window);
2224
context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
2228
private = PRIVATE_DATA (context);
2229
if (private->version == 5)
2230
private->drop_failed = xevent->xclient.data.l[1] == 0;
2232
event->dnd.type = GDK_DROP_FINISHED;
2233
event->dnd.context = context;
2234
g_object_ref (context);
2236
event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
2238
return GDK_FILTER_TRANSLATE;
2241
return GDK_FILTER_REMOVE;
2245
xdnd_set_targets (GdkDragContext *context)
2247
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2249
GList *tmp_list = context->targets;
2251
gint n_atoms = g_list_length (context->targets);
2252
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2254
atomlist = g_new (Atom, n_atoms);
2258
atomlist[i] = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (tmp_list->data));
2259
tmp_list = tmp_list->next;
2263
XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
2264
GDK_DRAWABLE_XID (context->source_window),
2265
gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
2266
XA_ATOM, 32, PropModeReplace,
2267
(guchar *)atomlist, n_atoms);
2271
private->xdnd_targets_set = 1;
2275
xdnd_set_actions (GdkDragContext *context)
2277
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2282
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2284
if (!xdnd_actions_initialized)
2285
xdnd_initialize_actions();
2287
actions = context->actions;
2289
for (i=0; i<xdnd_n_actions; i++)
2291
if (actions & xdnd_actions_table[i].action)
2293
actions &= ~xdnd_actions_table[i].action;
2298
atomlist = g_new (Atom, n_atoms);
2300
actions = context->actions;
2302
for (i=0; i<xdnd_n_actions; i++)
2304
if (actions & xdnd_actions_table[i].action)
2306
actions &= ~xdnd_actions_table[i].action;
2307
atomlist[n_atoms] = gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
2312
XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
2313
GDK_DRAWABLE_XID (context->source_window),
2314
gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
2315
XA_ATOM, 32, PropModeReplace,
2316
(guchar *)atomlist, n_atoms);
2320
private->xdnd_actions_set = TRUE;
2321
private->xdnd_actions = context->actions;
2325
send_client_message_async_cb (Window window,
2329
GdkDragContext *context = data;
2331
g_message ("Got async callback for #%lx, success = %d",
2334
/* On failure, we immediately continue with the protocol
2335
* so we don't end up blocking for a timeout
2338
context->dest_window &&
2339
window == GDK_WINDOW_XID (context->dest_window))
2341
GdkEvent temp_event;
2342
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2344
g_object_unref (context->dest_window);
2345
context->dest_window = NULL;
2346
context->action = 0;
2348
private->drag_status = GDK_DRAG_STATUS_DRAG;
2350
temp_event.dnd.type = GDK_DRAG_STATUS;
2351
temp_event.dnd.window = context->source_window;
2352
temp_event.dnd.send_event = TRUE;
2353
temp_event.dnd.context = context;
2354
temp_event.dnd.time = GDK_CURRENT_TIME;
2356
gdk_event_put (&temp_event);
2359
g_object_unref (context);
2364
gdk_drag_context_get_display (GdkDragContext *context)
2366
if (context->source_window)
2367
return GDK_DRAWABLE_DISPLAY (context->source_window);
2368
else if (context->dest_window)
2369
return GDK_DRAWABLE_DISPLAY (context->dest_window);
2371
g_assert_not_reached ();
2376
send_client_message_async (GdkDragContext *context,
2380
XClientMessageEvent *event_send)
2382
GdkDisplay *display = gdk_drag_context_get_display (context);
2384
g_object_ref (context);
2386
_gdk_x11_send_client_message_async (display, window,
2387
propagate, event_mask, event_send,
2388
send_client_message_async_cb, context);
2392
xdnd_send_xevent (GdkDragContext *context,
2397
GdkDisplay *display = gdk_drag_context_get_display (context);
2401
g_assert (event_send->xany.type == ClientMessage);
2403
/* We short-circuit messages to ourselves */
2404
if (gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
2408
for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
2410
if (gdk_x11_get_xatom_by_name_for_display (display, xdnd_filters[i].atom_name) ==
2411
event_send->xclient.message_type)
2413
GdkEvent temp_event;
2414
temp_event.any.window = window;
2416
if ((*xdnd_filters[i].func) (event_send, &temp_event, NULL) == GDK_FILTER_TRANSLATE)
2418
gdk_event_put (&temp_event);
2419
g_object_unref (temp_event.dnd.context);
2427
xwindow = GDK_WINDOW_XWINDOW (window);
2429
if (_gdk_x11_display_is_root_window (display, xwindow))
2430
event_mask = ButtonPressMask;
2434
send_client_message_async (context, xwindow, propagate, event_mask,
2435
&event_send->xclient);
2441
xdnd_send_enter (GdkDragContext *context)
2444
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2445
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->dest_window);
2447
xev.xclient.type = ClientMessage;
2448
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndEnter");
2449
xev.xclient.format = 32;
2450
xev.xclient.window = private->drop_xid ?
2452
GDK_DRAWABLE_XID (context->dest_window);
2453
xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2454
xev.xclient.data.l[1] = (private->version << 24); /* version */
2455
xev.xclient.data.l[2] = 0;
2456
xev.xclient.data.l[3] = 0;
2457
xev.xclient.data.l[4] = 0;
2460
g_message ("Sending enter source window %#lx XDND protocol version %d\n",
2461
GDK_DRAWABLE_XID (context->source_window), private->version));
2462
if (g_list_length (context->targets) > 3)
2464
if (!private->xdnd_targets_set)
2465
xdnd_set_targets (context);
2466
xev.xclient.data.l[1] |= 1;
2470
GList *tmp_list = context->targets;
2475
xev.xclient.data.l[i] = gdk_x11_atom_to_xatom_for_display (display,
2476
GDK_POINTER_TO_ATOM (tmp_list->data));
2477
tmp_list = tmp_list->next;
2482
if (!xdnd_send_xevent (context, context->dest_window,
2486
g_message ("Send event to %lx failed",
2487
GDK_DRAWABLE_XID (context->dest_window)));
2488
g_object_unref (context->dest_window);
2489
context->dest_window = NULL;
2494
xdnd_send_leave (GdkDragContext *context)
2496
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2499
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2501
xev.xclient.type = ClientMessage;
2502
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndLeave");
2503
xev.xclient.format = 32;
2504
xev.xclient.window = private->drop_xid ?
2506
GDK_DRAWABLE_XID (context->dest_window);
2507
xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2508
xev.xclient.data.l[1] = 0;
2509
xev.xclient.data.l[2] = 0;
2510
xev.xclient.data.l[3] = 0;
2511
xev.xclient.data.l[4] = 0;
2513
if (!xdnd_send_xevent (context, context->dest_window,
2517
g_message ("Send event to %lx failed",
2518
GDK_DRAWABLE_XID (context->dest_window)));
2519
g_object_unref (context->dest_window);
2520
context->dest_window = NULL;
2525
xdnd_send_drop (GdkDragContext *context, guint32 time)
2527
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2528
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2531
xev.xclient.type = ClientMessage;
2532
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndDrop");
2533
xev.xclient.format = 32;
2534
xev.xclient.window = private->drop_xid ?
2536
GDK_DRAWABLE_XID (context->dest_window);
2537
xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2538
xev.xclient.data.l[1] = 0;
2539
xev.xclient.data.l[2] = time;
2540
xev.xclient.data.l[3] = 0;
2541
xev.xclient.data.l[4] = 0;
2543
if (!xdnd_send_xevent (context, context->dest_window,
2547
g_message ("Send event to %lx failed",
2548
GDK_DRAWABLE_XID (context->dest_window)));
2549
g_object_unref (context->dest_window);
2550
context->dest_window = NULL;
2555
xdnd_send_motion (GdkDragContext *context,
2558
GdkDragAction action,
2561
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2562
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2565
xev.xclient.type = ClientMessage;
2566
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndPosition");
2567
xev.xclient.format = 32;
2568
xev.xclient.window = private->drop_xid ?
2570
GDK_DRAWABLE_XID (context->dest_window);
2571
xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2572
xev.xclient.data.l[1] = 0;
2573
xev.xclient.data.l[2] = (x_root << 16) | y_root;
2574
xev.xclient.data.l[3] = time;
2575
xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
2577
if (!xdnd_send_xevent (context, context->dest_window,
2581
g_message ("Send event to %lx failed",
2582
GDK_DRAWABLE_XID (context->dest_window)));
2583
g_object_unref (context->dest_window);
2584
context->dest_window = NULL;
2586
private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
2590
xdnd_check_dest (GdkDisplay *display,
2592
guint *xdnd_version)
2594
gboolean retval = FALSE;
2597
unsigned long nitems, after;
2602
Atom xdnd_proxy_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndProxy");
2603
Atom xdnd_aware_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndAware");
2607
gdk_error_trap_push ();
2609
if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win,
2611
1, False, AnyPropertyType,
2612
&type, &format, &nitems, &after,
2617
proxy_data = (Window *)data;
2619
if ((format == 32) && (nitems == 1))
2621
proxy = *proxy_data;
2625
g_warning ("Invalid XdndProxy "
2626
"property on window %ld\n", win));
2631
if ((XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), proxy ? proxy : win,
2633
1, False, AnyPropertyType,
2634
&type, &format, &nitems, &after,
2635
&data) == Success) &&
2638
version = (Atom *)data;
2640
if ((format == 32) && (nitems == 1))
2645
*xdnd_version = *version;
2649
g_warning ("Invalid XdndAware "
2650
"property on window %ld\n", win));
2656
gdk_error_trap_pop ();
2658
return retval ? (proxy ? proxy : win) : None;
2664
xdnd_read_actions (GdkDragContext *context)
2666
GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
2669
gulong nitems, after;
2675
PRIVATE_DATA (context)->xdnd_have_actions = FALSE;
2677
if (gdk_window_get_window_type (context->source_window) == GDK_WINDOW_FOREIGN)
2679
/* Get the XdndActionList, if set */
2681
gdk_error_trap_push ();
2683
if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
2684
GDK_DRAWABLE_XID (context->source_window),
2685
gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
2687
False, XA_ATOM, &type, &format, &nitems,
2688
&after, &data) == Success &&
2691
atoms = (Atom *)data;
2693
context->actions = 0;
2695
for (i=0; i<nitems; i++)
2696
context->actions |= xdnd_action_from_atom (display, atoms[i]);
2698
PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
2700
#ifdef G_ENABLE_DEBUG
2701
if (_gdk_debug_flags & GDK_DEBUG_DND)
2703
GString *action_str = g_string_new (NULL);
2704
if (context->actions & GDK_ACTION_MOVE)
2705
g_string_append(action_str, "MOVE ");
2706
if (context->actions & GDK_ACTION_COPY)
2707
g_string_append(action_str, "COPY ");
2708
if (context->actions & GDK_ACTION_LINK)
2709
g_string_append(action_str, "LINK ");
2710
if (context->actions & GDK_ACTION_ASK)
2711
g_string_append(action_str, "ASK ");
2713
g_message("Xdnd actions = %s", action_str->str);
2714
g_string_free (action_str, TRUE);
2716
#endif /* G_ENABLE_DEBUG */
2723
gdk_error_trap_pop ();
2729
GdkDragContext *source_context;
2731
source_context = gdk_drag_context_find (display, TRUE,
2732
GDK_DRAWABLE_XID (context->source_window),
2733
GDK_DRAWABLE_XID (context->dest_window));
2737
context->actions = source_context->actions;
2738
PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
2743
/* We have to make sure that the XdndActionList we keep internally
2744
* is up to date with the XdndActionList on the source window
2745
* because we get no notification, because Xdnd wasn't meant
2746
* to continually send actions. So we select on PropertyChangeMask
2747
* and add this filter.
2749
static GdkFilterReturn
2750
xdnd_source_window_filter (GdkXEvent *xev,
2754
XEvent *xevent = (XEvent *)xev;
2755
GdkDragContext *context = cb_data;
2756
GdkDisplay *display = GDK_WINDOW_DISPLAY(event->any.window);
2758
if ((xevent->xany.type == PropertyNotify) &&
2759
(xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList")))
2761
xdnd_read_actions (context);
2763
return GDK_FILTER_REMOVE;
2766
return GDK_FILTER_CONTINUE;
2770
xdnd_manage_source_filter (GdkDragContext *context,
2772
gboolean add_filter)
2774
if (!GDK_WINDOW_DESTROYED (window) &&
2775
gdk_window_get_window_type (window) == GDK_WINDOW_FOREIGN)
2777
gdk_error_trap_push ();
2781
gdk_window_set_events (window,
2782
gdk_window_get_events (window) |
2783
GDK_PROPERTY_CHANGE_MASK);
2784
gdk_window_add_filter (window, xdnd_source_window_filter, context);
2788
gdk_window_remove_filter (window,
2789
xdnd_source_window_filter,
2791
/* Should we remove the GDK_PROPERTY_NOTIFY mask?
2792
* but we might want it for other reasons. (Like
2793
* INCR selection transactions).
2797
gdk_display_sync (gdk_drawable_get_display (window));
2798
gdk_error_trap_pop ();
2803
base_precache_atoms (GdkDisplay *display)
2805
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
2807
if (!display_x11->base_dnd_atoms_precached)
2809
static const char *const precache_atoms[] = {
2810
"ENLIGHTENMENT_DESKTOP",
2814
"_MOTIF_DRAG_RECEIVER_INFO"
2817
_gdk_x11_precache_atoms (display,
2818
precache_atoms, G_N_ELEMENTS (precache_atoms));
2820
display_x11->base_dnd_atoms_precached = TRUE;
2825
xdnd_precache_atoms (GdkDisplay *display)
2827
GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
2829
if (!display_x11->xdnd_atoms_precached)
2831
static const char *const precache_atoms[] = {
2837
"XdndActionPrivate",
2848
_gdk_x11_precache_atoms (display,
2849
precache_atoms, G_N_ELEMENTS (precache_atoms));
2851
display_x11->xdnd_atoms_precached = TRUE;
2855
static GdkFilterReturn
2856
xdnd_enter_filter (GdkXEvent *xev,
2860
GdkDisplay *display;
2861
GdkDisplayX11 *display_x11;
2862
XEvent *xevent = (XEvent *)xev;
2863
GdkDragContext *new_context;
2868
gulong nitems, after;
2872
guint32 source_window;
2876
if (!event->any.window ||
2877
gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2878
return GDK_FILTER_CONTINUE; /* Not for us */
2880
source_window = xevent->xclient.data.l[0];
2881
get_types = ((xevent->xclient.data.l[1] & 1) != 0);
2882
version = (xevent->xclient.data.l[1] & 0xff000000) >> 24;
2884
display = GDK_DRAWABLE_DISPLAY (event->any.window);
2885
display_x11 = GDK_DISPLAY_X11 (display);
2887
xdnd_precache_atoms (display);
2890
g_message ("XdndEnter: source_window: %#x, version: %#x",
2891
source_window, version));
2895
/* Old source ignore */
2896
GDK_NOTE (DND, g_message ("Ignored old XdndEnter message"));
2897
return GDK_FILTER_REMOVE;
2900
if (display_x11->current_dest_drag != NULL)
2902
g_object_unref (display_x11->current_dest_drag);
2903
display_x11->current_dest_drag = NULL;
2906
new_context = gdk_drag_context_new ();
2907
new_context->protocol = GDK_DRAG_PROTO_XDND;
2908
PRIVATE_DATA(new_context)->version = version;
2910
new_context->source_window = gdk_window_lookup_for_display (display, source_window);
2911
if (new_context->source_window)
2912
g_object_ref (new_context->source_window);
2915
new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
2916
if (!new_context->source_window)
2918
g_object_unref (new_context);
2919
return GDK_FILTER_REMOVE;
2922
new_context->dest_window = event->any.window;
2923
g_object_ref (new_context->dest_window);
2925
new_context->targets = NULL;
2928
gdk_error_trap_push ();
2929
XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (event->any.window),
2931
gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
2933
False, XA_ATOM, &type, &format, &nitems,
2936
if (gdk_error_trap_pop () || (format != 32) || (type != XA_ATOM))
2938
g_object_unref (new_context);
2943
return GDK_FILTER_REMOVE;
2946
atoms = (Atom *)data;
2948
for (i=0; i<nitems; i++)
2949
new_context->targets =
2950
g_list_append (new_context->targets,
2951
GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display,
2959
if (xevent->xclient.data.l[2+i])
2960
new_context->targets =
2961
g_list_append (new_context->targets,
2962
GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display,
2963
xevent->xclient.data.l[2+i])));
2966
#ifdef G_ENABLE_DEBUG
2967
if (_gdk_debug_flags & GDK_DEBUG_DND)
2968
print_target_list (new_context->targets);
2969
#endif /* G_ENABLE_DEBUG */
2971
xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
2972
xdnd_read_actions (new_context);
2974
event->dnd.type = GDK_DRAG_ENTER;
2975
event->dnd.context = new_context;
2976
g_object_ref (new_context);
2978
display_x11->current_dest_drag = new_context;
2980
return GDK_FILTER_TRANSLATE;
2983
static GdkFilterReturn
2984
xdnd_leave_filter (GdkXEvent *xev,
2988
XEvent *xevent = (XEvent *)xev;
2989
guint32 source_window = xevent->xclient.data.l[0];
2990
GdkDisplay *display;
2991
GdkDisplayX11 *display_x11;
2993
if (!event->any.window ||
2994
gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2995
return GDK_FILTER_CONTINUE; /* Not for us */
2998
g_message ("XdndLeave: source_window: %#x",
3001
display = GDK_DRAWABLE_DISPLAY (event->any.window);
3002
display_x11 = GDK_DISPLAY_X11 (display);
3004
xdnd_precache_atoms (display);
3006
if ((display_x11->current_dest_drag != NULL) &&
3007
(display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
3008
(GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
3010
event->dnd.type = GDK_DRAG_LEAVE;
3011
/* Pass ownership of context to the event */
3012
event->dnd.context = display_x11->current_dest_drag;
3014
display_x11->current_dest_drag = NULL;
3016
return GDK_FILTER_TRANSLATE;
3019
return GDK_FILTER_REMOVE;
3022
static GdkFilterReturn
3023
xdnd_position_filter (GdkXEvent *xev,
3027
XEvent *xevent = (XEvent *)xev;
3028
guint32 source_window = xevent->xclient.data.l[0];
3029
gint16 x_root = xevent->xclient.data.l[2] >> 16;
3030
gint16 y_root = xevent->xclient.data.l[2] & 0xffff;
3031
guint32 time = xevent->xclient.data.l[3];
3032
Atom action = xevent->xclient.data.l[4];
3034
GdkDisplay *display;
3035
GdkDisplayX11 *display_x11;
3037
if (!event->any.window ||
3038
gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
3039
return GDK_FILTER_CONTINUE; /* Not for us */
3042
g_message ("XdndPosition: source_window: %#x position: (%d, %d) time: %d action: %ld",
3043
source_window, x_root, y_root, time, action));
3045
display = GDK_DRAWABLE_DISPLAY (event->any.window);
3046
display_x11 = GDK_DISPLAY_X11 (display);
3048
xdnd_precache_atoms (display);
3050
if ((display_x11->current_dest_drag != NULL) &&
3051
(display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
3052
(GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
3054
event->dnd.type = GDK_DRAG_MOTION;
3055
event->dnd.context = display_x11->current_dest_drag;
3056
g_object_ref (display_x11->current_dest_drag);
3058
event->dnd.time = time;
3060
display_x11->current_dest_drag->suggested_action = xdnd_action_from_atom (display, action);
3062
if (!(PRIVATE_DATA (display_x11->current_dest_drag))->xdnd_have_actions)
3063
display_x11->current_dest_drag->actions = display_x11->current_dest_drag->suggested_action;
3065
event->dnd.x_root = x_root;
3066
event->dnd.y_root = y_root;
3068
(PRIVATE_DATA (display_x11->current_dest_drag))->last_x = x_root;
3069
(PRIVATE_DATA (display_x11->current_dest_drag))->last_y = y_root;
3071
return GDK_FILTER_TRANSLATE;
3074
return GDK_FILTER_REMOVE;
3077
static GdkFilterReturn
3078
xdnd_drop_filter (GdkXEvent *xev,
3082
XEvent *xevent = (XEvent *)xev;
3083
guint32 source_window = xevent->xclient.data.l[0];
3084
guint32 time = xevent->xclient.data.l[2];
3085
GdkDisplay *display;
3086
GdkDisplayX11 *display_x11;
3088
if (!event->any.window ||
3089
gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
3090
return GDK_FILTER_CONTINUE; /* Not for us */
3093
g_message ("XdndDrop: source_window: %#x time: %d",
3094
source_window, time));
3096
display = GDK_DRAWABLE_DISPLAY (event->any.window);
3097
display_x11 = GDK_DISPLAY_X11 (display);
3099
xdnd_precache_atoms (display);
3101
if ((display_x11->current_dest_drag != NULL) &&
3102
(display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
3103
(GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
3105
GdkDragContextPrivateX11 *private;
3106
private = PRIVATE_DATA (display_x11->current_dest_drag);
3108
event->dnd.type = GDK_DROP_START;
3110
event->dnd.context = display_x11->current_dest_drag;
3111
g_object_ref (display_x11->current_dest_drag);
3113
event->dnd.time = time;
3114
event->dnd.x_root = private->last_x;
3115
event->dnd.y_root = private->last_y;
3117
gdk_x11_window_set_user_time (event->any.window, time);
3119
return GDK_FILTER_TRANSLATE;
3122
return GDK_FILTER_REMOVE;
3125
/*************************************************************
3126
************************** Public API ***********************
3127
*************************************************************/
3129
_gdk_dnd_init (GdkDisplay *display)
3134
gdk_display_add_client_message_filter (
3136
gdk_atom_intern_static_string ("_MOTIF_DRAG_AND_DROP_MESSAGE"),
3137
motif_dnd_filter, NULL);
3139
for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
3141
gdk_display_add_client_message_filter (
3143
gdk_atom_intern_static_string (xdnd_filters[i].atom_name),
3144
xdnd_filters[i].func, NULL);
3151
gdk_drag_do_leave (GdkDragContext *context, guint32 time)
3153
if (context->dest_window)
3155
switch (context->protocol)
3157
case GDK_DRAG_PROTO_MOTIF:
3158
motif_send_leave (context, time);
3160
case GDK_DRAG_PROTO_XDND:
3161
xdnd_send_leave (context);
3163
case GDK_DRAG_PROTO_ROOTWIN:
3164
case GDK_DRAG_PROTO_NONE:
3169
g_object_unref (context->dest_window);
3170
context->dest_window = NULL;
3176
* @window: the source window for this drag.
3177
* @targets: (transfer none) (element-type GdkAtom): the offered targets,
3178
* as list of #GdkAtom<!-- -->s
3180
* Starts a drag and creates a new drag context for it.
3182
* This function is called by the drag source.
3184
* Return value: a newly created #GdkDragContext.
3187
gdk_drag_begin (GdkWindow *window,
3190
GdkDragContext *new_context;
3192
g_return_val_if_fail (window != NULL, NULL);
3193
g_return_val_if_fail (GDK_WINDOW_IS_X11 (window), NULL);
3195
new_context = gdk_drag_context_new ();
3196
new_context->is_source = TRUE;
3197
new_context->source_window = window;
3198
g_object_ref (window);
3200
new_context->targets = g_list_copy (targets);
3201
precache_target_list (new_context);
3203
new_context->actions = 0;
3208
static GdkNativeWindow
3209
_gdk_drag_get_protocol_for_display (GdkDisplay *display,
3210
GdkNativeWindow xid,
3211
GdkDragProtocol *protocol,
3216
GdkNativeWindow retval;
3217
g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
3219
base_precache_atoms (display);
3221
/* Check for a local drag
3223
window = gdk_window_lookup_for_display (display, xid);
3225
gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
3227
if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
3229
*protocol = GDK_DRAG_PROTO_XDND;
3231
xdnd_precache_atoms (display);
3232
GDK_NOTE (DND, g_message ("Entering local Xdnd window %#x\n", xid));
3235
else if (_gdk_x11_display_is_root_window (display, (Window) xid))
3237
*protocol = GDK_DRAG_PROTO_ROOTWIN;
3238
GDK_NOTE (DND, g_message ("Entering root window\n"));
3242
else if ((retval = xdnd_check_dest (display, xid, version)))
3244
*protocol = GDK_DRAG_PROTO_XDND;
3245
xdnd_precache_atoms (display);
3246
GDK_NOTE (DND, g_message ("Entering Xdnd window %#x\n", xid));
3249
else if ((retval = motif_check_dest (display, xid)))
3251
*protocol = GDK_DRAG_PROTO_MOTIF;
3252
GDK_NOTE (DND, g_message ("Entering motif window %#x\n", xid));
3257
/* Check if this is a root window */
3259
gboolean rootwin = FALSE;
3262
unsigned long nitems, after;
3263
unsigned char *data;
3265
if (_gdk_x11_display_is_root_window (display, (Window) xid))
3268
gdk_error_trap_push ();
3272
if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid,
3273
gdk_x11_get_xatom_by_name_for_display (display, "ENLIGHTENMENT_DESKTOP"),
3274
0, 0, False, AnyPropertyType,
3275
&type, &format, &nitems, &after, &data) == Success &&
3283
/* Until I find out what window manager the next one is for,
3284
* I'm leaving it commented out. It's supported in the
3285
* xscreensaver sources, though.
3290
if (XGetWindowProperty (gdk_display, win,
3291
gdk_x11_get_xatom_by_name ("__SWM_VROOT"),
3292
0, 0, False, AnyPropertyType,
3293
&type, &format, &nitems, &data) &&
3302
gdk_error_trap_pop ();
3306
GDK_NOTE (DND, g_message ("Entering root window\n"));
3307
*protocol = GDK_DRAG_PROTO_ROOTWIN;
3312
*protocol = GDK_DRAG_PROTO_NONE;
3314
return 0; /* a.k.a. None */
3318
* gdk_drag_get_protocol_for_display:
3319
* @display: the #GdkDisplay where the destination window resides
3320
* @xid: the windowing system id of the destination window.
3321
* @protocol: location where the supported DND protocol is returned.
3322
* @returns: the windowing system id of the window where the drop should happen. This
3323
* may be @xid or the id of a proxy window, or zero if @xid doesn't
3324
* support Drag and Drop.
3326
* Finds out the DND protocol supported by a window.
3331
gdk_drag_get_protocol_for_display (GdkDisplay *display,
3332
GdkNativeWindow xid,
3333
GdkDragProtocol *protocol)
3335
return _gdk_drag_get_protocol_for_display (display, xid, protocol, NULL);
3338
static GdkWindowCache *
3339
drag_context_find_window_cache (GdkDragContext *context,
3342
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3344
GdkWindowCache *cache;
3346
for (tmp_list = private->window_caches; tmp_list; tmp_list = tmp_list->next)
3348
cache = tmp_list->data;
3349
if (cache->screen == screen)
3353
cache = gdk_window_cache_get (screen);
3354
private->window_caches = g_slist_prepend (private->window_caches, cache);
3360
* gdk_drag_find_window_for_screen:
3361
* @context: a #GdkDragContext
3362
* @drag_window: a window which may be at the pointer position, but
3363
* should be ignored, since it is put up by the drag source as an icon.
3364
* @screen: the screen where the destination window is sought.
3365
* @x_root: the x position of the pointer in root coordinates.
3366
* @y_root: the y position of the pointer in root coordinates.
3367
* @dest_window: (out): location to store the destination window in.
3368
* @protocol: (out): location to store the DND protocol in.
3370
* Finds the destination window and DND protocol to use at the
3371
* given pointer position.
3373
* This function is called by the drag source to obtain the
3374
* @dest_window and @protocol parameters for gdk_drag_motion().
3379
gdk_drag_find_window_for_screen (GdkDragContext *context,
3380
GdkWindow *drag_window,
3384
GdkWindow **dest_window,
3385
GdkDragProtocol *protocol)
3387
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3388
GdkWindowCache *window_cache;
3389
GdkDisplay *display;
3392
g_return_if_fail (context != NULL);
3394
display = GDK_WINDOW_DISPLAY (context->source_window);
3396
window_cache = drag_context_find_window_cache (context, screen);
3398
dest = get_client_window_at_coords (window_cache,
3399
drag_window && GDK_WINDOW_IS_X11 (drag_window) ?
3400
GDK_DRAWABLE_XID (drag_window) : None,
3403
if (private->dest_xid != dest)
3406
private->dest_xid = dest;
3408
/* Check if new destination accepts drags, and which protocol */
3410
/* There is some ugliness here. We actually need to pass
3411
* _three_ pieces of information to drag_motion - dest_window,
3412
* protocol, and the XID of the unproxied window. The first
3413
* two are passed explicitely, the third implicitly through
3414
* protocol->dest_xid.
3416
if ((recipient = _gdk_drag_get_protocol_for_display (display, dest,
3417
protocol, &private->version)))
3419
*dest_window = gdk_window_lookup_for_display (display, recipient);
3421
g_object_ref (*dest_window);
3423
*dest_window = gdk_window_foreign_new_for_display (display, recipient);
3426
*dest_window = NULL;
3430
*dest_window = context->dest_window;
3432
g_object_ref (*dest_window);
3433
*protocol = context->protocol;
3439
* @context: a #GdkDragContext.
3440
* @dest_window: the new destination window, obtained by
3441
* gdk_drag_find_window().
3442
* @protocol: the DND protocol in use, obtained by gdk_drag_find_window().
3443
* @x_root: the x position of the pointer in root coordinates.
3444
* @y_root: the y position of the pointer in root coordinates.
3445
* @suggested_action: the suggested action.
3446
* @possible_actions: the possible actions.
3447
* @time_: the timestamp for this operation.
3449
* Updates the drag context when the pointer moves or the
3450
* set of actions changes.
3452
* This function is called by the drag source.
3454
* Return value: FIXME
3457
gdk_drag_motion (GdkDragContext *context,
3458
GdkWindow *dest_window,
3459
GdkDragProtocol protocol,
3462
GdkDragAction suggested_action,
3463
GdkDragAction possible_actions,
3466
GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3468
g_return_val_if_fail (context != NULL, FALSE);
3469
g_return_val_if_fail (dest_window == NULL || GDK_WINDOW_IS_X11 (dest_window), FALSE);
3471
private->old_actions = context->actions;
3472
context->actions = possible_actions;
3474
if (private->old_actions != possible_actions)
3475
private->xdnd_actions_set = FALSE;
3477
if (protocol == GDK_DRAG_PROTO_XDND && private->version == 0)
3479
/* This ugly hack is necessary since GTK+ doesn't know about
3480
* the XDND protocol version, and in particular doesn't know
3481
* that gdk_drag_find_window_for_screen() has the side-effect
3482
* of setting private->version, and therefore sometimes call
3483
* gdk_drag_motion() without a prior call to
3484
* gdk_drag_find_window_for_screen(). This happens, e.g.
3485
* when GTK+ is proxying DND events to embedded windows.
3489
GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
3491
xdnd_check_dest (display,
3492
GDK_DRAWABLE_XID (dest_window),
3497
/* When we have a Xdnd target, make sure our XdndActionList
3498
* matches the current actions;
3500
if (protocol == GDK_DRAG_PROTO_XDND && !private->xdnd_actions_set)
3504
if (gdk_window_get_window_type (dest_window) == GDK_WINDOW_FOREIGN)
3505
xdnd_set_actions (context);
3506
else if (context->dest_window == dest_window)
3508
GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
3509
GdkDragContext *dest_context;
3511
dest_context = gdk_drag_context_find (display, FALSE,
3512
GDK_DRAWABLE_XID (context->source_window),
3513
GDK_DRAWABLE_XID (dest_window));
3517
dest_context->actions = context->actions;
3518
PRIVATE_DATA (dest_context)->xdnd_have_actions = TRUE;
3524
if (context->dest_window != dest_window)
3526
GdkEvent temp_event;
3528
/* Send a leave to the last destination */
3529
gdk_drag_do_leave (context, time);
3530
private->drag_status = GDK_DRAG_STATUS_DRAG;
3532
/* Check if new destination accepts drags, and which protocol */
3536
context->dest_window = dest_window;
3537
private->drop_xid = private->dest_xid;
3538
g_object_ref (context->dest_window);
3539
context->protocol = protocol;
3543
case GDK_DRAG_PROTO_MOTIF:
3544
motif_send_enter (context, time);
3547
case GDK_DRAG_PROTO_XDND:
3548
xdnd_send_enter (context);
3551
case GDK_DRAG_PROTO_ROOTWIN:
3552
case GDK_DRAG_PROTO_NONE:
3556
private->old_action = suggested_action;
3557
context->suggested_action = suggested_action;
3558
private->old_actions = possible_actions;
3562
context->dest_window = NULL;
3563
private->drop_xid = None;
3564
context->action = 0;
3567
/* Push a status event, to let the client know that
3571
temp_event.dnd.type = GDK_DRAG_STATUS;
3572
temp_event.dnd.window = context->source_window;
3573
/* We use this to signal a synthetic status. Perhaps
3574
* we should use an extra field...
3576
temp_event.dnd.send_event = TRUE;
3578
temp_event.dnd.context = context;
3579
temp_event.dnd.time = time;
3581
gdk_event_put (&temp_event);
3585
private->old_action = context->suggested_action;
3586
context->suggested_action = suggested_action;
3589
/* Send a drag-motion event */
3591
private->last_x = x_root;
3592
private->last_y = y_root;
3594
if (context->dest_window)
3596
if (private->drag_status == GDK_DRAG_STATUS_DRAG)
3598
switch (context->protocol)
3600
case GDK_DRAG_PROTO_MOTIF:
3601
motif_send_motion (context, x_root, y_root, suggested_action, time);
3604
case GDK_DRAG_PROTO_XDND:
3605
xdnd_send_motion (context, x_root, y_root, suggested_action, time);
3608
case GDK_DRAG_PROTO_ROOTWIN:
3610
GdkEvent temp_event;
3611
/* GTK+ traditionally has used application/x-rootwin-drop,
3612
* but the XDND spec specifies x-rootwindow-drop.
3614
GdkAtom target1 = gdk_atom_intern_static_string ("application/x-rootwindow-drop");
3615
GdkAtom target2 = gdk_atom_intern_static_string ("application/x-rootwin-drop");
3617
if (g_list_find (context->targets,
3618
GDK_ATOM_TO_POINTER (target1)) ||
3619
g_list_find (context->targets,
3620
GDK_ATOM_TO_POINTER (target2)))
3621
context->action = context->suggested_action;
3623
context->action = 0;
3625
temp_event.dnd.type = GDK_DRAG_STATUS;
3626
temp_event.dnd.window = context->source_window;
3627
temp_event.dnd.send_event = FALSE;
3628
temp_event.dnd.context = context;
3629
temp_event.dnd.time = time;
3631
gdk_event_put (&temp_event);
3634
case GDK_DRAG_PROTO_NONE:
3635
g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
3650
* @context: a #GdkDragContext.
3651
* @time_: the timestamp for this operation.
3653
* Drops on the current destination.
3655
* This function is called by the drag source.
3658
gdk_drag_drop (GdkDragContext *context,
3661
g_return_if_fail (context != NULL);
3663
if (context->dest_window)
3665
switch (context->protocol)
3667
case GDK_DRAG_PROTO_MOTIF:
3668
motif_send_leave (context, time);
3669
motif_send_drop (context, time);
3672
case GDK_DRAG_PROTO_XDND:
3673
xdnd_send_drop (context, time);
3676
case GDK_DRAG_PROTO_ROOTWIN:
3677
g_warning ("Drops for GDK_DRAG_PROTO_ROOTWIN must be handled internally");
3679
case GDK_DRAG_PROTO_NONE:
3680
g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
3690
* @context: a #GdkDragContext.
3691
* @time_: the timestamp for this operation.
3693
* Aborts a drag without dropping.
3695
* This function is called by the drag source.
3698
gdk_drag_abort (GdkDragContext *context,
3701
g_return_if_fail (context != NULL);
3703
gdk_drag_do_leave (context, time);
3706
/* Destination side */
3710
* @context: a #GdkDragContext.
3711
* @action: the selected action which will be taken when a drop happens,
3712
* or 0 to indicate that a drop will not be accepted.
3713
* @time_: the timestamp for this operation.
3715
* Selects one of the actions offered by the drag source.
3717
* This function is called by the drag destination in response to
3718
* gdk_drag_motion() called by the drag source.
3721
gdk_drag_status (GdkDragContext *context,
3722
GdkDragAction action,
3725
GdkDragContextPrivateX11 *private;
3727
GdkDisplay *display;
3729
g_return_if_fail (context != NULL);
3731
private = PRIVATE_DATA (context);
3732
display = GDK_DRAWABLE_DISPLAY (context->source_window);
3734
context->action = action;
3736
if (context->protocol == GDK_DRAG_PROTO_MOTIF)
3738
gboolean need_coords = FALSE;
3740
xev.xclient.type = ClientMessage;
3741
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
3742
"_MOTIF_DRAG_AND_DROP_MESSAGE");
3743
xev.xclient.format = 8;
3744
xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3746
if (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT)
3748
MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED | 0x80;
3752
if ((action != 0) != (private->old_action != 0))
3756
MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_ENTER | 0x80;
3760
MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_LEAVE | 0x80;
3764
MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION | 0x80;
3769
MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
3773
case GDK_ACTION_MOVE:
3774
MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_MOVE;
3776
case GDK_ACTION_COPY:
3777
MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY;
3779
case GDK_ACTION_LINK:
3780
MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_LINK;
3783
MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP;
3788
MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmDROP_SITE_VALID << 4);
3790
MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmNO_DROP_SITE << 4);
3792
MOTIF_XCLIENT_LONG (&xev, 1) = time;
3796
MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
3797
MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
3800
MOTIF_XCLIENT_LONG (&xev, 2) = 0;
3802
MOTIF_XCLIENT_LONG (&xev, 3) = 0;
3803
MOTIF_XCLIENT_LONG (&xev, 4) = 0;
3805
if (!_gdk_send_xevent (display,
3806
GDK_DRAWABLE_XID (context->source_window),
3809
g_message ("Send event to %lx failed",
3810
GDK_DRAWABLE_XID (context->source_window)));
3812
else if (context->protocol == GDK_DRAG_PROTO_XDND)
3814
xev.xclient.type = ClientMessage;
3815
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndStatus");
3816
xev.xclient.format = 32;
3817
xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3819
xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
3820
xev.xclient.data.l[1] = (action != 0) ? (2 | 1) : 0;
3821
xev.xclient.data.l[2] = 0;
3822
xev.xclient.data.l[3] = 0;
3823
xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
3825
if (!xdnd_send_xevent (context, context->source_window,
3828
g_message ("Send event to %lx failed",
3829
GDK_DRAWABLE_XID (context->source_window)));
3832
private->old_action = action;
3837
* @context: a #GdkDragContext.
3838
* @ok: %TRUE if the drop is accepted.
3839
* @time_: the timestamp for this operation.
3841
* Accepts or rejects a drop.
3843
* This function is called by the drag destination in response
3844
* to a drop initiated by the drag source.
3847
gdk_drop_reply (GdkDragContext *context,
3851
GdkDragContextPrivateX11 *private;
3853
g_return_if_fail (context != NULL);
3855
private = PRIVATE_DATA (context);
3857
if (context->protocol == GDK_DRAG_PROTO_MOTIF)
3859
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
3862
xev.xclient.type = ClientMessage;
3863
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
3864
"_MOTIF_DRAG_AND_DROP_MESSAGE");
3865
xev.xclient.format = 8;
3867
MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START | 0x80;
3868
MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
3870
MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY |
3871
(XmDROP_SITE_VALID << 4) |
3872
(XmDROP_NOOP << 8) |
3875
MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP |
3876
(XmNO_DROP_SITE << 4) |
3877
(XmDROP_NOOP << 8) |
3878
(XmDROP_CANCEL << 12);
3879
MOTIF_XCLIENT_SHORT (&xev, 2) = private->last_x;
3880
MOTIF_XCLIENT_SHORT (&xev, 3) = private->last_y;
3881
MOTIF_XCLIENT_LONG (&xev, 2) = 0;
3882
MOTIF_XCLIENT_LONG (&xev, 3) = 0;
3883
MOTIF_XCLIENT_LONG (&xev, 4) = 0;
3885
_gdk_send_xevent (display,
3886
GDK_DRAWABLE_XID (context->source_window),
3893
* @context: a #GtkDragContext.
3894
* @success: %TRUE if the data was successfully received.
3895
* @time_: the timestamp for this operation.
3897
* Ends the drag operation after a drop.
3899
* This function is called by the drag destination.
3902
gdk_drop_finish (GdkDragContext *context,
3906
g_return_if_fail (context != NULL);
3908
if (context->protocol == GDK_DRAG_PROTO_XDND)
3910
GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
3913
xev.xclient.type = ClientMessage;
3914
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndFinished");
3915
xev.xclient.format = 32;
3916
xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3918
xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
3921
xev.xclient.data.l[1] = 1;
3922
xev.xclient.data.l[2] = xdnd_action_to_atom (display,
3927
xev.xclient.data.l[1] = 0;
3928
xev.xclient.data.l[2] = None;
3930
xev.xclient.data.l[3] = 0;
3931
xev.xclient.data.l[4] = 0;
3933
if (!xdnd_send_xevent (context, context->source_window,
3936
g_message ("Send event to %lx failed",
3937
GDK_DRAWABLE_XID (context->source_window)));
3943
gdk_window_register_dnd (GdkWindow *window)
3945
static const gulong xdnd_version = 5;
3946
MotifDragReceiverInfo info;
3947
Atom motif_drag_receiver_info_atom;
3948
GdkDisplay *display = gdk_drawable_get_display (window);
3950
g_return_if_fail (window != NULL);
3952
if (gdk_window_get_window_type (window) == GDK_WINDOW_OFFSCREEN)
3955
base_precache_atoms (display);
3957
if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
3960
g_object_set_data (G_OBJECT (window), "gdk-dnd-registered", GINT_TO_POINTER (TRUE));
3962
/* Set Motif drag receiver information property */
3964
motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display,
3965
"_MOTIF_DRAG_RECEIVER_INFO");
3966
/* initialize to zero to avoid writing uninitialized data to socket */
3967
memset(&info, 0, sizeof(info));
3968
info.byte_order = local_byte_order;
3969
info.protocol_version = 0;
3970
info.protocol_style = XmDRAG_DYNAMIC;
3971
info.proxy_window = None;
3972
info.num_drop_sites = 0;
3973
info.total_size = sizeof(info);
3975
XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_DRAWABLE_XID (window),
3976
motif_drag_receiver_info_atom,
3977
motif_drag_receiver_info_atom,
3984
/* The property needs to be of type XA_ATOM, not XA_INTEGER. Blech */
3985
XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
3986
GDK_DRAWABLE_XID (window),
3987
gdk_x11_get_xatom_by_name_for_display (display, "XdndAware"),
3988
XA_ATOM, 32, PropModeReplace,
3989
(guchar *)&xdnd_version, 1);
3993
* gdk_drag_get_selection:
3994
* @context: a #GdkDragContext.
3996
* Returns the selection atom for the current source window.
3998
* Return value: the selection atom.
4001
gdk_drag_get_selection (GdkDragContext *context)
4003
g_return_val_if_fail (context != NULL, GDK_NONE);
4005
if (context->protocol == GDK_DRAG_PROTO_MOTIF)
4006
return gdk_x11_xatom_to_atom_for_display (GDK_DRAWABLE_DISPLAY (context->source_window),
4007
(PRIVATE_DATA (context))->motif_selection);
4008
else if (context->protocol == GDK_DRAG_PROTO_XDND)
4009
return gdk_atom_intern_static_string ("XdndSelection");
4015
* gdk_drag_drop_succeeded:
4016
* @context: a #GdkDragContext
4018
* Returns whether the dropped data has been successfully
4019
* transferred. This function is intended to be used while
4020
* handling a %GDK_DROP_FINISHED event, its return value is
4021
* meaningless at other times.
4023
* Return value: %TRUE if the drop was successful.
4028
gdk_drag_drop_succeeded (GdkDragContext *context)
4030
GdkDragContextPrivateX11 *private;
4032
g_return_val_if_fail (context != NULL, FALSE);
4034
private = PRIVATE_DATA (context);
4036
return !private->drop_failed;
4039
#define __GDK_DND_X11_C__
4040
#include "gdkaliasdef.c"