However, dragging contents from Emacs is implemented entirely in C.
X Windows has several competing drag-and-drop protocols, of which
Emacs supports two: the XDND protocol (see
- https://freedesktop.org/wiki/Specifications/XDND) and the Motif drop
- protocol. These protocols are based on the initiator owning a
- special selection, specifying an action the recipient should
- perform, grabbing the mouse, and sending various different client
- messages to the toplevel window underneath the mouse as it moves, or
- when buttons are released.
+ https://freedesktop.org/wiki/Specifications/XDND) and the Motif drag
+ and drop protocols. These protocols are based on the initiator
+ owning a special selection, specifying an action the recipient
+ should perform, grabbing the mouse, and sending various different
+ client messages to the toplevel window underneath the mouse as it
+ moves, or when buttons are released.
The Lisp interface to drag-and-drop is synchronous, and involves
running a nested event loop with some global state until the drag
or XmTRANSFER_FAILURE. */
static int x_dnd_waiting_for_motif_finish;
static bool x_dnd_xm_use_help;
+static bool x_dnd_motif_setup_p;
static Window x_dnd_pending_finish_target;
static int x_dnd_waiting_for_finish_proto;
static bool x_dnd_allow_current_frame;
static Window x_dnd_last_seen_window;
static Window x_dnd_end_window;
static int x_dnd_last_protocol_version;
+static int x_dnd_last_motif_style;
static Time x_dnd_selection_timestamp;
static Window x_dnd_mouse_rect_target;
unsigned long wm_state;
struct x_client_list_window *next;
+ uint8_t xm_protocol_style;
#ifdef HAVE_XSHAPE
int border_width;
/* CARD32 */ uint32_t unspecified3;
} xm_drag_receiver_info;
+typedef struct xm_top_level_enter_message
+{
+ /* BYTE */ uint8_t reason;
+ /* BYTE */ uint8_t byteorder;
+
+ /* CARD16 */ uint16_t zero;
+ /* CARD32 */ uint32_t timestamp;
+ /* CARD32 */ uint32_t source_window;
+ /* CARD32 */ uint32_t index_atom;
+} xm_top_level_enter_message;
+
+typedef struct xm_drag_motion_message
+{
+ /* BYTE */ uint8_t reason;
+ /* BYTE */ uint8_t byteorder;
+
+ /* CARD16 */ uint16_t side_effects;
+ /* CARD32 */ uint32_t timestamp;
+ /* CARD16 */ uint16_t x, y;
+} xm_drag_motion_message;
+
+typedef struct xm_top_level_leave_message
+{
+ /* BYTE */ uint8_t reason;
+ /* BYTE */ uint8_t byteorder;
+
+ /* CARD16 */ uint16_t zero;
+ /* CARD32 */ uint32_t timestamp;
+ /* CARD32 */ uint32_t source_window;
+} xm_top_level_leave_message;
+
#define XM_DRAG_SIDE_EFFECT(op, site, ops, act) \
((op) | ((site) << 4) | ((ops) << 8) | ((act) << 12))
#define XM_DRAG_REASON_CODE(reason) ((reason) & 0x7f)
#define XM_DRAG_REASON_DROP_START 5
+#define XM_DRAG_REASON_TOP_LEVEL_ENTER 0
+#define XM_DRAG_REASON_TOP_LEVEL_LEAVE 1
+#define XM_DRAG_REASON_DRAG_MOTION 2
#define XM_DRAG_ORIGINATOR_INITIATOR 0
#define XM_DRAG_ORIGINATOR_RECEIVER 1
-#define XM_DRAG_STYLE_NONE 0
+#define XM_DRAG_STYLE_NONE 0
+
+#define XM_DRAG_STYLE_DROP_ONLY 1
+#define XM_DRAG_STYLE_DROP_ONLY_REC 3
+
+#define XM_DRAG_STYLE_DYNAMIC 5
+#define XM_DRAG_STYLE_DYNAMIC_REC 2
+#define XM_DRAG_STYLE_DYNAMIC_REC1 4
+
+#define XM_DRAG_STYLE_IS_DROP_ONLY(n) ((n) == XM_DRAG_STYLE_DROP_ONLY \
+ || (n) == XM_DRAG_STYLE_DROP_ONLY_REC)
+#define XM_DRAG_STYLE_IS_DYNAMIC(n) ((n) == XM_DRAG_STYLE_DYNAMIC \
+ || (n) == XM_DRAG_STYLE_DYNAMIC_REC \
+ || (n) == XM_DRAG_STYLE_DYNAMIC_REC1)
#define XM_DROP_SITE_VALID 3
/* #define XM_DROP_SITE_INVALID 2 */
return idx;
}
+static void
+xm_setup_drag_info (struct x_display_info *dpyinfo,
+ struct frame *source_frame)
+{
+ xm_drag_initiator_info drag_initiator_info;
+ int idx;
+
+ idx = xm_setup_dnd_targets (dpyinfo, x_dnd_targets,
+ x_dnd_n_targets);
+
+ if (idx != -1)
+ {
+ drag_initiator_info.byteorder = XM_TARGETS_TABLE_CUR;
+ drag_initiator_info.protocol = 0;
+ drag_initiator_info.table_index = idx;
+ drag_initiator_info.selection = dpyinfo->Xatom_XdndSelection;
+
+ xm_write_drag_initiator_info (dpyinfo->display, FRAME_X_WINDOW (source_frame),
+ dpyinfo->Xatom_XdndSelection,
+ dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO,
+ &drag_initiator_info);
+
+ x_dnd_motif_setup_p = true;
+ }
+}
+
static void
xm_send_drop_message (struct x_display_info *dpyinfo, Window source,
Window target, xm_drop_start_message *dmsg)
x_uncatch_errors ();
}
+static void
+xm_send_top_level_enter_message (struct x_display_info *dpyinfo, Window source,
+ Window target, xm_top_level_enter_message *dmsg)
+{
+ XEvent msg;
+
+ msg.xclient.type = ClientMessage;
+ msg.xclient.message_type
+ = dpyinfo->Xatom_MOTIF_DRAG_AND_DROP_MESSAGE;
+ msg.xclient.format = 8;
+ msg.xclient.window = target;
+ msg.xclient.data.b[0] = dmsg->reason;
+ msg.xclient.data.b[1] = dmsg->byteorder;
+ *((uint16_t *) &msg.xclient.data.b[2]) = dmsg->zero;
+ *((uint32_t *) &msg.xclient.data.b[4]) = dmsg->timestamp;
+ *((uint32_t *) &msg.xclient.data.b[8]) = dmsg->source_window;
+ *((uint32_t *) &msg.xclient.data.b[12]) = dmsg->index_atom;
+ msg.xclient.data.b[16] = 0;
+ msg.xclient.data.b[17] = 0;
+ msg.xclient.data.b[18] = 0;
+ msg.xclient.data.b[19] = 0;
+
+ x_catch_errors (dpyinfo->display);
+ XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
+ x_uncatch_errors ();
+}
+
+static void
+xm_send_drag_motion_message (struct x_display_info *dpyinfo, Window source,
+ Window target, xm_drag_motion_message *dmsg)
+{
+ XEvent msg;
+
+ msg.xclient.type = ClientMessage;
+ msg.xclient.message_type
+ = dpyinfo->Xatom_MOTIF_DRAG_AND_DROP_MESSAGE;
+ msg.xclient.format = 8;
+ msg.xclient.window = target;
+ msg.xclient.data.b[0] = dmsg->reason;
+ msg.xclient.data.b[1] = dmsg->byteorder;
+ *((uint16_t *) &msg.xclient.data.b[2]) = dmsg->side_effects;
+ *((uint32_t *) &msg.xclient.data.b[4]) = dmsg->timestamp;
+ *((uint16_t *) &msg.xclient.data.b[8]) = dmsg->x;
+ *((uint16_t *) &msg.xclient.data.b[10]) = dmsg->y;
+ msg.xclient.data.b[12] = 0;
+ msg.xclient.data.b[13] = 0;
+ msg.xclient.data.b[14] = 0;
+ msg.xclient.data.b[15] = 0;
+ msg.xclient.data.b[16] = 0;
+ msg.xclient.data.b[17] = 0;
+ msg.xclient.data.b[18] = 0;
+ msg.xclient.data.b[19] = 0;
+
+ x_catch_errors (dpyinfo->display);
+ XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
+ x_uncatch_errors ();
+}
+
+static void
+xm_send_top_level_leave_message (struct x_display_info *dpyinfo, Window source,
+ Window target, xm_top_level_leave_message *dmsg)
+{
+ XEvent msg;
+
+ msg.xclient.type = ClientMessage;
+ msg.xclient.message_type
+ = dpyinfo->Xatom_MOTIF_DRAG_AND_DROP_MESSAGE;
+ msg.xclient.format = 8;
+ msg.xclient.window = target;
+ msg.xclient.data.b[0] = dmsg->reason;
+ msg.xclient.data.b[1] = dmsg->byteorder;
+ *((uint16_t *) &msg.xclient.data.b[2]) = dmsg->zero;
+ *((uint32_t *) &msg.xclient.data.b[4]) = dmsg->timestamp;
+ *((uint32_t *) &msg.xclient.data.b[8]) = dmsg->source_window;
+ msg.xclient.data.b[12] = 0;
+ msg.xclient.data.b[13] = 0;
+ msg.xclient.data.b[14] = 0;
+ msg.xclient.data.b[15] = 0;
+ msg.xclient.data.b[16] = 0;
+ msg.xclient.data.b[17] = 0;
+ msg.xclient.data.b[18] = 0;
+ msg.xclient.data.b[19] = 0;
+
+ x_catch_errors (dpyinfo->display);
+ XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
+ x_uncatch_errors ();
+}
+
static int
xm_read_drop_start_reply (const XEvent *msg, xm_drop_start_reply *reply)
{
unsigned char *wmstate_data = NULL;
XWindowAttributes attrs;
Window child;
+ xm_drag_receiver_info xm_info;
#else
uint32_t *wmstate;
+ uint8_t *xmdata;
xcb_get_window_attributes_cookie_t *window_attribute_cookies;
xcb_translate_coordinates_cookie_t *translate_coordinate_cookies;
xcb_get_property_cookie_t *get_property_cookies;
+ xcb_get_property_cookie_t *xm_property_cookies;
xcb_get_geometry_cookie_t *get_geometry_cookies;
xcb_get_window_attributes_reply_t attrs, *attrs_reply;
xcb_translate_coordinates_reply_t *coordinates_reply;
xcb_get_property_reply_t *property_reply;
+ xcb_get_property_reply_t *xm_property_reply;
xcb_get_geometry_reply_t *geometry_reply;
xcb_generic_error_t *error;
#endif
= alloca (sizeof *translate_coordinate_cookies * nitems);
get_property_cookies
= alloca (sizeof *get_property_cookies * nitems);
+ xm_property_cookies
+ = alloca (sizeof *xm_property_cookies * nitems);
get_geometry_cookies
= alloca (sizeof *get_geometry_cookies * nitems);
= xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) toplevels[i],
(xcb_atom_t) dpyinfo->Xatom_wm_state, XCB_ATOM_ANY,
0, 2);
+ xm_property_cookies[i]
+ = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) toplevels[i],
+ (xcb_atom_t) dpyinfo->Xatom_MOTIF_DRAG_RECEIVER_INFO,
+ (xcb_atom_t) dpyinfo->Xatom_MOTIF_DRAG_RECEIVER_INFO,
+ 0, 4);
get_geometry_cookies[i]
= xcb_get_geometry (dpyinfo->xcb_connection, (xcb_window_t) toplevels[i]);
free (error);
}
+ xm_property_reply = xcb_get_property_reply (dpyinfo->xcb_connection,
+ xm_property_cookies[i],
+ &error);
+
+ if (!xm_property_reply)
+ free (error);
+
if (property_reply
&& (xcb_get_property_value_length (property_reply) != 8
|| property_reply->format != 32))
tem->next = x_dnd_toplevels;
tem->previous_event_mask = attrs.your_event_mask;
tem->wm_state = wmstate[0];
+ tem->xm_protocol_style = XM_DRAG_STYLE_NONE;
+
+#ifndef USE_XCB
+ if (!xm_read_drag_receiver_info (dpyinfo, toplevels[i], &xm_info))
+ tem->xm_protocol_style = xm_info.protocol_style;
+#else
+ if (xm_property_reply
+ && xm_property_reply->format == 8
+ && xm_property_reply->type == dpyinfo->Xatom_MOTIF_DRAG_RECEIVER_INFO
+ && xcb_get_property_value_length (xm_property_reply) >= 4)
+ {
+ xmdata = xcb_get_property_value (xm_property_reply);
+ tem->xm_protocol_style = xmdata[2];
+ }
+#endif
#ifdef HAVE_XSHAPE
#ifndef USE_XCB
if (property_reply)
free (property_reply);
+ if (xm_property_reply)
+ free (xm_property_reply);
+
if (geometry_reply)
free (geometry_reply);
#endif
static Window
x_dnd_get_target_window_1 (struct x_display_info *dpyinfo,
- int root_x, int root_y)
+ int root_x, int root_y, int *motif_out)
{
- struct x_client_list_window *tem;
+ struct x_client_list_window *tem, *chosen = NULL;
/* Loop through x_dnd_toplevels until we find the toplevel where
root_x and root_y are. */
#ifdef HAVE_XSHAPE
if (tem->n_bounding_rects == -1)
#endif
- return tem->window;
+ {
+ chosen = tem;
+ break;
+ }
#ifdef HAVE_XSHAPE
if (x_dnd_get_target_window_2 (tem->bounding_rects,
tem->n_input_rects,
tem->border_width + root_x - tem->x,
tem->border_width + root_y - tem->y))
- return tem->window;
+ {
+ chosen = tem;
+ break;
+ }
}
#endif
}
}
+ if (chosen)
+ {
+ *motif_out = chosen->xm_protocol_style;
+ return chosen->window;
+ }
+ else
+ *motif_out = XM_DRAG_STYLE_NONE;
+
return None;
}
static Window
x_dnd_get_target_window (struct x_display_info *dpyinfo,
- int root_x, int root_y, int *proto_out)
+ int root_x, int root_y, int *proto_out,
+ int *motif_out)
{
Window child_return, child, dummy, proxy;
int dest_x_return, dest_y_return, rc, proto;
dest_y_return = root_y;
proto = -1;
+ *motif_out = XM_DRAG_STYLE_NONE;
if (x_dnd_use_toplevels)
{
- child = x_dnd_get_target_window_1 (dpyinfo, root_x, root_y);
+ child = x_dnd_get_target_window_1 (dpyinfo, root_x,
+ root_y, motif_out);
+
+ if (!x_dnd_allow_current_frame
+ && FRAME_X_WINDOW (x_dnd_frame) == child)
+ *motif_out = XM_DRAG_STYLE_NONE;
if (child != None)
{
x_dnd_cleanup_drag_and_drop (void *frame)
{
struct frame *f = frame;
+ xm_drop_start_message dmsg;
if (!x_dnd_unwind_flag)
return;
&& x_dnd_last_protocol_version != -1)
x_dnd_send_leave (x_dnd_frame,
x_dnd_last_seen_window);
+ else if (x_dnd_last_seen_window != None
+ && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
+ && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
+ && x_dnd_motif_setup_p)
+ {
+ dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_DROP_START);
+ dmsg.byte_order = XM_TARGETS_TABLE_CUR;
+ dmsg.timestamp = 0;
+ dmsg.side_effects
+ = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
+ x_dnd_wanted_action),
+ XM_DROP_SITE_VALID,
+ xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
+ x_dnd_wanted_action),
+ XM_DROP_ACTION_DROP_CANCEL);
+ dmsg.x = 0;
+ dmsg.y = 0;
+ dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
+ dmsg.source_window = FRAME_X_WINDOW (f);
+
+ xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
+ x_dnd_last_seen_window, &dmsg);
+ }
unblock_input ();
x_dnd_end_window = x_dnd_last_seen_window;
specpdl_ref ref;
ptrdiff_t i, end, fill;
XTextProperty prop;
+ xm_drop_start_message dmsg;
if (!FRAME_VISIBLE_P (f))
error ("Frame is invisible");
x_dnd_frame = f;
x_dnd_last_seen_window = None;
x_dnd_last_protocol_version = -1;
+ x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
x_dnd_mouse_rect_target = None;
x_dnd_action = None;
x_dnd_wanted_action = xaction;
x_dnd_waiting_for_finish = false;
x_dnd_waiting_for_motif_finish = 0;
x_dnd_xm_use_help = false;
+ x_dnd_motif_setup_p = false;
x_dnd_end_window = None;
x_dnd_use_toplevels
= x_wm_supports (f, FRAME_DISPLAY_INFO (f)->Xatom_net_client_list_stacking);
if (x_dnd_last_seen_window != None
&& x_dnd_last_protocol_version != -1)
x_dnd_send_leave (f, x_dnd_last_seen_window);
+ else if (x_dnd_last_seen_window != None
+ && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
+ && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
+ && x_dnd_motif_setup_p)
+ {
+ dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_DROP_START);
+ dmsg.byte_order = XM_TARGETS_TABLE_CUR;
+ dmsg.timestamp = hold_quit.timestamp;
+ dmsg.side_effects
+ = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
+ x_dnd_wanted_action),
+ XM_DROP_SITE_VALID,
+ xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
+ x_dnd_wanted_action),
+ XM_DROP_ACTION_DROP_CANCEL);
+ dmsg.x = 0;
+ dmsg.y = 0;
+ dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
+ dmsg.source_window = FRAME_X_WINDOW (f);
+
+ xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
+ x_dnd_last_seen_window, &dmsg);
+ }
x_dnd_end_window = x_dnd_last_seen_window;
x_dnd_last_seen_window = None;
/* Get the window underneath the pointer, see if it moved, and update
the DND state accordingly. */
static void
-x_dnd_update_state (struct x_display_info *dpyinfo)
+x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
{
- int root_x, root_y, dummy_x, dummy_y, target_proto;
+ int root_x, root_y, dummy_x, dummy_y, target_proto, motif_style;
unsigned int dummy_mask;
Window dummy, dummy_child, target;
+ xm_top_level_leave_message lmsg;
+ xm_top_level_enter_message emsg;
+ xm_drag_motion_message dmsg;
+ xm_drop_start_message dsmsg;
if (XQueryPointer (dpyinfo->display,
dpyinfo->root_window,
&dummy_mask))
{
target = x_dnd_get_target_window (dpyinfo, root_x,
- root_y, &target_proto);
+ root_y, &target_proto,
+ &motif_style);
if (target != x_dnd_last_seen_window)
{
&& x_dnd_last_protocol_version != -1
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
+ else if (x_dnd_last_seen_window != None
+ && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
+ {
+ if (!x_dnd_motif_setup_p)
+ xm_setup_drag_info (dpyinfo, x_dnd_frame);
+
+ lmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_TOP_LEVEL_LEAVE);
+ lmsg.byteorder = XM_TARGETS_TABLE_CUR;
+ lmsg.zero = 0;
+ lmsg.timestamp = timestamp;
+ lmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
+
+ if (x_dnd_motif_setup_p)
+ xm_send_top_level_leave_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
+ x_dnd_last_seen_window, &lmsg);
+ }
if (target != FRAME_OUTER_WINDOW (x_dnd_frame)
&& x_dnd_return_frame == 1)
x_dnd_action = None;
x_dnd_last_seen_window = target;
x_dnd_last_protocol_version = target_proto;
+ x_dnd_last_motif_style = motif_style;
if (target != None && x_dnd_last_protocol_version != -1)
x_dnd_send_enter (x_dnd_frame, target,
x_dnd_last_protocol_version);
+ else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style))
+ {
+ if (!x_dnd_motif_setup_p)
+ xm_setup_drag_info (dpyinfo, x_dnd_frame);
+
+ emsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_TOP_LEVEL_ENTER);
+ emsg.byteorder = XM_TARGETS_TABLE_CUR;
+ emsg.zero = 0;
+ emsg.timestamp = timestamp;
+ emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
+ emsg.index_atom = dpyinfo->Xatom_XdndSelection;
+
+ if (x_dnd_motif_setup_p)
+ xm_send_top_level_enter_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
+ target, &emsg);
+ }
}
if (x_dnd_last_protocol_version != -1 && target != None)
root_x, root_y,
x_dnd_selection_timestamp,
x_dnd_wanted_action);
+ else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None)
+ {
+ if (!x_dnd_motif_setup_p)
+ xm_setup_drag_info (dpyinfo, x_dnd_frame);
+
+ dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_DRAG_MOTION);
+ dmsg.byteorder = XM_TARGETS_TABLE_CUR;
+ dmsg.side_effects
+ = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
+ x_dnd_wanted_action),
+ XM_DROP_SITE_VALID,
+ xm_side_effect_from_action (dpyinfo,
+ x_dnd_wanted_action),
+ (!x_dnd_xm_use_help
+ ? XM_DROP_ACTION_DROP
+ : XM_DROP_ACTION_DROP_HELP));
+ dmsg.timestamp = timestamp;
+ dmsg.x = root_x;
+ dmsg.y = root_y;
+
+ if (x_dnd_motif_setup_p)
+ xm_send_drag_motion_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
+ target, &dmsg);
+ }
}
/* The pointer moved out of the screen. */
else if (x_dnd_last_protocol_version != -1)
&& x_dnd_last_protocol_version != -1)
x_dnd_send_leave (x_dnd_frame,
x_dnd_last_seen_window);
+ else if (x_dnd_last_seen_window != None
+ && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
+ && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
+ && x_dnd_motif_setup_p)
+ {
+ dsmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_DROP_START);
+ dmsg.byteorder = XM_TARGETS_TABLE_CUR;
+ dsmsg.timestamp = timestamp;
+ dsmsg.side_effects
+ = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
+ x_dnd_wanted_action),
+ XM_DROP_SITE_VALID,
+ xm_side_effect_from_action (dpyinfo,
+ x_dnd_wanted_action),
+ XM_DROP_ACTION_DROP_CANCEL);
+ dsmsg.x = 0;
+ dsmsg.y = 0;
+ dsmsg.index_atom
+ = FRAME_DISPLAY_INFO (x_dnd_frame)->Xatom_XdndSelection;
+ dsmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
+
+ xm_send_drop_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
+ x_dnd_last_seen_window, &dsmsg);
+ }
x_dnd_end_window = x_dnd_last_seen_window;
x_dnd_last_seen_window = None;
x_uncatch_errors_after_check ();
}
- x_dnd_update_state (dpyinfo);
+ x_dnd_update_state (dpyinfo, event->xproperty.time);
break;
}
}
}
}
- x_dnd_update_state (dpyinfo);
+ x_dnd_update_state (dpyinfo, event->xproperty.time);
}
x_handle_property_notify (&event->xproperty);
#endif
if (x_dnd_in_progress)
- x_dnd_update_state (dpyinfo);
+ x_dnd_update_state (dpyinfo, 0);
if (x_dnd_in_progress && x_dnd_use_toplevels
&& dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
&& dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
{
Window target;
- int target_proto;
+ int target_proto, motif_style;
+ xm_top_level_leave_message lmsg;
+ xm_top_level_enter_message emsg;
+ xm_drag_motion_message dmsg;
/* Sometimes the drag-and-drop operation starts with the
pointer of a frame invisible due to input. Since
target = x_dnd_get_target_window (dpyinfo,
event->xmotion.x_root,
event->xmotion.y_root,
- &target_proto);
+ &target_proto,
+ &motif_style);
if (target != x_dnd_last_seen_window)
{
&& x_dnd_last_protocol_version != -1
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
+ else if (x_dnd_last_seen_window != None
+ && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
+ {
+ if (!x_dnd_motif_setup_p)
+ xm_setup_drag_info (dpyinfo, x_dnd_frame);
+
+ lmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_TOP_LEVEL_LEAVE);
+ lmsg.byteorder = XM_TARGETS_TABLE_CUR;
+ lmsg.zero = 0;
+ lmsg.timestamp = event->xbutton.time;
+ lmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
+
+ if (x_dnd_motif_setup_p)
+ xm_send_top_level_leave_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
+ x_dnd_last_seen_window, &lmsg);
+ }
if (target != FRAME_OUTER_WINDOW (x_dnd_frame)
&& x_dnd_return_frame == 1)
x_dnd_action = None;
x_dnd_last_seen_window = target;
x_dnd_last_protocol_version = target_proto;
+ x_dnd_last_motif_style = motif_style;
if (target != None && x_dnd_last_protocol_version != -1)
x_dnd_send_enter (x_dnd_frame, target,
x_dnd_last_protocol_version);
+ else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style))
+ {
+ if (!x_dnd_motif_setup_p)
+ xm_setup_drag_info (dpyinfo, x_dnd_frame);
+
+ emsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_TOP_LEVEL_ENTER);
+ emsg.byteorder = XM_TARGETS_TABLE_CUR;
+ emsg.zero = 0;
+ emsg.timestamp = event->xbutton.time;
+ emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
+ emsg.index_atom = dpyinfo->Xatom_XdndSelection;
+
+ if (x_dnd_motif_setup_p)
+ xm_send_top_level_enter_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
+ target, &emsg);
+ }
}
if (x_dnd_last_protocol_version != -1 && target != None)
event->xmotion.y_root,
x_dnd_selection_timestamp,
x_dnd_wanted_action);
+ else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None)
+ {
+ if (!x_dnd_motif_setup_p)
+ xm_setup_drag_info (dpyinfo, x_dnd_frame);
+
+ dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_DRAG_MOTION);
+ dmsg.byteorder = XM_TARGETS_TABLE_CUR;
+ dmsg.side_effects = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
+ x_dnd_wanted_action),
+ XM_DROP_SITE_VALID,
+ xm_side_effect_from_action (dpyinfo,
+ x_dnd_wanted_action),
+ (!x_dnd_xm_use_help
+ ? XM_DROP_ACTION_DROP
+ : XM_DROP_ACTION_DROP_HELP));
+ dmsg.timestamp = event->xbutton.time;
+ dmsg.x = event->xmotion.x_root;
+ dmsg.y = event->xmotion.y_root;
+
+ if (x_dnd_motif_setup_p)
+ xm_send_drag_motion_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
+ target, &dmsg);
+ }
goto OTHER;
}
}
if (x_dnd_in_progress)
- x_dnd_update_state (dpyinfo);
+ x_dnd_update_state (dpyinfo, 0);
goto OTHER;
case ButtonRelease:
}
else if (x_dnd_last_seen_window != None)
{
- xm_drag_receiver_info drag_receiver_info;
- xm_drag_initiator_info drag_initiator_info;
xm_drop_start_message dmsg;
- int idx;
+ xm_drag_receiver_info drag_receiver_info;
if (!xm_read_drag_receiver_info (dpyinfo, x_dnd_last_seen_window,
&drag_receiver_info)
&& drag_receiver_info.protocol_style != XM_DRAG_STYLE_NONE
&& (x_dnd_allow_current_frame
- || FRAME_OUTER_WINDOW (x_dnd_frame) != x_dnd_last_seen_window))
+ || x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)))
{
- idx = xm_setup_dnd_targets (dpyinfo, x_dnd_targets,
- x_dnd_n_targets);
+ if (!x_dnd_motif_setup_p)
+ xm_setup_drag_info (dpyinfo, x_dnd_frame);
- if (idx != -1)
+ if (x_dnd_motif_setup_p)
{
- drag_initiator_info.byteorder = XM_TARGETS_TABLE_CUR;
- drag_initiator_info.protocol = 0;
- drag_initiator_info.table_index = idx;
- drag_initiator_info.selection = dpyinfo->Xatom_XdndSelection;
-
memset (&dmsg, 0, sizeof dmsg);
- xm_write_drag_initiator_info (dpyinfo->display,
- FRAME_X_WINDOW (x_dnd_frame),
- dpyinfo->Xatom_XdndSelection,
- dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO,
- &drag_initiator_info);
-
dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
XM_DRAG_REASON_DROP_START);
dmsg.byte_order = XM_TARGETS_TABLE_CUR;
}
x_dnd_last_protocol_version = -1;
+ x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
x_dnd_last_seen_window = None;
x_dnd_frame = NULL;
x_set_dnd_targets (NULL, 0);
case CirculateNotify:
if (x_dnd_in_progress)
- x_dnd_update_state (dpyinfo);
+ x_dnd_update_state (dpyinfo, 0);
goto OTHER;
case CirculateRequest:
#endif
/* A fake XMotionEvent for x_note_mouse_movement. */
XMotionEvent ev;
+ xm_top_level_leave_message lmsg;
+ xm_top_level_enter_message emsg;
+ xm_drag_motion_message dmsg;
+
#ifdef HAVE_XINPUT2_1
states = &xev->valuators;
&& dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
{
Window target;
- int target_proto;
+ int target_proto, motif_style;
/* Sometimes the drag-and-drop operation starts with the
pointer of a frame invisible due to input. Since
target = x_dnd_get_target_window (dpyinfo,
xev->root_x,
xev->root_y,
- &target_proto);
+ &target_proto,
+ &motif_style);
if (target != x_dnd_last_seen_window)
{
&& x_dnd_last_protocol_version != -1
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
+ else if (x_dnd_last_seen_window != None
+ && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
+ {
+ if (!x_dnd_motif_setup_p)
+ xm_setup_drag_info (dpyinfo, x_dnd_frame);
+
+ lmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_TOP_LEVEL_LEAVE);
+ lmsg.byteorder = XM_TARGETS_TABLE_CUR;
+ lmsg.zero = 0;
+ lmsg.timestamp = xev->time;
+ lmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
+
+ if (x_dnd_motif_setup_p)
+ xm_send_top_level_leave_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
+ x_dnd_last_seen_window, &lmsg);
+ }
if (target != FRAME_OUTER_WINDOW (x_dnd_frame)
&& x_dnd_return_frame == 1)
x_dnd_action = None;
x_dnd_last_seen_window = target;
x_dnd_last_protocol_version = target_proto;
+ x_dnd_last_motif_style = motif_style;
if (target != None && x_dnd_last_protocol_version != -1)
x_dnd_send_enter (x_dnd_frame, target,
x_dnd_last_protocol_version);
+ else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style))
+ {
+ if (!x_dnd_motif_setup_p)
+ xm_setup_drag_info (dpyinfo, x_dnd_frame);
+
+ emsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_TOP_LEVEL_ENTER);
+ emsg.byteorder = XM_TARGETS_TABLE_CUR;
+ emsg.zero = 0;
+ emsg.timestamp = xev->time;
+ emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
+ emsg.index_atom = dpyinfo->Xatom_XdndSelection;
+
+ if (x_dnd_motif_setup_p)
+ xm_send_top_level_enter_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
+ target, &emsg);
+ }
}
if (x_dnd_last_protocol_version != -1 && target != None)
xev->root_x, xev->root_y,
x_dnd_selection_timestamp,
x_dnd_wanted_action);
+ else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None)
+ {
+ if (!x_dnd_motif_setup_p)
+ xm_setup_drag_info (dpyinfo, x_dnd_frame);
+
+ dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_DRAG_MOTION);
+ dmsg.byteorder = XM_TARGETS_TABLE_CUR;
+ dmsg.side_effects
+ = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
+ x_dnd_wanted_action),
+ XM_DROP_SITE_VALID,
+ xm_side_effect_from_action (dpyinfo,
+ x_dnd_wanted_action),
+ (!x_dnd_xm_use_help
+ ? XM_DROP_ACTION_DROP
+ : XM_DROP_ACTION_DROP_HELP));
+ dmsg.timestamp = xev->time;
+ dmsg.x = lrint (xev->root_x);
+ dmsg.y = lrint (xev->root_y);
+
+ if (x_dnd_motif_setup_p)
+ xm_send_drag_motion_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
+ target, &dmsg);
+ }
goto XI_OTHER;
}
}
else if (x_dnd_last_seen_window != None)
{
- xm_drag_receiver_info drag_receiver_info;
- xm_drag_initiator_info drag_initiator_info;
xm_drop_start_message dmsg;
- int idx;
+ xm_drag_receiver_info drag_receiver_info;
if (!xm_read_drag_receiver_info (dpyinfo, x_dnd_last_seen_window,
&drag_receiver_info)
&& drag_receiver_info.protocol_style != XM_DRAG_STYLE_NONE
&& (x_dnd_allow_current_frame
- || FRAME_OUTER_WINDOW (x_dnd_frame) != x_dnd_last_seen_window))
+ || x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)))
{
- idx = xm_setup_dnd_targets (dpyinfo, x_dnd_targets,
- x_dnd_n_targets);
+ if (!x_dnd_motif_setup_p)
+ xm_setup_drag_info (dpyinfo, x_dnd_frame);
- if (idx != -1)
+ if (x_dnd_motif_setup_p)
{
- drag_initiator_info.byteorder = XM_TARGETS_TABLE_CUR;
- drag_initiator_info.protocol = 0;
- drag_initiator_info.table_index = idx;
- drag_initiator_info.selection = dpyinfo->Xatom_XdndSelection;
-
memset (&dmsg, 0, sizeof dmsg);
- xm_write_drag_initiator_info (dpyinfo->display,
- FRAME_X_WINDOW (x_dnd_frame),
- dpyinfo->Xatom_XdndSelection,
- dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO,
- &drag_initiator_info);
-
dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
XM_DRAG_REASON_DROP_START);
dmsg.byte_order = XM_TARGETS_TABLE_CUR;
}
x_dnd_last_protocol_version = -1;
+ x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
x_dnd_last_seen_window = None;
x_dnd_frame = NULL;
x_set_dnd_targets (NULL, 0);
Lisp_Object bar;
struct scroll_bar *b;
#endif
+ xm_drop_start_message dmsg;
if (x_dnd_in_progress && f == x_dnd_frame)
{
if (x_dnd_last_seen_window != None
&& x_dnd_last_protocol_version != -1)
x_dnd_send_leave (f, x_dnd_last_seen_window);
+ else if (x_dnd_last_seen_window != None
+ && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
+ && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
+ && x_dnd_motif_setup_p)
+ {
+ dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_DROP_START);
+ dmsg.byte_order = XM_TARGETS_TABLE_CUR;
+ dmsg.timestamp = 0;
+ dmsg.side_effects
+ = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
+ x_dnd_wanted_action),
+ XM_DROP_SITE_VALID,
+ xm_side_effect_from_action (dpyinfo,
+ x_dnd_wanted_action),
+ XM_DROP_ACTION_DROP_CANCEL);
+ dmsg.x = 0;
+ dmsg.y = 0;
+ dmsg.index_atom = dpyinfo->Xatom_XdndSelection;
+ dmsg.source_window = FRAME_X_WINDOW (f);
+
+ xm_send_drop_message (dpyinfo, FRAME_X_WINDOW (f),
+ x_dnd_last_seen_window, &dmsg);
+ }
unblock_input ();
x_dnd_end_window = None;