]> git.eshelyaron.com Git - emacs.git/commitdiff
Implement the Motif drag protocol
authorPo Lu <luangruo@yahoo.com>
Fri, 1 Apr 2022 11:57:42 +0000 (19:57 +0800)
committerPo Lu <luangruo@yahoo.com>
Fri, 1 Apr 2022 11:58:02 +0000 (19:58 +0800)
* 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.

src/xterm.c

index ed4d0a6d272a0645f301b346095c9d31969c0a16..109c7789f337a3c14390ae55c17f9f6ffc679854 100644 (file)
@@ -511,12 +511,12 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
   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;