]> git.eshelyaron.com Git - emacs.git/commitdiff
Implement Motif drop protocol
authorPo Lu <luangruo@yahoo.com>
Thu, 31 Mar 2022 09:21:37 +0000 (17:21 +0800)
committerPo Lu <luangruo@yahoo.com>
Thu, 31 Mar 2022 09:21:37 +0000 (17:21 +0800)
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
lisp/x-dnd.el
src/xterm.c
src/xterm.h

index 7b9475a64021c199ddbdeb462e42d398c4c62988..ee65678c69d0e7c32a28e4747986a9d6f4e9d346 100644 (file)
@@ -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)
 
index 17e65adc64ea49ad2619acc3d6b7bd3c28fd3738..e26703ad848f38c22935707ede2f3b2df6d84bb8 100644 (file)
@@ -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)))))))
 
 
 ;;;
index a92c34396ca8e1ee09cd468aa2bbb0a56e65a125..bd5d756c8cceda1d01011d01cbc1d832b7c7073f 100644 (file)
@@ -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;
index 57b55ecf0db0919514ae61f5b1ec959f8485dc0d..eb9e25d3cdd38498a3c709c6217327b6f668470f 100644 (file)
@@ -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