From: Po Lu Date: Fri, 1 Apr 2022 11:57:42 +0000 (+0800) Subject: Implement the Motif drag protocol X-Git-Tag: emacs-29.0.90~1931^2~838 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=611179d000cd5cf8e8955e3b3c205692a3e91225;p=emacs.git Implement the Motif drag protocol * src/xterm.c (struct x_client_list_window): New field `xm_protocol_style'. (xm_top_level_enter_message, xm_drag_motion_message) (xm_top_level_leave_message): New structures. (xm_setup_drag_info, xm_send_top_level_enter_message) (xm_send_drag_motion_message, xm_send_top_level_leave_message): New functions. (x_dnd_compute_toplevels): Compute `xm_protocol_style'. (x_dnd_get_target_window_1, x_dnd_get_target_window): New parameter `motif_out'. Place the xm protocol style in it if necessary. (x_dnd_cleanup_drag_and_drop, x_dnd_begin_drag_and_drop) (x_dnd_update_state, handle_one_xevent): Handle Motif drag protocol messages. (x_free_frame_resources): Cancel Motif drag protocol operations correctly. --- diff --git a/src/xterm.c b/src/xterm.c index ed4d0a6d272..109c7789f33 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -511,12 +511,12 @@ along with GNU Emacs. If not, see . */ 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 @@ -852,6 +852,7 @@ static bool x_dnd_waiting_for_finish; 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; @@ -867,6 +868,7 @@ static struct frame *x_dnd_return_frame_object; 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; @@ -891,6 +893,7 @@ struct x_client_list_window unsigned long wm_state; struct x_client_list_window *next; + uint8_t xm_protocol_style; #ifdef HAVE_XSHAPE int border_width; @@ -996,6 +999,37 @@ typedef struct xm_drag_receiver_info /* 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)) @@ -1020,10 +1054,26 @@ typedef struct xm_drag_receiver_info #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 */ @@ -1425,6 +1475,32 @@ xm_setup_dnd_targets (struct x_display_info *dpyinfo, 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) @@ -1450,6 +1526,94 @@ xm_send_drop_message (struct x_display_info *dpyinfo, Window source, 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) { @@ -1583,15 +1747,19 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) 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 @@ -1637,6 +1805,8 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) = 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); @@ -1664,6 +1834,11 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) = 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]); @@ -1748,6 +1923,13 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) 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)) @@ -1796,6 +1978,21 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) 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 @@ -2026,6 +2223,9 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) if (property_reply) free (property_reply); + if (xm_property_reply) + free (xm_property_reply); + if (geometry_reply) free (geometry_reply); #endif @@ -2138,9 +2338,9 @@ x_dnd_get_target_window_2 (XRectangle *rects, int nrects, 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. */ @@ -2157,7 +2357,10 @@ x_dnd_get_target_window_1 (struct x_display_info *dpyinfo, #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, @@ -2170,12 +2373,23 @@ x_dnd_get_target_window_1 (struct x_display_info *dpyinfo, 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; } @@ -2265,7 +2479,8 @@ x_dnd_get_wm_state_and_proto (struct x_display_info *dpyinfo, 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; @@ -2280,10 +2495,16 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, 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) { @@ -2761,6 +2982,7 @@ static void x_dnd_cleanup_drag_and_drop (void *frame) { struct frame *f = frame; + xm_drop_start_message dmsg; if (!x_dnd_unwind_flag) return; @@ -2774,6 +2996,30 @@ x_dnd_cleanup_drag_and_drop (void *frame) && 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; @@ -8571,6 +8817,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, specpdl_ref ref; ptrdiff_t i, end, fill; XTextProperty prop; + xm_drop_start_message dmsg; if (!FRAME_VISIBLE_P (f)) error ("Frame is invisible"); @@ -8643,6 +8890,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, 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; @@ -8650,6 +8898,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom 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); @@ -8747,6 +8996,30 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, 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; @@ -12378,11 +12651,15 @@ mouse_or_wdesc_frame (struct x_display_info *dpyinfo, int wdesc) /* 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, @@ -12392,7 +12669,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo) &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) { @@ -12400,6 +12678,24 @@ x_dnd_update_state (struct x_display_info *dpyinfo) && 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) @@ -12421,10 +12717,28 @@ x_dnd_update_state (struct x_display_info *dpyinfo) 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) @@ -12433,6 +12747,31 @@ x_dnd_update_state (struct x_display_info *dpyinfo) 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) @@ -12441,6 +12780,31 @@ x_dnd_update_state (struct x_display_info *dpyinfo) && 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; @@ -12996,7 +13360,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_uncatch_errors_after_check (); } - x_dnd_update_state (dpyinfo); + x_dnd_update_state (dpyinfo, event->xproperty.time); break; } } @@ -13063,7 +13427,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, } } - x_dnd_update_state (dpyinfo); + x_dnd_update_state (dpyinfo, event->xproperty.time); } x_handle_property_notify (&event->xproperty); @@ -13295,7 +13659,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, #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)) @@ -13918,7 +14282,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, && 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 @@ -13931,7 +14298,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, 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) { @@ -13939,6 +14307,24 @@ handle_one_xevent (struct x_display_info *dpyinfo, && 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) @@ -13960,10 +14346,28 @@ handle_one_xevent (struct x_display_info *dpyinfo, 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) @@ -13973,6 +14377,30 @@ handle_one_xevent (struct x_display_info *dpyinfo, 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; } @@ -14352,7 +14780,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, } if (x_dnd_in_progress) - x_dnd_update_state (dpyinfo); + x_dnd_update_state (dpyinfo, 0); goto OTHER; case ButtonRelease: @@ -14416,35 +14844,22 @@ handle_one_xevent (struct x_display_info *dpyinfo, } 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; @@ -14471,6 +14886,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, } 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); @@ -14695,7 +15111,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, case CirculateNotify: if (x_dnd_in_progress) - x_dnd_update_state (dpyinfo); + x_dnd_update_state (dpyinfo, 0); goto OTHER; case CirculateRequest: @@ -15015,6 +15431,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, #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; @@ -15289,7 +15709,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, && 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 @@ -15302,7 +15722,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, 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) { @@ -15310,6 +15731,24 @@ handle_one_xevent (struct x_display_info *dpyinfo, && 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) @@ -15331,10 +15770,28 @@ handle_one_xevent (struct x_display_info *dpyinfo, 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) @@ -15343,6 +15800,31 @@ handle_one_xevent (struct x_display_info *dpyinfo, 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; } @@ -15470,35 +15952,22 @@ handle_one_xevent (struct x_display_info *dpyinfo, } 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; @@ -15536,6 +16005,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, } 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); @@ -19865,6 +20335,7 @@ x_free_frame_resources (struct frame *f) Lisp_Object bar; struct scroll_bar *b; #endif + xm_drop_start_message dmsg; if (x_dnd_in_progress && f == x_dnd_frame) { @@ -19872,6 +20343,30 @@ x_free_frame_resources (struct frame *f) 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;