/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <string.h>
guint16 last_x; /* Coordinates from last event */
guint16 last_y;
- GdkDragAction old_action; /* The last action we sent to the source */
+ GdkDragAction old_action; /* The last action we sent to the source */
+ GdkDragAction old_actions; /* The last actions we sent to the source */
+ GdkDragAction xdnd_actions; /* What is currently set in XdndActionList */
- Window dest_xid;
+ Window dest_xid; /* The last window we looked up */
+ Window drop_xid; /* The (non-proxied) window that is receiving drops */
guint xdnd_targets_set : 1; /* Whether we've already set XdndTypeList */
+ guint xdnd_actions_set : 1; /* Whether we've already set XdndActionList */
+ guint xdnd_have_actions : 1; /* Whether an XdndActionList was provided */
guint motif_targets_set : 1; /* Whether we've already set motif initiator info */
guint drag_status : 4; /* current status of drag */
GdkEvent *event,
gpointer data);
+static void xdnd_manage_source_filter (GdkDragContext *context,
+ GdkWindow *window,
+ gboolean add_filter);
+
/* Drag Contexts */
static GList *contexts;
void
gdk_drag_context_ref (GdkDragContext *context)
{
+ g_return_if_fail (context != NULL);
+
((GdkDragContextPrivate *)context)->ref_count++;
}
gdk_drag_context_unref (GdkDragContext *context)
{
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+
+ g_return_if_fail (context != NULL);
+ g_return_if_fail (private->ref_count > 0);
+
private->ref_count--;
if (private->ref_count == 0)
g_list_free (context->targets);
if (context->source_window)
- gdk_window_unref (context->source_window);
+ {
+ if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
+ !context->is_source)
+ xdnd_manage_source_filter (context, context->source_window, FALSE);
+
+ gdk_window_unref (context->source_window);
+ }
if (context->dest_window)
gdk_window_unref (context->dest_window);
Window dest_xid)
{
GList *tmp_list = contexts;
+ GdkDragContext *context;
+ GdkDragContextPrivate *private;
+ Window context_dest_xid;
while (tmp_list)
{
- GdkDragContext *context = (GdkDragContext *)tmp_list->data;
+ context = (GdkDragContext *)tmp_list->data;
+ private = (GdkDragContextPrivate *)context;
+
+ context_dest_xid = context->dest_window ?
+ (private->drop_xid ?
+ private->drop_xid :
+ GDK_WINDOW_XWINDOW (context->dest_window)) :
+ None;
if ((!context->is_source == !is_source) &&
((source_xid == None) || (context->source_window &&
(GDK_WINDOW_XWINDOW (context->source_window) == source_xid))) &&
- ((dest_xid == None) || (context->dest_window &&
- (GDK_WINDOW_XWINDOW (context->dest_window) == dest_xid))))
+ ((dest_xid == None) || (context_dest_xid == dest_xid)))
return context;
tmp_list = tmp_list->next;
{
cache->children = g_list_remove_link (cache->children, node);
node->next = above_node->next;
+ if (node->next)
+ node->next->prev = node;
node->prev = above_node;
above_node->next = node;
}
case CreateNotify:
{
XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
+
if (!g_hash_table_lookup (cache->child_hash,
GUINT_TO_POINTER (xcwe->window)))
gdk_window_cache_add (cache, xcwe->window,
xwa.x, xwa.y, xwa.width, xwa.height,
xwa.map_state != IsUnmapped);
- if (gdk_error_code != 0)
+ if (gdk_error_code)
gdk_error_code = 0;
else
{
g_list_foreach (cache->children, (GFunc)g_free, NULL);
g_list_free (cache->children);
g_hash_table_destroy (cache->child_hash);
+
+ g_free (cache);
}
static Window
get_client_window_at_coords_recurse (Window win,
- gint x_root,
- gint y_root)
+ gint x,
+ gint y)
{
- Window child;
+ Window root, tmp_parent, *children;
+ unsigned int nchildren;
+ int i;
+ Window child = None;
Atom type = None;
int format;
unsigned long nitems, after;
unsigned char *data;
- int dest_x, dest_y;
static Atom wm_state_atom = None;
wm_state_atom, 0, 0, False, AnyPropertyType,
&type, &format, &nitems, &after, &data);
- if (gdk_error_code != 0)
+ if (gdk_error_code)
{
gdk_error_code = 0;
+
return None;
}
return win;
}
+#if 0
+ /* This is beautiful! Damn Enlightenment and click-to-focus */
XTranslateCoordinates (gdk_display, gdk_root_window, win,
x_root, y_root, &dest_x, &dest_y, &child);
- if (gdk_error_code != 0)
+ if (gdk_error_code)
{
gdk_error_code = 0;
+
return None;
}
+
+#else
+ if (XQueryTree(gdk_display, win,
+ &root, &tmp_parent, &children, &nchildren) == 0)
+ return 0;
+
+ if (!gdk_error_code)
+ {
+ for (i = nchildren - 1; (i >= 0) && (child == None); i--)
+ {
+ XWindowAttributes xwa;
+
+ XGetWindowAttributes (gdk_display, children[i], &xwa);
+
+ if (gdk_error_code)
+ gdk_error_code = 0;
+ else if ((xwa.map_state == IsViewable) && (xwa.class == InputOutput) &&
+ (x >= xwa.x) && (x < xwa.x + (gint)xwa.width) &&
+ (y >= xwa.y) && (y < xwa.y + (gint)xwa.height))
+ {
+ x -= xwa.x;
+ y -= xwa.y;
+ child = children[i];
+ }
+ }
+
+ XFree (children);
+ }
+ else
+ gdk_error_code = 0;
+#endif
if (child)
- return get_client_window_at_coords_recurse (child, x_root, y_root);
+ return get_client_window_at_coords_recurse (child, x, y);
else
return None;
}
-Window
+static Window
get_client_window_at_coords (GdkWindowCache *cache,
- Window ignore,
- gint x_root,
- gint y_root)
+ Window ignore,
+ gint x_root,
+ gint y_root)
{
GList *tmp_list;
Window retval = None;
(y_root >= child->y) && (y_root < child->y + child->height))
{
retval = get_client_window_at_coords_recurse (child->xid,
- x_root, y_root);
+ x_root - child->x,
+ y_root - child->y);
if (!retval)
retval = child->xid;
}
wm_state_atom, 0, 0, False, AnyPropertyType,
&type, &format, &nitems, &after, &data);
- if (gdk_error_code != 0)
+ if (gdk_error_code)
{
gdk_error_code = 0;
+
return None;
}
XTranslateCoordinates (gdk_display, gdk_root_window, win,
x_root, y_root, &dest_x, &dest_y, &child);
- if (gdk_error_code != 0)
+ if (gdk_error_code)
{
gdk_error_code = 0;
+
return None;
}
return None;
}
-Window
+static Window
get_client_window_at_coords (Window ignore,
gint x_root,
gint y_root)
if (XQueryTree(gdk_display, gdk_root_window,
&root, &parent, &children, &nchildren) == 0)
return 0;
-
+
for (i = nchildren - 1; (i >= 0) && (retval == None); i--)
{
if (children[i] != ignore)
XGetWindowAttributes (gdk_display, children[i], &xwa);
- if (gdk_error_code != 0)
+ if (gdk_error_code)
gdk_error_code = 0;
else if ((xwa.map_state == IsViewable) &&
(x_root >= xwa.x) && (x_root < xwa.x + (gint)xwa.width) &&
return (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
}
+/* Motif packs together fields of varying length into the
+ * client message. We can't rely on accessing these
+ * through data.s[], data.l[], etc, because on some architectures
+ * (i.e., Alpha) these won't be valid for format == 8.
+ */
+
+#define MOTIF_XCLIENT_BYTE(xevent,i) \
+ (xevent)->xclient.data.b[i]
+#define MOTIF_XCLIENT_SHORT(xevent,i) \
+ ((gint16 *)&((xevent)->xclient.data.b[0]))[i]
+#define MOTIF_XCLIENT_LONG(xevent,i) \
+ ((gint32 *)&((xevent)->xclient.data.b[0]))[i]
+
+#define MOTIF_UNPACK_BYTE(xevent,i) MOTIF_XCLIENT_BYTE(xevent,i)
+#define MOTIF_UNPACK_SHORT(xevent,i) \
+ card16_to_host (MOTIF_XCLIENT_SHORT(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
+#define MOTIF_UNPACK_LONG(xevent,i) \
+ card32_to_host (MOTIF_XCLIENT_LONG(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
/***** Dest side ***********/
return GDK_FILTER_REMOVE;
}
-static GdkAtom motif_drag_window_atom = GDK_NONE;
+static Atom motif_drag_window_atom = GDK_NONE;
static Window
motif_lookup_drag_window (Display *display)
guchar *data;
XGetWindowProperty (gdk_display, gdk_root_window, motif_drag_window_atom,
- 0, sizeof(Window)/4, FALSE,
+ 0, 1, FALSE,
XA_WINDOW, &type, &format, &nitems, &bytes_after,
&data);
- if ((format == 8*sizeof(Window)) && (nitems == 1) && (bytes_after == 0))
+ if ((format == 32) && (nitems == 1) && (bytes_after == 0))
{
retval = *(Window *)data;
GDK_NOTE(DND,
Display *display;
XSetWindowAttributes attr;
- display = XOpenDisplay (NULL);
+ display = XOpenDisplay (gdk_display_name);
XSetCloseDownMode (display, RetainPermanent);
XGrabServer (display);
XGetWindowProperty (gdk_display, motif_drag_window, motif_drag_targets_atom,
(sizeof(MotifTargetTableHeader)+3)/4,
- (header->total_size - sizeof(MotifTargetTableHeader) + 3)/4,
+ (header->total_size + 3)/4 - (sizeof(MotifTargetTableHeader) + 3)/4,
FALSE,
motif_drag_targets_atom, &type, &format, &nitems,
&bytes_after, &target_bytes);
goto error;
n_targets = card16_to_host (*(gushort *)p, header->byte_order);
- targets = (guint32 *)(p + sizeof(guint16));
+
+ /* We need to make a copy of the targets, since it may
+ * be unaligned
+ */
+ targets = g_new (guint32, n_targets);
+ memcpy (targets, p + sizeof(guint16), sizeof(guint32) * n_targets);
p += sizeof(guint16) + n_targets * sizeof(guint32);
if (p - target_bytes > nitems)
g_list_prepend (motif_target_lists[i],
GUINT_TO_POINTER (card32_to_host (targets[j],
header->byte_order)));
-
+ g_free (targets);
motif_target_lists[i] = g_list_reverse (motif_target_lists[i]);
}
guchar *data;
guchar *p;
guint16 *p16;
- guint32 *p32;
MotifTargetTableHeader *header;
if (!motif_target_lists)
for (i = 0; i < motif_n_target_lists ; i++)
{
- guint16 count = 0;
+ guint16 n_targets = g_list_length (motif_target_lists[i]);
+ guint32 *targets = g_new (guint32, n_targets);
+ guint32 *p32 = targets;
- p16 = (guint16 *)p;
- p += sizeof(guint16);
- p32 = (guint32 *)p;
tmp_list = motif_target_lists[i];
while (tmp_list)
{
- *p32++ = GPOINTER_TO_UINT (tmp_list->data);
+ *p32 = GPOINTER_TO_UINT (tmp_list->data);
+
tmp_list = tmp_list->next;
- count++;
+ p32++;
}
- *p16 = count;
- p = (guchar *)p32;
+
+ p16 = (guint16 *)p;
+ p += sizeof(guint16);
+
+ memcpy (p, targets, n_targets * sizeof(guint32));
+
+ *p16 = n_targets;
+ p += sizeof(guint32) * n_targets;
+ g_free (targets);
}
XChangeProperty (gdk_display, motif_drag_window,
private->motif_targets_set = 1;
}
-gboolean
+guint32
motif_check_dest (Window win)
{
gboolean retval = FALSE;
if (!motif_drag_receiver_info_atom)
motif_drag_receiver_info_atom = gdk_atom_intern ("_MOTIF_DRAG_RECEIVER_INFO", FALSE);
-
+
XGetWindowProperty (gdk_display, win,
motif_drag_receiver_info_atom,
0, (sizeof(*info)+3)/4, False, AnyPropertyType,
XFree (info);
}
- return retval;
+ return retval ? win : GDK_NONE;
}
xev.xclient.format = 8;
xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
- xev.xclient.data.b[0] = XmTOP_LEVEL_ENTER;
- xev.xclient.data.b[1] = local_byte_order;
- xev.xclient.data.s[1] = 0;
- xev.xclient.data.l[1] = time;
- xev.xclient.data.l[2] = GDK_WINDOW_XWINDOW (context->source_window);
+ MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_ENTER;
+ MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
+ MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
+ MOTIF_XCLIENT_LONG (&xev, 1) = time;
+ MOTIF_XCLIENT_LONG (&xev, 2) = GDK_WINDOW_XWINDOW (context->source_window);
if (!private->motif_targets_set)
motif_set_targets (context);
- xev.xclient.data.l[3] = private->motif_selection;
+ MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection;
if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
FALSE, 0, &xev))
xev.xclient.format = 8;
xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
- xev.xclient.data.b[0] = XmTOP_LEVEL_LEAVE;
- xev.xclient.data.b[1] = local_byte_order;
- xev.xclient.data.s[1] = 0;
- xev.xclient.data.l[1] = time;
- xev.xclient.data.l[2] = GDK_WINDOW_XWINDOW (context->source_window);
- xev.xclient.data.l[3] = 0;
+ MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_LEAVE;
+ MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
+ MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
+ MOTIF_XCLIENT_LONG (&xev, 1) = time;
+ MOTIF_XCLIENT_LONG (&xev, 2) = GDK_WINDOW_XWINDOW (context->source_window);
+ MOTIF_XCLIENT_LONG (&xev, 3) = 0;
if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
FALSE, 0, &xev))
xev.xclient.format = 8;
xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
- xev.xclient.data.b[1] = local_byte_order;
- xev.xclient.data.s[1] = motif_dnd_get_flags (context);
- xev.xclient.data.l[1] = time;
+ MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
+ MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
+ MOTIF_XCLIENT_LONG (&xev, 1) = time;
- if (context->suggested_action != private->old_action)
+ if ((context->suggested_action != private->old_action) ||
+ (context->actions != private->old_actions))
{
- xev.xclient.data.b[0] = XmOPERATION_CHANGED;
+ MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
- private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
+ /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
retval = TRUE;
}
else
{
- xev.xclient.data.b[0] = XmDRAG_MOTION;
+ MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION;
- xev.xclient.data.s[4] = x_root;
- xev.xclient.data.s[5] = y_root;
+ MOTIF_XCLIENT_SHORT (&xev, 4) = x_root;
+ MOTIF_XCLIENT_SHORT (&xev, 5) = y_root;
private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
retval = FALSE;
xev.xclient.format = 8;
xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
- xev.xclient.data.b[0] = XmDROP_START;
- xev.xclient.data.b[1] = local_byte_order;
- xev.xclient.data.s[1] = motif_dnd_get_flags (context);
- xev.xclient.data.l[1] = time;
+ MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START;
+ MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
+ MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
+ MOTIF_XCLIENT_LONG (&xev, 1) = time;
- xev.xclient.data.s[4] = private->last_x;
- xev.xclient.data.s[5] = private->last_y;
+ MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
+ MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
- xev.xclient.data.l[3] = private->motif_selection;
- xev.xclient.data.l[4] = GDK_WINDOW_XWINDOW (context->source_window);
+ MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection;
+ MOTIF_XCLIENT_LONG (&xev, 4) = GDK_WINDOW_XWINDOW (context->source_window);
if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
FALSE, 0, &xev))
motif_read_target_table ();
+ initiator_info->targets_index =
+ card16_to_host (initiator_info->targets_index, initiator_info->byte_order);
+ initiator_info->selection_atom =
+ card32_to_host (initiator_info->selection_atom, initiator_info->byte_order);
+
if (initiator_info->targets_index >= motif_n_target_lists)
{
g_warning ("Invalid target index in TOP_LEVEL_ENTER MESSAGE");
if (context)
{
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
- if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
+ if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
+ (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
private->drag_status = GDK_DRAG_STATUS_DRAG;
event->dnd.type = GDK_DRAG_STATUS;
gpointer data)
{
XEvent *xevent = (XEvent *)xev;
- XClientMessageEvent *xce = &xevent->xclient;
guint8 reason;
- gchar byte_order;
guint16 flags;
guint32 timestamp;
guint32 source_window;
/* First read some fields common to all Motif DND messages */
- reason = xce->data.b[0];
- byte_order = xce->data.b[1];
- flags = card16_to_host (xce->data.s[1], byte_order);
- timestamp = card32_to_host (xce->data.l[1], byte_order);
+ reason = MOTIF_UNPACK_BYTE (xevent, 0);
+ flags = MOTIF_UNPACK_SHORT (xevent, 1);
+ timestamp = MOTIF_UNPACK_LONG (xevent, 1);
is_reply = ((reason & 0x80) != 0);
switch (reason & 0x7f)
{
case XmTOP_LEVEL_ENTER:
- source_window = card32_to_host (xce->data.l[2], byte_order);
- atom = card32_to_host (xce->data.l[3], byte_order);
+ source_window = MOTIF_UNPACK_LONG (xevent, 2);
+ atom = MOTIF_UNPACK_LONG (xevent, 3);
return motif_top_level_enter (event, flags, timestamp, source_window, atom);
case XmTOP_LEVEL_LEAVE:
return motif_top_level_leave (event, flags, timestamp);
case XmDRAG_MOTION:
- x_root = card16_to_host (xce->data.s[4], byte_order);
- y_root = card16_to_host (xce->data.s[5], byte_order);
+ x_root = MOTIF_UNPACK_SHORT (xevent, 4);
+ y_root = MOTIF_UNPACK_SHORT (xevent, 5);
if (!is_reply)
return motif_motion (event, flags, timestamp, x_root, y_root);
XmNO_DROP_SITE << 8 | XmDROP_NOOP,
timestamp);
case XmDROP_START:
- x_root = card16_to_host (xce->data.s[4], byte_order);
- y_root = card16_to_host (xce->data.s[5], byte_order);
- atom = card32_to_host (xce->data.l[3], byte_order);
- source_window = card32_to_host (xce->data.l[4], byte_order);
+ x_root = MOTIF_UNPACK_SHORT (xevent, 4);
+ y_root = MOTIF_UNPACK_SHORT (xevent, 5);
+ atom = MOTIF_UNPACK_LONG (xevent, 3);
+ source_window = MOTIF_UNPACK_LONG (xevent, 4);
if (!is_reply)
return motif_drop_start (event, flags, timestamp, source_window, atom, x_root, y_root);
xdnd_set_targets (GdkDragContext *context)
{
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
- GdkAtom *typelist;
+ GdkAtom *atomlist;
GList *tmp_list = context->targets;
gint i;
- gint n_targets = g_list_length (context->targets);
+ gint n_atoms = g_list_length (context->targets);
- typelist = g_new (GdkAtom, n_targets);
+ atomlist = g_new (GdkAtom, n_atoms);
i = 0;
while (tmp_list)
{
- typelist[i] = GPOINTER_TO_INT (tmp_list->data);
+ atomlist[i] = GPOINTER_TO_INT (tmp_list->data);
tmp_list = tmp_list->next;
i++;
}
GDK_WINDOW_XWINDOW (context->source_window),
gdk_atom_intern ("XdndTypeList", FALSE),
XA_ATOM, 32, PropModeReplace,
- (guchar *)typelist, n_targets);
+ (guchar *)atomlist, n_atoms);
+
+ g_free (atomlist);
private->xdnd_targets_set = 1;
}
+static void
+xdnd_set_actions (GdkDragContext *context)
+{
+ GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+ GdkAtom *atomlist;
+ gint i;
+ gint n_atoms;
+ guint actions;
+
+ if (!xdnd_actions_initialized)
+ xdnd_initialize_actions();
+
+ actions = context->actions;
+ n_atoms = 0;
+ for (i=0; i<xdnd_n_actions; i++)
+ {
+ if (actions & xdnd_actions_table[i].action)
+ {
+ actions &= ~xdnd_actions_table[i].action;
+ n_atoms++;
+ }
+ }
+
+ atomlist = g_new (GdkAtom, n_atoms);
+
+ actions = context->actions;
+ n_atoms = 0;
+ for (i=0; i<xdnd_n_actions; i++)
+ {
+ if (actions & xdnd_actions_table[i].action)
+ {
+ actions &= ~xdnd_actions_table[i].action;
+ atomlist[n_atoms] = xdnd_actions_table[i].atom;
+ n_atoms++;
+ }
+ }
+
+ XChangeProperty (GDK_WINDOW_XDISPLAY (context->source_window),
+ GDK_WINDOW_XWINDOW (context->source_window),
+ gdk_atom_intern ("XdndActionList", FALSE),
+ XA_ATOM, 32, PropModeReplace,
+ (guchar *)atomlist, n_atoms);
+
+ g_free (atomlist);
+
+ private->xdnd_actions_set = 1;
+ private->xdnd_actions = context->actions;
+}
+
+/*************************************************************
+ * xdnd_send_xevent:
+ * Like gdk_send_event, but if the target is the root
+ * window, sets an event mask of ButtonPressMask, otherwise
+ * an event mask of 0.
+ * arguments:
+ *
+ * results:
+ *************************************************************/
+
+gint
+xdnd_send_xevent (Window window, gboolean propagate,
+ XEvent *event_send)
+{
+ if (window == gdk_root_window)
+ return gdk_send_xevent (window, propagate, ButtonPressMask, event_send);
+ else
+ return gdk_send_xevent (window, propagate, 0, event_send);
+}
+
static void
xdnd_send_enter (GdkDragContext *context)
{
xev.xclient.type = ClientMessage;
xev.xclient.message_type = gdk_atom_intern ("XdndEnter", FALSE);
xev.xclient.format = 32;
- xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
+ xev.xclient.window = private->drop_xid ?
+ private->drop_xid :
+ GDK_WINDOW_XWINDOW (context->dest_window);
xev.xclient.data.l[0] = GDK_WINDOW_XWINDOW (context->source_window);
xev.xclient.data.l[1] = (3 << 24); /* version */
xev.xclient.data.l[2] = 0;
}
}
- if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
- FALSE, 0, &xev))
+ if (!xdnd_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
+ FALSE, &xev))
{
GDK_NOTE (DND,
g_message ("Send event to %lx failed",
{
XEvent xev;
+ GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+
xev.xclient.type = ClientMessage;
xev.xclient.message_type = gdk_atom_intern ("XdndLeave", FALSE);
xev.xclient.format = 32;
- xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
+ xev.xclient.window = private->drop_xid ?
+ private->drop_xid :
+ GDK_WINDOW_XWINDOW (context->dest_window);
xev.xclient.data.l[0] = GDK_WINDOW_XWINDOW (context->source_window);
xev.xclient.data.l[1] = 0;
xev.xclient.data.l[2] = 0;
xev.xclient.data.l[3] = 0;
xev.xclient.data.l[4] = 0;
- if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
- FALSE, 0, &xev))
+ if (!xdnd_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
+ FALSE, &xev))
{
GDK_NOTE (DND,
g_message ("Send event to %lx failed",
static void
xdnd_send_drop (GdkDragContext *context, guint32 time)
{
+ GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
XEvent xev;
xev.xclient.type = ClientMessage;
xev.xclient.message_type = gdk_atom_intern ("XdndDrop", FALSE);
xev.xclient.format = 32;
- xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
+ xev.xclient.window = private->drop_xid ?
+ private->drop_xid :
+ GDK_WINDOW_XWINDOW (context->dest_window);
xev.xclient.data.l[0] = GDK_WINDOW_XWINDOW (context->source_window);
xev.xclient.data.l[1] = 0;
xev.xclient.data.l[2] = time;
xev.xclient.data.l[3] = 0;
xev.xclient.data.l[4] = 0;
- if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
- FALSE, 0, &xev))
+ if (!xdnd_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
+ FALSE, &xev))
{
GDK_NOTE (DND,
g_message ("Send event to %lx failed",
xev.xclient.type = ClientMessage;
xev.xclient.message_type = gdk_atom_intern ("XdndPosition", FALSE);
xev.xclient.format = 32;
- xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
+ xev.xclient.window = private->drop_xid ?
+ private->drop_xid :
+ GDK_WINDOW_XWINDOW (context->dest_window);
xev.xclient.data.l[0] = GDK_WINDOW_XWINDOW (context->source_window);
xev.xclient.data.l[1] = 0;
xev.xclient.data.l[2] = (x_root << 16) | y_root;
xev.xclient.data.l[3] = time;
xev.xclient.data.l[4] = xdnd_action_to_atom (action);
- if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
- FALSE, 0, &xev))
+ if (!xdnd_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
+ FALSE, &xev))
{
GDK_NOTE (DND,
g_message ("Send event to %lx failed",
private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
}
-static gboolean
+static guint32
xdnd_check_dest (Window win)
{
gboolean retval = FALSE;
int format;
unsigned long nitems, after;
GdkAtom *version;
+ Window *proxy_data;
+ Window proxy;
+ static GdkAtom xdnd_proxy_atom = GDK_NONE;
+
+ gint old_warnings = gdk_error_warnings;
+
+ if (!xdnd_proxy_atom)
+ xdnd_proxy_atom = gdk_atom_intern ("XdndProxy", FALSE);
if (!xdnd_aware_atom)
xdnd_aware_atom = gdk_atom_intern ("XdndAware", FALSE);
+ proxy = GDK_NONE;
+
+ gdk_error_code = 0;
+ gdk_error_warnings = 0;
+
XGetWindowProperty (gdk_display, win,
- xdnd_aware_atom, 0,
+ xdnd_proxy_atom, 0,
1, False, AnyPropertyType,
&type, &format, &nitems, &after,
- (guchar **)&version);
+ (guchar **)&proxy_data);
+
+ if (!gdk_error_code)
+ {
+ if (type != None)
+ {
+ if ((format == 32) && (nitems == 1))
+ {
+ proxy = *proxy_data;
+ }
+ else
+ GDK_NOTE (DND,
+ g_warning ("Invalid XdndOwner property on window %ld\n", win));
+
+ XFree (proxy_data);
+ }
+
+ XGetWindowProperty (gdk_display, proxy ? proxy : win,
+ xdnd_aware_atom, 0,
+ 1, False, AnyPropertyType,
+ &type, &format, &nitems, &after,
+ (guchar **)&version);
+
+ if (!gdk_error_code && type != None)
+ {
+ if ((format == 32) && (nitems == 1))
+ {
+ if (*version == 3)
+ retval = TRUE;
+ }
+ else
+ GDK_NOTE (DND,
+ g_warning ("Invalid XdndAware property on window %ld\n", win));
+
+ XFree (version);
+ }
+
+ }
+
+ gdk_error_warnings = old_warnings;
+ gdk_error_code = 0;
- if (type != None)
+ return retval ? (proxy ? proxy : win) : GDK_NONE;
+}
+
+/* Target side */
+
+static void
+xdnd_read_actions (GdkDragContext *context)
+{
+ Atom type;
+ int format;
+ gulong nitems, after;
+ Atom *data;
+
+ gint i;
+
+ gint old_warnings = gdk_error_warnings;
+
+ gdk_error_code = 0;
+ gdk_error_warnings = 0;
+
+ /* Get the XdndActionList, if set */
+
+ XGetWindowProperty (GDK_WINDOW_XDISPLAY (context->source_window),
+ GDK_WINDOW_XWINDOW (context->source_window),
+ gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
+ False, XA_ATOM, &type, &format, &nitems,
+ &after, (guchar **)&data);
+
+ if (!gdk_error_code && (format == 32) && (type == XA_ATOM))
{
- if ((format == 32) && (nitems == 1))
+ context->actions = 0;
+
+ for (i=0; i<nitems; i++)
+ context->actions |= xdnd_action_from_atom (data[i]);
+
+ ((GdkDragContextPrivate *)context)->xdnd_have_actions = TRUE;
+
+#ifdef G_ENABLE_DEBUG
+ if (gdk_debug_flags & GDK_DEBUG_DND)
{
- if (*version == 3)
- retval = TRUE;
+ GString *action_str = g_string_new (NULL);
+ if (context->actions & GDK_ACTION_MOVE)
+ g_string_append(action_str, "MOVE ");
+ if (context->actions & GDK_ACTION_COPY)
+ g_string_append(action_str, "COPY ");
+ if (context->actions & GDK_ACTION_LINK)
+ g_string_append(action_str, "LINK ");
+ if (context->actions & GDK_ACTION_ASK)
+ g_string_append(action_str, "ASK ");
+
+ g_message("Xdnd actions = %s", action_str->str);
+ g_string_free (action_str, TRUE);
}
- else
- GDK_NOTE (DND,
- g_warning ("Invalid XdndAware property on window %ld\n", win));
+#endif /* G_ENABLE_DEBUG */
+
+ XFree(data);
+ }
+
+ gdk_error_warnings = old_warnings;
+ gdk_error_code = 0;
+}
+
+/* We have to make sure that the XdndActionList we keep internally
+ * is up to date with the XdndActionList on the source window
+ * because we get no notification, because Xdnd wasn't meant
+ * to continually send actions. So we select on PropertyChangeMask
+ * and add this filter.
+ */
+static GdkFilterReturn
+xdnd_source_window_filter (GdkXEvent *xev,
+ GdkEvent *event,
+ gpointer cb_data)
+{
+ XEvent *xevent = (XEvent *)xev;
+ GdkDragContext *context = cb_data;
+
+ if ((xevent->xany.type == PropertyNotify) &&
+ (xevent->xproperty.atom == gdk_atom_intern ("XdndActionList", FALSE)))
+ {
+ xdnd_read_actions (context);
- XFree (version);
+ return GDK_FILTER_REMOVE;
}
- return retval;
+ return GDK_FILTER_CONTINUE;
}
-/* Target side */
+static void
+xdnd_manage_source_filter (GdkDragContext *context,
+ GdkWindow *window,
+ gboolean add_filter)
+{
+ gint old_warnings = 0; /* quiet gcc */
+ GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+ gboolean is_foreign = (private->window_type == GDK_WINDOW_FOREIGN);
+
+ if (is_foreign)
+ {
+ old_warnings = gdk_error_warnings;
+ gdk_error_warnings = 0;
+ }
+
+ if (!private->destroyed)
+ {
+ if (add_filter)
+ {
+ gdk_window_set_events (window,
+ gdk_window_get_events (window) |
+ GDK_PROPERTY_CHANGE_MASK);
+ gdk_window_add_filter (window, xdnd_source_window_filter, context);
+
+ }
+ else
+ {
+ gdk_window_remove_filter (window,
+ xdnd_source_window_filter,
+ context);
+ /* Should we remove the GDK_PROPERTY_NOTIFY mask?
+ * but we might want it for other reasons. (Like
+ * INCR selection transactions).
+ */
+ }
+ }
+
+ if (is_foreign)
+ {
+ gdk_flush();
+ gdk_error_warnings = old_warnings;
+ }
+}
static GdkFilterReturn
xdnd_enter_filter (GdkXEvent *xev,
GdkEvent *event,
- gpointer data)
+ gpointer cb_data)
{
XEvent *xevent = (XEvent *)xev;
GdkDragContext *new_context;
gint i;
+ Atom type;
+ int format;
+ gulong nitems, after;
+ Atom *data;
+
guint32 source_window = xevent->xclient.data.l[0];
gboolean get_types = ((xevent->xclient.data.l[1] & 1) != 0);
gint version = (xevent->xclient.data.l[1] & 0xff000000) >> 24;
new_context->targets = NULL;
if (get_types)
{
- Atom type;
- int format;
- gulong nitems, after;
- Atom *data;
-
XGetWindowProperty (GDK_WINDOW_XDISPLAY (event->any.window),
source_window,
gdk_atom_intern ("XdndTypeList", FALSE), 0, 65536,
print_target_list (new_context->targets);
#endif /* G_ENABLE_DEBUG */
+ xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
+ xdnd_read_actions (new_context);
+
event->dnd.type = GDK_DRAG_ENTER;
event->dnd.context = new_context;
gdk_drag_context_ref (new_context);
event->dnd.time = time;
current_dest_drag->suggested_action = xdnd_action_from_atom (action);
+ if (!((GdkDragContextPrivate *)current_dest_drag)->xdnd_have_actions)
+ current_dest_drag->actions = current_dest_drag->suggested_action;
event->dnd.x_root = x_root;
event->dnd.y_root = y_root;
xdnd_send_leave (context);
break;
case GDK_DRAG_PROTO_ROOTWIN:
+ case GDK_DRAG_PROTO_NONE:
break;
}
GdkDragContext *
gdk_drag_begin (GdkWindow *window,
- GList *targets,
- GdkDragAction actions)
+ GList *targets)
{
GList *tmp_list;
GdkDragContext *new_context;
tmp_list = tmp_list->prev;
}
- new_context->actions = actions;
+ new_context->actions = 0;
return new_context;
}
-gboolean
+guint32
gdk_drag_get_protocol (guint32 xid,
GdkDragProtocol *protocol)
{
- if (xdnd_check_dest (xid))
+ guint32 retval;
+
+ if ((retval = xdnd_check_dest (xid)))
{
*protocol = GDK_DRAG_PROTO_XDND;
GDK_NOTE (DND, g_message ("Entering dnd window %#x\n", xid));
- return TRUE;
+ return retval;
}
- else if (motif_check_dest (xid))
+ else if ((retval = motif_check_dest (xid)))
{
*protocol = GDK_DRAG_PROTO_MOTIF;
GDK_NOTE (DND, g_message ("Entering motif window %#x\n", xid));
- return TRUE;
+ return retval;
}
else
{
if (rootwin)
{
*protocol = GDK_DRAG_PROTO_ROOTWIN;
- return TRUE;
+ return xid;
}
}
- return FALSE;
+ *protocol = GDK_DRAG_PROTO_NONE;
+ return GDK_NONE;
}
void
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
Window dest;
+ g_return_if_fail (context != NULL);
+
if (!private->window_cache)
private->window_cache = gdk_window_cache_new();
if (private->dest_xid != dest)
{
+ Window recipient;
private->dest_xid = dest;
/* Check if new destination accepts drags, and which protocol */
- if (gdk_drag_get_protocol (dest, protocol))
+ /* There is some ugliness here. We actually need to pass
+ * _three_ pieces of information to drag_motion - dest_window,
+ * protocol, and the XID of the unproxied window. The first
+ * two are passed explicitely, the third implicitly through
+ * protocol->dest_xid.
+ */
+ if ((recipient = gdk_drag_get_protocol (dest, protocol)))
{
- *dest_window = gdk_window_lookup (dest);
+ *dest_window = gdk_window_lookup (recipient);
if (*dest_window)
gdk_window_ref (*dest_window);
else
- *dest_window = gdk_window_foreign_new (dest);
+ *dest_window = gdk_window_foreign_new (recipient);
}
else
*dest_window = NULL;
GdkDragProtocol protocol,
gint x_root,
gint y_root,
- GdkDragAction action,
+ GdkDragAction suggested_action,
+ GdkDragAction possible_actions,
guint32 time)
{
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+ g_return_val_if_fail (context != NULL, FALSE);
+
+ /* When we have a Xdnd target, make sure our XdndActionList
+ * matches the current actions;
+ */
+ private->old_actions = context->actions;
+ context->actions = possible_actions;
+
+ if ((protocol == GDK_DRAG_PROTO_XDND) &&
+ (!private->xdnd_actions_set ||
+ private->xdnd_actions != possible_actions))
+ xdnd_set_actions (context);
+
if (context->dest_window != dest_window)
{
GdkEvent temp_event;
if (dest_window)
{
context->dest_window = dest_window;
+ private->drop_xid = private->dest_xid;
gdk_window_ref (context->dest_window);
context->protocol = protocol;
break;
case GDK_DRAG_PROTO_ROOTWIN:
+ case GDK_DRAG_PROTO_NONE:
break;
}
- private->old_action = action;
- context->suggested_action = action;
+ private->old_action = suggested_action;
+ context->suggested_action = suggested_action;
+ private->old_actions = possible_actions;
}
else
{
context->dest_window = NULL;
+ private->drop_xid = None;
context->action = 0;
}
else
{
private->old_action = context->suggested_action;
- context->suggested_action = action;
+ context->suggested_action = suggested_action;
}
/* Send a drag-motion event */
switch (context->protocol)
{
case GDK_DRAG_PROTO_MOTIF:
- motif_send_motion (context, x_root, y_root, action, time);
+ motif_send_motion (context, x_root, y_root, suggested_action, time);
break;
case GDK_DRAG_PROTO_XDND:
- xdnd_send_motion (context, x_root, y_root, action, time);
+ xdnd_send_motion (context, x_root, y_root, suggested_action, time);
break;
case GDK_DRAG_PROTO_ROOTWIN:
gdk_event_put (&temp_event);
}
break;
+ case GDK_DRAG_PROTO_NONE:
+ g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
+ break;
}
}
else
gdk_drag_drop (GdkDragContext *context,
guint32 time)
{
+ g_return_if_fail (context != NULL);
+
if (context->dest_window)
{
switch (context->protocol)
case GDK_DRAG_PROTO_ROOTWIN:
g_warning ("Drops for GDK_DRAG_PROTO_ROOTWIN must be handled internally");
break;
+ case GDK_DRAG_PROTO_NONE:
+ g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
+ break;
}
}
}
gdk_drag_abort (GdkDragContext *context,
guint32 time)
{
+ g_return_if_fail (context != NULL);
+
gdk_drag_do_leave (context, time);
}
GdkDragContextPrivate *private;
XEvent xev;
- g_return_if_fail (context != 0);
+ g_return_if_fail (context != NULL);
private = (GdkDragContextPrivate *)context;
if (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT)
{
- xev.xclient.data.b[0] = XmOPERATION_CHANGED | 0x80;
+ MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED | 0x80;
}
else
{
if ((action != 0) != (private->old_action != 0))
{
if (action != 0)
- xev.xclient.data.b[0] = XmDROP_SITE_ENTER | 0x80;
+ MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_ENTER | 0x80;
else
- xev.xclient.data.b[0] = XmDROP_SITE_LEAVE | 0x80;
+ MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_LEAVE | 0x80;
}
else
- xev.xclient.data.b[0] = XmDRAG_MOTION | 0x80;
+ MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION | 0x80;
}
- xev.xclient.data.b[1] = local_byte_order;
+ MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
switch (action)
{
case GDK_ACTION_MOVE:
- xev.xclient.data.s[1] = XmDROP_MOVE;
+ MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_MOVE;
break;
case GDK_ACTION_COPY:
- xev.xclient.data.s[1] = XmDROP_COPY;
+ MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY;
break;
case GDK_ACTION_LINK:
- xev.xclient.data.s[1] = XmDROP_LINK;
+ MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_LINK;
break;
default:
- xev.xclient.data.s[1] = XmDROP_NOOP;
+ MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP;
break;
}
if (action)
- xev.xclient.data.s[1] |= (XmDROP_SITE_VALID << 4);
+ MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmDROP_SITE_VALID << 4);
else
- xev.xclient.data.s[1] |= (XmNO_DROP_SITE << 4);
+ MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmNO_DROP_SITE << 4);
- xev.xclient.data.l[1] = time;
- xev.xclient.data.s[4] = private->last_x;
- xev.xclient.data.s[5] = private->last_y;
+ MOTIF_XCLIENT_LONG (&xev, 1) = time;
+ MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
+ MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->source_window),
FALSE, 0, &xev))
xev.xclient.data.l[3] = 0;
xev.xclient.data.l[4] = xdnd_action_to_atom (action);
- if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->source_window),
- FALSE, 0, &xev))
+ if (!xdnd_send_xevent (GDK_WINDOW_XWINDOW (context->source_window),
+ FALSE, &xev))
GDK_NOTE (DND,
g_message ("Send event to %lx failed",
GDK_WINDOW_XWINDOW (context->source_window)));
{
GdkDragContextPrivate *private;
- g_return_if_fail (context != 0);
+ g_return_if_fail (context != NULL);
private = (GdkDragContextPrivate *)context;
xev.xclient.message_type = gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE);
xev.xclient.format = 8;
- xev.xclient.data.b[0] = XmDROP_START | 0x80;
- xev.xclient.data.b[1] = local_byte_order;
+ MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START | 0x80;
+ MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
if (ok)
- xev.xclient.data.s[2] = XmDROP_COPY |
- (XmDROP_SITE_VALID << 4) |
- (XmDROP_NOOP << 8) |
- (XmDROP << 12);
+ MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY |
+ (XmDROP_SITE_VALID << 4) |
+ (XmDROP_NOOP << 8) |
+ (XmDROP << 12);
else
- xev.xclient.data.s[2] = XmDROP_NOOP |
- (XmNO_DROP_SITE << 4) |
- (XmDROP_NOOP << 8) |
- (XmDROP_CANCEL << 12);
- xev.xclient.data.s[2] = private->last_x;
- xev.xclient.data.s[3] = private->last_y;
+ MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP |
+ (XmNO_DROP_SITE << 4) |
+ (XmDROP_NOOP << 8) |
+ (XmDROP_CANCEL << 12);
+ MOTIF_XCLIENT_SHORT (&xev, 2) = private->last_x;
+ MOTIF_XCLIENT_SHORT (&xev, 3) = private->last_y;
gdk_send_xevent (GDK_WINDOW_XWINDOW (context->source_window),
FALSE, 0, &xev);
gboolean success,
guint32 time)
{
+ g_return_if_fail (context != NULL);
+
if (context->protocol == GDK_DRAG_PROTO_XDND)
{
XEvent xev;
xev.xclient.data.l[3] = 0;
xev.xclient.data.l[4] = 0;
- if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->source_window),
- FALSE, 0, &xev))
+ if (!xdnd_send_xevent (GDK_WINDOW_XWINDOW (context->source_window),
+ FALSE, &xev))
GDK_NOTE (DND,
g_message ("Send event to %lx failed",
GDK_WINDOW_XWINDOW (context->source_window)));
void
gdk_window_register_dnd (GdkWindow *window)
{
- static guint32 xdnd_version = 3;
-
+ static gulong xdnd_version = 3;
MotifDragReceiverInfo info;
+ g_return_if_fail (window != NULL);
+
/* Set Motif drag receiver information property */
if (!motif_drag_receiver_info_atom)
GDK_WINDOW_XWINDOW (window),
xdnd_aware_atom, XA_ATOM,
32, PropModeReplace,
- (guchar *)&xdnd_version,
- sizeof (xdnd_version));
+ (guchar *)&xdnd_version, 1);
}
/*************************************************************