emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 1d4306a8a7: Implement Motif drop protocol


From: Po Lu
Subject: master 1d4306a8a7: Implement Motif drop protocol
Date: Thu, 31 Mar 2022 05:22:22 -0400 (EDT)

branch: master
commit 1d4306a8a770cb73db3b39301ee41e15f9e3656f
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Implement Motif drop protocol
    
    This is the second most widely implemented drag-and-drop
    protocol on X Windows, but seems to have some unsolvable
    problems (i.e. stuff will keep accumulating in the drag window
    as long the target lists keep changing.)  The implementation is
    not yet complete and doesn't work with some programs.
    
    * lisp/select.el (xselect-convert-xm-special): New functions.
    (selection-converter-alist): Add new converters.
    * lisp/x-dnd.el (x-dnd-handle-motif): Ignore messages sent by
    the receiver.
    * src/xterm.c (xm_targets_table_byte_order): New enum;
    (SWAPCARD32, SWAPCARD16): New macros.
    (xm_targets_table_rec, xm_drop_start_message)
    (xm_drag_initiator_info, xm_drag_receiver_info): New structures.
    (XM_DRAG_SIDE_EFFECT, xm_read_targets_table_header)
    (xm_read_targets_table_rec, xm_find_targets_table_idx)
    (x_atoms_compare, xm_write_targets_table)
    (xm_write_drag_initiator_info, xm_get_drag_window)
    (xm_setup_dnd_targets, xm_send_drop_message)
    (xm_read_drag_receiver_info): New functions.
    (x_dnd_compute_toplevels): Correctly free some temp data.
    (x_dnd_get_window_proxy, x_dnd_get_window_proto)
    (x_set_frame_alpha): Likewise.
    (handle_one_xevent): If the window has no XDND proto but has
    motif drag receiver data, send a motif drop protocol request.
    (x_term_init): New atoms for Motif DND support.
    * src/xterm.h (struct x_display_info): Add new atoms.
---
 lisp/select.el |   7 +-
 lisp/x-dnd.el  | 321 +++++++++++++------------
 src/xterm.c    | 746 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/xterm.h    |   4 +-
 4 files changed, 900 insertions(+), 178 deletions(-)

diff --git a/lisp/select.el b/lisp/select.el
index 7b9475a640..ee65678c69 100644
--- a/lisp/select.el
+++ b/lisp/select.el
@@ -655,6 +655,9 @@ VALUE is the local selection value of SELECTION."
        (stringp value)
        (file-exists-p value)))
 
+(defun xselect-convert-xm-special (_selection _type _value)
+  "")
+
 (setq selection-converter-alist
       '((TEXT . xselect-convert-to-string)
        (COMPOUND_TEXT . xselect-convert-to-string)
@@ -679,7 +682,9 @@ VALUE is the local selection value of SELECTION."
        (ATOM . xselect-convert-to-atom)
        (INTEGER . xselect-convert-to-integer)
        (SAVE_TARGETS . xselect-convert-to-save-targets)
-       (_EMACS_INTERNAL . xselect-convert-to-identity)))
+       (_EMACS_INTERNAL . xselect-convert-to-identity)
+        (XmTRANSFER_SUCCESS . xselect-convert-xm-special)
+        (XmTRANSFER_FAILURE . xselect-convert-xm-special)))
 
 (provide 'select)
 
diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el
index 17e65adc64..e26703ad84 100644
--- a/lisp/x-dnd.el
+++ b/lisp/x-dnd.el
@@ -603,174 +603,177 @@ FORMAT is 32 (not used).  MESSAGE is the data part of 
an XClientMessageEvent."
     (2 . private)) ; Motif does not have private, so use copy for private.
   "Mapping from number to operation for Motif DND.")
 
-(defun x-dnd-handle-motif (event frame window message-atom _format data)
-  (let* ((message-type (cdr (assoc (aref data 0) x-dnd-motif-message-types)))
+(defun x-dnd-handle-motif (event frame window _message-atom _format data)
+  (let* ((message-type (cdr (assoc (logand (aref data 0) #x3f)
+                                   x-dnd-motif-message-types)))
+         (initiator-p (eq (lsh (aref data 0) -7) 0))
         (source-byteorder (aref data 1))
         (my-byteorder (byteorder))
         (source-flags (x-dnd-get-motif-value data 2 2 source-byteorder))
         (source-action (cdr (assoc (logand ?\xF source-flags)
                                    x-dnd-motif-to-action))))
 
-    (cond ((eq message-type 'XmTOP_LEVEL_ENTER)
-          (let* ((dnd-source (x-dnd-get-motif-value
-                              data 8 4 source-byteorder))
-                 (selection-atom (x-dnd-get-motif-value
-                                  data 12 4 source-byteorder))
-                 (atom-name (x-get-atom-name selection-atom))
-                 (types (when atom-name
-                          (x-get-selection-internal (intern atom-name)
-                                                    'TARGETS))))
-            (x-dnd-forget-drop frame)
-            (when types (x-dnd-save-state window nil nil
-                                          types
-                                          dnd-source))))
-
-         ;; Can not forget drop here, LEAVE comes before DROP_START and
-         ;; we need the state in DROP_START.
-         ((eq message-type 'XmTOP_LEVEL_LEAVE)
-          nil)
-
-         ((eq message-type 'XmDRAG_MOTION)
-          (let* ((state (x-dnd-get-state-for-frame frame))
-                 (timestamp (x-dnd-motif-value-to-list
-                             (x-dnd-get-motif-value data 4 4
-                                                    source-byteorder)
-                             4 my-byteorder))
-                 (x (x-dnd-motif-value-to-list
-                     (x-dnd-get-motif-value data 8 2 source-byteorder)
+    (when initiator-p
+      (cond ((eq message-type 'XmTOP_LEVEL_ENTER)
+            (let* ((dnd-source (x-dnd-get-motif-value
+                                data 8 4 source-byteorder))
+                   (selection-atom (x-dnd-get-motif-value
+                                    data 12 4 source-byteorder))
+                   (atom-name (x-get-atom-name selection-atom))
+                   (types (when atom-name
+                            (x-get-selection-internal (intern atom-name)
+                                                      'TARGETS))))
+              (x-dnd-forget-drop frame)
+              (when types (x-dnd-save-state window nil nil
+                                            types
+                                            dnd-source))))
+
+           ;; Can not forget drop here, LEAVE comes before DROP_START and
+           ;; we need the state in DROP_START.
+           ((eq message-type 'XmTOP_LEVEL_LEAVE)
+            nil)
+
+           ((eq message-type 'XmDRAG_MOTION)
+            (let* ((state (x-dnd-get-state-for-frame frame))
+                   (timestamp (x-dnd-motif-value-to-list
+                               (x-dnd-get-motif-value data 4 4
+                                                      source-byteorder)
+                               4 my-byteorder))
+                   (x (x-dnd-motif-value-to-list
+                       (x-dnd-get-motif-value data 8 2 source-byteorder)
+                       2 my-byteorder))
+                   (y (x-dnd-motif-value-to-list
+                       (x-dnd-get-motif-value data 10 2 source-byteorder)
+                       2 my-byteorder))
+                   (dnd-source (aref state 6))
+                   (first-move (not (aref state 3)))
+                   (action-type (x-dnd-maybe-call-test-function
+                                 window
+                                 source-action))
+                   (reply-action (car (rassoc (car action-type)
+                                              x-dnd-motif-to-action)))
+                   (reply-flags
+                    (x-dnd-motif-value-to-list
+                     (if reply-action
+                         (+ reply-action
+                            ?\x30      ; 30:  valid drop site
+                            ?\x700)    ; 700: can do copy, move or link
+                       ?\x30)          ; 30:  drop site, but noop.
                      2 my-byteorder))
-                 (y (x-dnd-motif-value-to-list
-                     (x-dnd-get-motif-value data 10 2 source-byteorder)
-                     2 my-byteorder))
-                 (dnd-source (aref state 6))
-                 (first-move (not (aref state 3)))
-                 (action-type (x-dnd-maybe-call-test-function
-                               window
-                               source-action))
-                 (reply-action (car (rassoc (car action-type)
-                                            x-dnd-motif-to-action)))
-                 (reply-flags
-                  (x-dnd-motif-value-to-list
-                   (if reply-action
-                       (+ reply-action
-                          ?\x30        ; 30:  valid drop site
-                          ?\x700)      ; 700: can do copy, move or link
-                     ?\x30)            ; 30:  drop site, but noop.
-                   2 my-byteorder))
-                 (reply (append
-                         (list
-                          (+ ?\x80     ; 0x80 indicates a reply.
-                             (if first-move
-                                 3     ; First time, reply is SITE_ENTER.
-                               2))     ; Not first time, reply is DRAG_MOTION.
-                          my-byteorder)
-                         reply-flags
-                         timestamp
-                         x
-                         y)))
-            (x-send-client-message frame
-                                   dnd-source
-                                   frame
-                                   "_MOTIF_DRAG_AND_DROP_MESSAGE"
-                                   8
-                                   reply)))
-
-         ((eq message-type 'XmOPERATION_CHANGED)
-          (let* ((state (x-dnd-get-state-for-frame frame))
-                 (timestamp (x-dnd-motif-value-to-list
-                             (x-dnd-get-motif-value data 4 4 source-byteorder)
-                             4 my-byteorder))
-                 (dnd-source (aref state 6))
-                 (action-type (x-dnd-maybe-call-test-function
-                               window
-                               source-action))
-                 (reply-action (car (rassoc (car action-type)
-                                            x-dnd-motif-to-action)))
-                 (reply-flags
-                  (x-dnd-motif-value-to-list
-                   (if reply-action
-                       (+ reply-action
-                          ?\x30        ; 30:  valid drop site
-                          ?\x700)      ; 700: can do copy, move or link
-                     ?\x30)            ; 30:  drop site, but noop
-                   2 my-byteorder))
-                 (reply (append
-                         (list
-                          (+ ?\x80     ; 0x80 indicates a reply.
-                             8)        ; 8 is OPERATION_CHANGED
-                          my-byteorder)
-                         reply-flags
-                         timestamp)))
-            (x-send-client-message frame
-                                   dnd-source
-                                   frame
-                                   "_MOTIF_DRAG_AND_DROP_MESSAGE"
-                                   8
-                                   reply)))
-
-         ((eq message-type 'XmDROP_START)
-          (let* ((x (x-dnd-motif-value-to-list
-                     (x-dnd-get-motif-value data 8 2 source-byteorder)
+                   (reply (append
+                           (list
+                            (+ ?\x80   ; 0x80 indicates a reply.
+                               (if first-move
+                                   3   ; First time, reply is SITE_ENTER.
+                                 2))   ; Not first time, reply is DRAG_MOTION.
+                            my-byteorder)
+                           reply-flags
+                           timestamp
+                           x
+                           y)))
+              (x-send-client-message frame
+                                     dnd-source
+                                     frame
+                                     "_MOTIF_DRAG_AND_DROP_MESSAGE"
+                                     8
+                                     reply)))
+
+           ((eq message-type 'XmOPERATION_CHANGED)
+            (let* ((state (x-dnd-get-state-for-frame frame))
+                   (timestamp (x-dnd-motif-value-to-list
+                               (x-dnd-get-motif-value data 4 4 
source-byteorder)
+                               4 my-byteorder))
+                   (dnd-source (aref state 6))
+                   (action-type (x-dnd-maybe-call-test-function
+                                 window
+                                 source-action))
+                   (reply-action (car (rassoc (car action-type)
+                                              x-dnd-motif-to-action)))
+                   (reply-flags
+                    (x-dnd-motif-value-to-list
+                     (if reply-action
+                         (+ reply-action
+                            ?\x30      ; 30:  valid drop site
+                            ?\x700)    ; 700: can do copy, move or link
+                       ?\x30)          ; 30:  drop site, but noop
                      2 my-byteorder))
-                 (y (x-dnd-motif-value-to-list
-                     (x-dnd-get-motif-value data 10 2 source-byteorder)
+                   (reply (append
+                           (list
+                            (+ ?\x80   ; 0x80 indicates a reply.
+                               8)      ; 8 is OPERATION_CHANGED
+                            my-byteorder)
+                           reply-flags
+                           timestamp)))
+              (x-send-client-message frame
+                                     dnd-source
+                                     frame
+                                     "_MOTIF_DRAG_AND_DROP_MESSAGE"
+                                     8
+                                     reply)))
+
+           ((eq message-type 'XmDROP_START)
+            (let* ((x (x-dnd-motif-value-to-list
+                       (x-dnd-get-motif-value data 8 2 source-byteorder)
+                       2 my-byteorder))
+                   (y (x-dnd-motif-value-to-list
+                       (x-dnd-get-motif-value data 10 2 source-byteorder)
+                       2 my-byteorder))
+                   (selection-atom (x-dnd-get-motif-value
+                                    data 12 4 source-byteorder))
+                   (atom-name (x-get-atom-name selection-atom))
+                   (dnd-source (x-dnd-get-motif-value
+                                data 16 4 source-byteorder))
+                   (action-type (x-dnd-maybe-call-test-function
+                                 window
+                                 source-action))
+                   (reply-action (car (rassoc (car action-type)
+                                              x-dnd-motif-to-action)))
+                   (reply-flags
+                    (x-dnd-motif-value-to-list
+                     (if reply-action
+                         (+ reply-action
+                            ?\x30      ; 30:  valid drop site
+                            ?\x700)    ; 700: can do copy, move or link
+                       (+ ?\x30                ; 30:  drop site, but noop.
+                          ?\x200))     ; 200: drop cancel.
                      2 my-byteorder))
-                 (selection-atom (x-dnd-get-motif-value
-                                  data 12 4 source-byteorder))
-                 (atom-name (x-get-atom-name selection-atom))
-                 (dnd-source (x-dnd-get-motif-value
-                              data 16 4 source-byteorder))
-                 (action-type (x-dnd-maybe-call-test-function
-                               window
-                               source-action))
-                 (reply-action (car (rassoc (car action-type)
-                                            x-dnd-motif-to-action)))
-                 (reply-flags
-                  (x-dnd-motif-value-to-list
-                   (if reply-action
-                       (+ reply-action
-                          ?\x30        ; 30:  valid drop site
-                          ?\x700)      ; 700: can do copy, move or link
-                     (+ ?\x30          ; 30:  drop site, but noop.
-                        ?\x200))       ; 200: drop cancel.
-                   2 my-byteorder))
-                 (reply (append
-                         (list
-                          (+ ?\x80     ; 0x80 indicates a reply.
-                             5)        ; DROP_START.
-                          my-byteorder)
-                         reply-flags
-                         x
-                         y))
-                 (timestamp (x-dnd-get-motif-value
-                             data 4 4 source-byteorder))
-                 action)
-
-            (x-send-client-message frame
-                                   dnd-source
-                                   frame
-                                   "_MOTIF_DRAG_AND_DROP_MESSAGE"
-                                   8
-                                   reply)
-            (setq action
-                  (when (and reply-action atom-name)
-                    (let* ((value (x-get-selection-internal
-                                   (intern atom-name)
-                                   (intern (x-dnd-current-type window)))))
-                      (when value
-                        (condition-case info
-                            (x-dnd-drop-data event frame window value
-                                             (x-dnd-current-type window))
-                          (error
-                           (message "Error: %s" info)
-                           nil))))))
-            (x-get-selection-internal
-             (intern atom-name)
-             (if action 'XmTRANSFER_SUCCESS 'XmTRANSFER_FAILURE)
-             timestamp)
-            (x-dnd-forget-drop frame)))
-
-         (t (error "Unknown Motif DND message %s %s" message-atom data)))))
+                   (reply (append
+                           (list
+                            (+ ?\x80   ; 0x80 indicates a reply.
+                               5)      ; DROP_START.
+                            my-byteorder)
+                           reply-flags
+                           x
+                           y))
+                   (timestamp (x-dnd-get-motif-value
+                               data 4 4 source-byteorder))
+                   action)
+
+              (x-send-client-message frame
+                                     dnd-source
+                                     frame
+                                     "_MOTIF_DRAG_AND_DROP_MESSAGE"
+                                     8
+                                     reply)
+              (setq action
+                    (when (and reply-action atom-name)
+                      (let* ((value (x-get-selection-internal
+                                     (intern atom-name)
+                                     (intern (x-dnd-current-type window)))))
+                        (when value
+                          (condition-case info
+                              (x-dnd-drop-data event frame window value
+                                               (x-dnd-current-type window))
+                            (error
+                             (message "Error: %s" info)
+                             nil))))))
+              (x-get-selection-internal
+               (intern atom-name)
+               (if action 'XmTRANSFER_SUCCESS 'XmTRANSFER_FAILURE)
+               timestamp)
+              (x-dnd-forget-drop frame)))
+
+            (t (message "Unknown Motif drag-and-drop message: %s" (logand 
(aref data 0) #x3f)))))))
 
 
 ;;;
diff --git a/src/xterm.c b/src/xterm.c
index a92c34396c..bd5d756c8c 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -861,6 +861,594 @@ struct x_client_list_window
 static struct x_client_list_window *x_dnd_toplevels = NULL;
 static bool x_dnd_use_toplevels;
 
+/* Motif drag-and-drop protocol support.  */
+
+typedef enum xm_targets_table_byte_order
+  {
+    XM_TARGETS_TABLE_LSB = 'l',
+    XM_TARGETS_TABLE_MSB = 'B',
+#ifndef WORDS_BIGENDIAN
+    XM_TARGETS_TABLE_CUR = 'l',
+#else
+    XM_TARGETS_TABLE_CUR = 'B',
+#endif
+  } xm_targets_table_byte_order;
+
+#define SWAPCARD32(l)                          \
+  {                                            \
+    struct { unsigned t : 32; } bit32;         \
+    char n, *tp = (char *) &bit32;             \
+    bit32.t = l;                               \
+    n = tp[0]; tp[0] = tp[3]; tp[3] = n;       \
+    n = tp[1]; tp[1] = tp[2]; tp[2] = n;       \
+    l = bit32.t;                               \
+  }
+
+#define SWAPCARD16(s)                          \
+  {                                            \
+    struct { unsigned t : 16; } bit16;         \
+    char n, *tp = (char *) &bit16;             \
+    bit16.t = s;                               \
+    n = tp[0]; tp[0] = tp[1]; tp[1] = n;       \
+    s = bit16.t;                               \
+  }
+
+typedef struct xm_targets_table_header
+{
+  /* BYTE   */ uint8_t byte_order;
+  /* BYTE   */ uint8_t protocol;
+
+  /* CARD16 */ uint16_t target_list_count;
+  /* CARD32 */ uint32_t total_data_size;
+} xm_targets_table_header;
+
+typedef struct xm_targets_table_rec
+{
+  /* CARD16 */ uint16_t n_targets;
+  /* CARD32 */ uint32_t targets[FLEXIBLE_ARRAY_MEMBER];
+} xm_targets_table_rec;
+
+typedef struct xm_drop_start_message
+{
+  /* BYTE   */ uint8_t reason;
+  /* BYTE   */ uint8_t byte_order;
+
+  /* CARD16 */ uint16_t side_effects;
+  /* CARD32 */ uint32_t timestamp;
+  /* CARD16 */ uint16_t x, y;
+  /* CARD32 */ uint32_t index_atom;
+  /* CARD32 */ uint32_t source_window;
+} xm_drop_start_message;
+
+typedef struct xm_drag_initiator_info
+{
+  /* BYTE   */ uint8_t byteorder;
+  /* BYTE   */ uint8_t protocol;
+
+  /* CARD16 */ uint16_t table_index;
+  /* CARD32 */ uint32_t selection;
+} xm_drag_initiator_info;
+
+typedef struct xm_drag_receiver_info
+{
+  /* BYTE   */ uint8_t byteorder;
+  /* BYTE   */ uint8_t protocol;
+
+  /* BYTE   */ uint8_t protocol_style;
+  /* BYTE   */ uint8_t unspecified0;
+  /* CARD32 */ uint32_t unspecified1;
+  /* CARD32 */ uint32_t unspecified2;
+  /* CARD32 */ uint32_t unspecified3;
+} xm_drag_receiver_info;
+
+#define XM_DRAG_SIDE_EFFECT(op, site, ops, act)                \
+  ((op) | ((site) << 4) | ((ops) << 8) | ((act) << 16))
+
+/* Some of the macros below are temporarily unused.  */
+
+/* #define XM_DRAG_SIDE_EFFECT_OPERATION(effect)       ((effect) & 0xf) */
+/* #define XM_DRAG_SIDE_EFFECT_SITE_STATUS(effect)     (((effect) & 0xf0) >> 
4) */
+/* #define XM_DRAG_SIDE_EFFECT_OPERATIONS(effect)      (((effect) & 0xf00) >> 
8) */
+/* #define XM_DRAG_SIDE_EFFECT_DROP_ACTION(effect)     (((effect) & 0xf000) >> 
16) */
+
+#define XM_DRAG_NOOP 0
+#define XM_DRAG_MOVE (1L << 0)
+#define XM_DRAG_COPY (1L << 1)
+#define XM_DRAG_LINK (1L << 2)
+
+#define XM_DROP_ACTION_DROP    0
+#define XM_DROP_SITE_VALID     1
+
+#define XM_DRAG_REASON(originator, code)       ((code) | ((originator) << 7))
+/* #define XM_DRAG_REASON_ORIGINATOR(reason)   (((reason) & 0x80) ? 1 : 0) */
+/* #define XM_DRAG_REASON_CODE(reason)         ((reason) & 0x7f) */
+
+#define XM_DRAG_REASON_DROP_START      5
+#define XM_DRAG_ORIGINATOR_INITIATOR   0
+/* #define XM_DRAG_ORIGINATOR_RECEIVER 1 */
+
+#define XM_DRAG_STYLE_NONE 0
+
+static uint8_t
+xm_side_effect_from_action (struct x_display_info *dpyinfo, Atom action)
+{
+  if (action == dpyinfo->Xatom_XdndActionCopy)
+    return XM_DRAG_COPY;
+  else if (action == dpyinfo->Xatom_XdndActionMove)
+    return XM_DRAG_MOVE;
+  else if (action == dpyinfo->Xatom_XdndActionLink)
+    return XM_DRAG_LINK;
+
+  return XM_DRAG_NOOP;
+}
+
+static int
+xm_read_targets_table_header (uint8_t *bytes, ptrdiff_t length,
+                             xm_targets_table_header *header_return,
+                             xm_targets_table_byte_order *byteorder_return)
+{
+  if (length < 8)
+    return -1;
+
+  header_return->byte_order = *byteorder_return = *(bytes++);
+  header_return->protocol = *(bytes++);
+
+  header_return->target_list_count = *(uint16_t *) bytes;
+  header_return->total_data_size = *(uint32_t *) (bytes + 2);
+
+  if (header_return->byte_order != XM_TARGETS_TABLE_CUR)
+    {
+      SWAPCARD16 (header_return->target_list_count);
+      SWAPCARD32 (header_return->total_data_size);
+    }
+
+  header_return->byte_order = XM_TARGETS_TABLE_CUR;
+
+  return 8;
+}
+
+static xm_targets_table_rec *
+xm_read_targets_table_rec (uint8_t *bytes, ptrdiff_t length,
+                          xm_targets_table_byte_order byteorder)
+{
+  uint16_t nitems, i;
+  xm_targets_table_rec *rec;
+
+  if (length < 2)
+    return NULL;
+
+  nitems = *(uint16_t *) bytes;
+
+  if (length < 2 + nitems * 4)
+    return NULL;
+
+  if (byteorder != XM_TARGETS_TABLE_CUR)
+    SWAPCARD16 (nitems);
+
+  rec = xmalloc (sizeof *rec + nitems * 4);
+  rec->n_targets = nitems;
+
+  for (i = 0; i < nitems; ++i)
+    {
+      rec->targets[i] = ((uint32_t *) (bytes + 2))[i];
+
+      if (byteorder != XM_TARGETS_TABLE_CUR)
+       SWAPCARD32 (rec->targets[i]);
+    }
+
+  return rec;
+}
+
+static int
+xm_find_targets_table_idx (xm_targets_table_header *header,
+                          xm_targets_table_rec **recs,
+                          Atom *sorted_targets, int ntargets)
+{
+  int j;
+  uint16_t i;
+  uint32_t *targets;
+
+  targets = alloca (sizeof *targets * ntargets);
+
+  for (j = 0; j < ntargets; ++j)
+    targets[j] = sorted_targets[j];
+
+  for (i = 0; i < header->target_list_count; ++i)
+    {
+      if (recs[i]->n_targets == ntargets
+         && !memcmp (&recs[i]->targets, targets,
+                     sizeof *targets * ntargets))
+       return i;
+    }
+
+  return -1;
+}
+
+static int
+x_atoms_compare (const void *a, const void *b)
+{
+  return *(Atom *) a - *(Atom *) b;
+}
+
+static void
+xm_write_targets_table (Display *dpy, Window wdesc,
+                       Atom targets_table_atom,
+                       xm_targets_table_header *header,
+                       xm_targets_table_rec **recs)
+{
+  uint8_t *header_buffer, *ptr, *rec_buffer;
+  ptrdiff_t rec_buffer_size;
+  uint16_t i, j;
+
+  header_buffer = alloca (8);
+  ptr = header_buffer;
+
+  *(header_buffer++) = header->byte_order;
+  *(header_buffer++) = header->protocol;
+  *((uint16_t *) header_buffer) = header->target_list_count;
+  *((uint32_t *) (header_buffer + 2)) = header->total_data_size;
+
+  rec_buffer = xmalloc (600);
+  rec_buffer_size = 600;
+
+  XGrabServer (dpy);
+  XChangeProperty (dpy, wdesc, targets_table_atom,
+                  targets_table_atom, 8, PropModeReplace,
+                  (unsigned char *) ptr, 8);
+
+  for (i = 0; i < header->target_list_count; ++i)
+    {
+      if (rec_buffer_size < 2 + recs[i]->n_targets * 4)
+       {
+         rec_buffer_size = 2 + recs[i]->n_targets * 4;
+         rec_buffer = xrealloc (rec_buffer, rec_buffer_size);
+       }
+
+      *((uint16_t *) rec_buffer) = recs[i]->n_targets;
+
+      for (j = 0; j < recs[i]->n_targets; ++j)
+       ((uint32_t *) (rec_buffer + 2))[j] = recs[i]->targets[j];
+
+      XChangeProperty (dpy, wdesc, targets_table_atom,
+                      targets_table_atom, 8, PropModeAppend,
+                      (unsigned char *) rec_buffer,
+                      2 + recs[i]->n_targets * 4);
+    }
+  XUngrabServer (dpy);
+
+  xfree (rec_buffer);
+}
+
+static void
+xm_write_drag_initiator_info (Display *dpy, Window wdesc,
+                             Atom prop_name, Atom type_name,
+                             xm_drag_initiator_info *info)
+{
+  uint8_t *buf;
+
+  buf = alloca (8);
+  buf[0] = info->byteorder;
+  buf[1] = info->protocol;
+
+  *((uint16_t *) (buf + 2)) = info->table_index;
+  *((uint32_t *) (buf + 4)) = info->selection;
+
+  XChangeProperty (dpy, wdesc, prop_name, type_name, 8,
+                  PropModeReplace, (unsigned char *) buf, 8);
+}
+
+static Window
+xm_get_drag_window (struct x_display_info *dpyinfo)
+{
+  Atom actual_type;
+  int rc, actual_format;
+  unsigned long nitems, bytes_remaining;
+  unsigned char *tmp_data = NULL;
+  Window drag_window;
+  XSetWindowAttributes attrs;
+  XWindowAttributes wattrs;
+  Display *temp_display;
+
+  drag_window = None;
+  XGrabServer (dpyinfo->display);
+  rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
+                          dpyinfo->Xatom_MOTIF_DRAG_WINDOW,
+                          0, 1, False, XA_WINDOW, &actual_type,
+                          &actual_format, &nitems, &bytes_remaining,
+                          &tmp_data) == Success;
+
+  if (rc)
+    {
+      if (actual_type == XA_WINDOW
+         && actual_format == 32 && nitems == 1)
+       {
+         drag_window = *(Window *) tmp_data;
+         x_catch_errors (dpyinfo->display);
+         XGetWindowAttributes (dpyinfo->display,
+                               drag_window, &wattrs);
+         rc = !x_had_errors_p (dpyinfo->display);
+         x_uncatch_errors_after_check ();
+
+         if (!rc)
+           drag_window = None;
+       }
+
+      if (tmp_data)
+       XFree (tmp_data);
+    }
+
+  XUngrabServer (dpyinfo->display);
+
+  if (drag_window == None)
+    {
+      unrequest_sigio ();
+      temp_display = XOpenDisplay (XDisplayString (dpyinfo->display));
+      request_sigio ();
+
+      if (!temp_display)
+       return None;
+
+      XSetCloseDownMode (temp_display, RetainPermanent);
+
+      XGrabServer (temp_display);
+      attrs.override_redirect = True;
+      drag_window = XCreateWindow (temp_display, DefaultRootWindow 
(temp_display),
+                                  -1, -1, 1, 1, 0, CopyFromParent, InputOnly,
+                                  CopyFromParent, CWOverrideRedirect, &attrs);
+      XChangeProperty (temp_display, DefaultRootWindow (temp_display),
+                      XInternAtom (temp_display,
+                                   "_MOTIF_DRAG_WINDOW", False),
+                      XA_WINDOW, 32, PropModeReplace,
+                      (unsigned char *) &drag_window, 1);
+      XUngrabServer (temp_display);
+      XCloseDisplay (temp_display);
+
+      /* Make sure the drag window created is actually valid for the
+        current display, and the XOpenDisplay above didn't
+        accidentally connect to some other display.  */
+      x_catch_errors (dpyinfo->display);
+      XGetWindowAttributes (dpyinfo->display,
+                           drag_window, &wattrs);
+      rc = !x_had_errors_p (dpyinfo->display);
+      x_uncatch_errors_after_check ();
+
+      /* We connected to the wrong display, so just give up.  */
+      if (!rc)
+       drag_window = None;
+    }
+
+  return drag_window;
+}
+
+/* TODO: overflow checks when inserting targets.  */
+static int
+xm_setup_dnd_targets (struct x_display_info *dpyinfo,
+                     Atom *targets, int ntargets)
+{
+  Window drag_window;
+  Atom *targets_sorted, actual_type;
+  unsigned char *tmp_data = NULL;
+  unsigned long nitems, bytes_remaining;
+  int rc, actual_format, idx;
+  xm_targets_table_header header;
+  xm_targets_table_rec **recs;
+  xm_targets_table_byte_order byteorder;
+  uint8_t *data;
+  ptrdiff_t total_bytes, total_items, i;
+
+  drag_window = xm_get_drag_window (dpyinfo);
+
+  if (drag_window == None || ntargets > 64)
+    return -1;
+
+  targets_sorted = xmalloc (sizeof *targets * ntargets);
+  memcpy (targets_sorted, targets,
+         sizeof *targets * ntargets);
+  qsort (targets_sorted, ntargets,
+        sizeof (Atom), x_atoms_compare);
+
+  XGrabServer (dpyinfo->display);
+  rc = XGetWindowProperty (dpyinfo->display, drag_window,
+                          dpyinfo->Xatom_MOTIF_DRAG_TARGETS,
+                          /* Do larger values occur in practice? */
+                          0L, 20000L, False,
+                          dpyinfo->Xatom_MOTIF_DRAG_TARGETS,
+                          &actual_type, &actual_format, &nitems,
+                          &bytes_remaining, &tmp_data) == Success;
+
+  if (rc && tmp_data && !bytes_remaining
+      && actual_type == dpyinfo->Xatom_MOTIF_DRAG_TARGETS
+      && actual_format == 8)
+    {
+      data = (uint8_t *) tmp_data;
+      if (xm_read_targets_table_header ((uint8_t *) tmp_data,
+                                       nitems, &header,
+                                       &byteorder) == 8)
+       {
+         data += 8;
+         nitems -= 8;
+         total_bytes = 0;
+         total_items = 0;
+
+         /* The extra rec is used to store a new target list if a
+            preexisting one doesn't already exist.  */
+         recs = xmalloc ((header.target_list_count + 1)
+                         * sizeof *recs);
+
+         while (total_items < header.target_list_count)
+           {
+             recs[total_items] = xm_read_targets_table_rec (data + total_bytes,
+                                                            nitems, byteorder);
+
+             if (!recs[total_items])
+               break;
+
+             total_bytes += 2 + recs[total_items]->n_targets * 4;
+             nitems -= 2 + recs[total_items]->n_targets * 4;
+             total_items++;
+           }
+
+         if (header.target_list_count != total_items
+             || header.total_data_size != 8 + total_bytes)
+           {
+             for (i = 0; i < total_items; ++i)
+               {
+                 if (recs[i])
+                     xfree (recs[i]);
+                 else
+                   break;
+               }
+
+             xfree (recs);
+
+             rc = false;
+           }
+       }
+      else
+       rc = false;
+    }
+  else
+    rc = false;
+
+  if (tmp_data)
+    XFree (tmp_data);
+
+  /* Now rc means whether or not the target lists weren't updated and
+     shouldn't be written to the drag window.  */
+
+  if (!rc)
+    {
+      header.byte_order = XM_TARGETS_TABLE_CUR;
+      header.protocol = 0;
+      header.target_list_count = 1;
+      header.total_data_size = 8 + 2 + ntargets * 4;
+
+      recs = xmalloc (sizeof *recs);
+      recs[0] = xmalloc (sizeof **recs + ntargets * 4);
+
+      recs[0]->n_targets = ntargets;
+
+      for (i = 0; i < ntargets; ++i)
+       recs[0]->targets[i] = targets_sorted[i];
+
+      idx = 0;
+    }
+  else
+    {
+      idx = xm_find_targets_table_idx (&header, recs,
+                                      targets_sorted,
+                                      ntargets);
+
+      if (idx == -1)
+       {
+         header.target_list_count++;
+         header.total_data_size += 2 + ntargets * 4;
+
+         recs[header.target_list_count - 1] = xmalloc (sizeof **recs + 
ntargets * 4);
+         recs[header.target_list_count - 1]->n_targets = ntargets;
+
+         for (i = 0; i < ntargets; ++i)
+           recs[header.target_list_count - 1]->targets[i] = targets_sorted[i];
+
+         idx = header.target_list_count - 1;
+         rc = false;
+       }
+    }
+
+  if (!rc)
+    xm_write_targets_table (dpyinfo->display, drag_window,
+                           dpyinfo->Xatom_MOTIF_DRAG_TARGETS,
+                           &header, recs);
+
+  XUngrabServer (dpyinfo->display);
+
+  for (i = 0; i < header.target_list_count; ++i)
+    xfree (recs[i]);
+
+  xfree (recs);
+  xfree (targets_sorted);
+
+  return idx;
+}
+
+static void
+xm_send_drop_message (struct x_display_info *dpyinfo, Window source,
+                     Window target, xm_drop_start_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->byte_order;
+  *((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;
+  *((uint32_t *) &msg.xclient.data.b[12]) = dmsg->index_atom;
+  *((uint32_t *) &msg.xclient.data.b[16]) = dmsg->source_window;
+
+  x_catch_errors (dpyinfo->display);
+  XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
+  x_uncatch_errors ();
+}
+
+static int
+xm_read_drag_receiver_info (struct x_display_info *dpyinfo,
+                           Window wdesc, xm_drag_receiver_info *rec)
+{
+  Atom actual_type;
+  int rc, actual_format;
+  unsigned long nitems, bytes_remaining;
+  unsigned char *tmp_data = NULL;
+  uint8_t *data;
+
+  x_catch_errors (dpyinfo->display);
+  rc = XGetWindowProperty (dpyinfo->display, wdesc,
+                          dpyinfo->Xatom_MOTIF_DRAG_RECEIVER_INFO,
+                          0, LONG_MAX, False,
+                          dpyinfo->Xatom_MOTIF_DRAG_RECEIVER_INFO,
+                          &actual_type, &actual_format, &nitems,
+                          &bytes_remaining,
+                          &tmp_data) == Success;
+
+  if (x_had_errors_p (dpyinfo->display)
+      || actual_format != 8 || nitems < 16 || !tmp_data
+      || actual_type != dpyinfo->Xatom_MOTIF_DRAG_RECEIVER_INFO)
+    rc = 0;
+  x_uncatch_errors_after_check ();
+
+  if (rc)
+    {
+      data = (uint8_t *) tmp_data;
+
+      rec->byteorder = data[0];
+      rec->protocol = data[1];
+      rec->protocol_style = data[2];
+      rec->unspecified0 = data[3];
+      rec->unspecified1 = *(uint32_t *) &data[4];
+      rec->unspecified2 = *(uint32_t *) &data[8];
+      rec->unspecified3 = *(uint32_t *) &data[12];
+
+      if (rec->byteorder != XM_TARGETS_TABLE_CUR)
+       {
+         SWAPCARD32 (rec->unspecified1);
+         SWAPCARD32 (rec->unspecified2);
+         SWAPCARD32 (rec->unspecified3);
+       }
+
+      rec->byteorder = XM_TARGETS_TABLE_CUR;
+    }
+
+  if (tmp_data)
+    XFree (tmp_data);
+
+  return !rc;
+}
+
 static void
 x_dnd_free_toplevels (void)
 {
@@ -1124,10 +1712,6 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
          tem->previous_event_mask = attrs.your_event_mask;
          tem->wm_state = wmstate[0];
 
-#ifndef USE_XCB
-         XFree (wmstate_data);
-#endif
-
 #ifdef HAVE_XSHAPE
 #ifndef USE_XCB
          tem->border_width = attrs.border_width;
@@ -1360,6 +1944,14 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
       if (geometry_reply)
        free (geometry_reply);
 #endif
+
+#ifndef USE_XCB
+      if (wmstate_data)
+       {
+         XFree (wmstate_data);
+         wmstate_data = NULL;
+       }
+#endif
     }
 
   return 0;
@@ -1715,7 +2307,7 @@ x_dnd_get_window_proxy (struct x_display_info *dpyinfo, 
Window wdesc)
 {
   int rc, actual_format;
   unsigned long actual_size, bytes_remaining;
-  unsigned char *tmp_data;
+  unsigned char *tmp_data = NULL;
   XWindowAttributes attrs;
   Atom actual_type;
   Window proxy;
@@ -1731,12 +2323,12 @@ x_dnd_get_window_proxy (struct x_display_info *dpyinfo, 
Window wdesc)
 
   if (!x_had_errors_p (dpyinfo->display)
       && rc == Success
+      && tmp_data
       && actual_type == XA_WINDOW
       && actual_format == 32
       && actual_size == 1)
     {
       proxy = *(Window *) tmp_data;
-      XFree (tmp_data);
 
       /* Verify the proxy window exists.  */
       XGetWindowAttributes (dpyinfo->display, proxy, &attrs);
@@ -1744,6 +2336,9 @@ x_dnd_get_window_proxy (struct x_display_info *dpyinfo, 
Window wdesc)
       if (x_had_errors_p (dpyinfo->display))
        proxy = None;
     }
+
+  if (tmp_data)
+    XFree (tmp_data);
   x_uncatch_errors_after_check ();
 
   return proxy;
@@ -1753,7 +2348,7 @@ static int
 x_dnd_get_window_proto (struct x_display_info *dpyinfo, Window wdesc)
 {
   Atom actual, value;
-  unsigned char *tmp_data;
+  unsigned char *tmp_data = NULL;
   int rc, format;
   unsigned long n, left;
   bool had_errors;
@@ -1769,8 +2364,13 @@ x_dnd_get_window_proto (struct x_display_info *dpyinfo, 
Window wdesc)
   had_errors = x_had_errors_p (dpyinfo->display);
   x_uncatch_errors_after_check ();
 
-  if (had_errors || rc != Success || actual != XA_ATOM || format != 32 || n < 
1)
-    return -1;
+  if (had_errors || rc != Success || actual != XA_ATOM || format != 32 || n < 1
+      || !tmp_data)
+    {
+      if (tmp_data)
+       XFree (tmp_data);
+      return -1;
+    }
 
   value = (int) *(Atom *) tmp_data;
   XFree (tmp_data);
@@ -3545,7 +4145,7 @@ x_set_frame_alpha (struct frame *f)
 
   /* return unless necessary */
   {
-    unsigned char *data;
+    unsigned char *data = NULL;
     Atom actual;
     int rc, format;
     unsigned long n, left;
@@ -3555,16 +4155,19 @@ x_set_frame_alpha (struct frame *f)
                             &actual, &format, &n, &left,
                             &data);
 
-    if (rc == Success && actual != None)
+    if (rc == Success && actual != None && data)
       {
-        unsigned long value = *(unsigned long *)data;
-       XFree (data);
+        unsigned long value = *(unsigned long *) data;
        if (value == opac)
          {
            x_uncatch_errors ();
+           XFree (data);
            return;
          }
       }
+
+    if (data)
+      XFree (data);
   }
 
   XChangeProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
@@ -12144,12 +12747,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
                      if (!x_had_errors_p (dpyinfo->display) && rc == Success 
&& data
                          && nitems == 2 && actual_format == 32)
-                       {
-                         tem->wm_state = ((unsigned long *) data)[0];
-                         XFree (data);
-                       }
+                       tem->wm_state = ((unsigned long *) data)[0];
                      else
                        tem->wm_state = WithdrawnState;
+
+                     if (data)
+                       XFree (data);
                      x_uncatch_errors_after_check ();
                    }
 
@@ -13569,6 +14172,56 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                x_dnd_frame = NULL;
                x_set_dnd_targets (NULL, 0);
              }
+           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;
+
+               if (!xm_read_drag_receiver_info (dpyinfo, 
x_dnd_last_seen_window,
+                                                &drag_receiver_info)
+                   && drag_receiver_info.protocol_style != XM_DRAG_STYLE_NONE)
+                 {
+                   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;
+
+                       memset (&dmsg, 0, sizeof dmsg);
+
+                       xm_write_drag_initiator_info (dpyinfo->display,
+                                                     FRAME_X_WINDOW 
(x_dnd_frame),
+                                                     
dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO,
+                                                     
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;
+                       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);
+                       dmsg.timestamp = event->xbutton.time;
+                       dmsg.x = event->xbutton.x_root;
+                       dmsg.y = event->xbutton.y_root;
+                       dmsg.index_atom = 
dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO;
+                       dmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
+
+                       xm_send_drop_message (dpyinfo, FRAME_X_WINDOW 
(x_dnd_frame),
+                                             x_dnd_last_seen_window, &dmsg);
+                     }
+                 }
+             }
 
            goto OTHER;
          }
@@ -14562,6 +15215,56 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                               x_dnd_selection_timestamp,
                                               x_dnd_last_protocol_version);
                        }
+                     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;
+
+                         if (!xm_read_drag_receiver_info (dpyinfo, 
x_dnd_last_seen_window,
+                                                          &drag_receiver_info)
+                             && drag_receiver_info.protocol_style != 
XM_DRAG_STYLE_NONE)
+                           {
+                             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;
+
+                                 memset (&dmsg, 0, sizeof dmsg);
+
+                                 xm_write_drag_initiator_info 
(dpyinfo->display,
+                                                               FRAME_X_WINDOW 
(x_dnd_frame),
+                                                               
dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO,
+                                                               
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;
+                                 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);
+                                 dmsg.timestamp = xev->time;
+                                 dmsg.x = lrint (xev->root_x);
+                                 dmsg.y = lrint (xev->root_y);
+                                 dmsg.index_atom = 
dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO;
+                                 dmsg.source_window = FRAME_X_WINDOW 
(x_dnd_frame);
+
+                                 xm_send_drop_message (dpyinfo, FRAME_X_WINDOW 
(x_dnd_frame),
+                                                       x_dnd_last_seen_window, 
&dmsg);
+                               }
+                           }
+                       }
 
                      x_dnd_last_protocol_version = -1;
                      x_dnd_last_seen_window = None;
@@ -20420,6 +21123,15 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
       ATOM_REFS_INIT ("XdndLeave", Xatom_XdndLeave)
       ATOM_REFS_INIT ("XdndDrop", Xatom_XdndDrop)
       ATOM_REFS_INIT ("XdndFinished", Xatom_XdndFinished)
+      /* Motif drop protocol support.  */
+      ATOM_REFS_INIT ("_MOTIF_DRAG_WINDOW", Xatom_MOTIF_DRAG_WINDOW)
+      ATOM_REFS_INIT ("_MOTIF_DRAG_TARGETS", Xatom_MOTIF_DRAG_TARGETS)
+      ATOM_REFS_INIT ("_MOTIF_DRAG_AND_DROP_MESSAGE",
+                     Xatom_MOTIF_DRAG_AND_DROP_MESSAGE)
+      ATOM_REFS_INIT ("_MOTIF_DRAG_INITIATOR_INFO",
+                     Xatom_MOTIF_DRAG_INITIATOR_INFO)
+      ATOM_REFS_INIT ("_MOTIF_DRAG_RECEIVER_INFO",
+                     Xatom_MOTIF_DRAG_RECEIVER_INFO)
     };
 
     int i;
diff --git a/src/xterm.h b/src/xterm.h
index 57b55ecf0d..eb9e25d3cd 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -433,7 +433,9 @@ struct x_display_info
   /* Atom used to determine whether or not the screen is composited.  */
   Atom Xatom_NET_WM_CM_Sn;
 
-  Atom Xatom_MOTIF_WM_HINTS;
+  Atom Xatom_MOTIF_WM_HINTS, Xatom_MOTIF_DRAG_WINDOW,
+    Xatom_MOTIF_DRAG_TARGETS, Xatom_MOTIF_DRAG_AND_DROP_MESSAGE,
+    Xatom_MOTIF_DRAG_INITIATOR_INFO, Xatom_MOTIF_DRAG_RECEIVER_INFO;
 
   /* The frame (if any) which has the X window that has keyboard focus.
      Zero if none.  This is examined by Ffocus_frame in xfns.c.  Note



reply via email to

[Prev in Thread] Current Thread [Next in Thread]