]> git.eshelyaron.com Git - emacs.git/commitdiff
Avoid ClientMessage overhead when dragging stuff to other frames
authorPo Lu <luangruo@yahoo.com>
Sat, 26 Mar 2022 02:15:53 +0000 (10:15 +0800)
committerPo Lu <luangruo@yahoo.com>
Sat, 26 Mar 2022 02:15:53 +0000 (10:15 +0800)
* lisp/dired.el (dired-mouse-drag): Handle correctly dragging
from dired buffers in nonselected windows.
* lisp/x-dnd.el (x-dnd-handle-drag-n-drop-event): Understand new
client message type.
* src/xterm.c (x_dnd_send_enter, x_dnd_send_position)
(x_dnd_send_leave): Ignore if window is the top window of a
frame.
(x_dnd_send_drop): Send special DND event in that case.

lisp/dired.el
lisp/x-dnd.el
src/xterm.c

index c5e389c9ce1c98e0ba5227937acd299a7ff9199a..3c37a887baf9258e311c7bb1553f8503d4bbbb38 100644 (file)
@@ -1704,7 +1704,8 @@ see `dired-use-ls-dired' for more details.")
   (when mark-active
     (deactivate-mark))
   (save-excursion
-    (goto-char (posn-point (event-end event)))
+    (with-selected-window (posn-window (event-end event))
+      (goto-char (posn-point (event-end event))))
     (track-mouse
       (let ((new-event (read-event)))
         (if (not (eq (event-basic-type new-event) 'mouse-movement))
@@ -1715,7 +1716,9 @@ see `dired-use-ls-dired' for more details.")
           (condition-case nil
               (progn
                 (gui-backend-set-selection 'XdndSelection
-                                           (dired-file-name-at-point))
+                                           (with-selected-window (posn-window
+                                                                  (event-end event))
+                                             (dired-file-name-at-point)))
                 (x-begin-drag '("text/uri-list"
                                 "text/x-dnd-username")
                               (if (eq 'dired-mouse-drag-files 'link)
index 0529d223dbe6452daa285b04700b3dd8535d5e36..e801c4fdfce46a7c2bd4eb9d18bd38c3acce4569 100644 (file)
@@ -115,6 +115,9 @@ the type we want for the drop,
 the action we want for the drop,
 any protocol specific data.")
 
+(declare-function x-get-selection-internal "xselect.c"
+                 (selection-symbol target-type &optional time-stamp terminal))
+
 (defvar x-dnd-empty-state [nil nil nil nil nil nil nil])
 
 (declare-function x-register-dnd-atom "xselect.c")
@@ -336,21 +339,41 @@ nil if not."
 Currently XDND, Motif and old KDE 1.x protocols are recognized."
   (interactive "e")
   (let* ((client-message (car (cdr (cdr event))))
-        (window (posn-window (event-start event)))
-        (message-atom (aref client-message 0))
-        (frame (aref client-message 1))
-        (format (aref client-message 2))
-        (data (aref client-message 3)))
-
-    (cond ((equal "DndProtocol" message-atom)  ; Old KDE 1.x.
-          (x-dnd-handle-old-kde event frame window message-atom format data))
-
-         ((equal "_MOTIF_DRAG_AND_DROP_MESSAGE" message-atom)  ; Motif
-          (x-dnd-handle-motif event frame window message-atom format data))
-
-         ((and (> (length message-atom) 4)     ; XDND protocol.
-               (equal "Xdnd" (substring message-atom 0 4)))
-          (x-dnd-handle-xdnd event frame window message-atom format data)))))
+        (window (posn-window (event-start event))))
+    (if (eq (and (consp client-message)
+                 (car client-message))
+            'XdndSelection)
+        ;; This is an internal Emacs message caused by something being
+        ;; dropped on top of a frame.
+        (progn
+          (let ((action (cdr (assoc (symbol-name (cadr client-message))
+                                    x-dnd-xdnd-to-action)))
+                (targets (cddr client-message)))
+            (x-dnd-save-state window nil nil
+                              (apply #'vector targets))
+            (x-dnd-maybe-call-test-function window action)
+            (unwind-protect
+                (x-dnd-drop-data event (if (framep window) window
+                                         (window-frame window))
+                                 window
+                                 (x-get-selection-internal
+                                  'XdndSelection
+                                  (intern (x-dnd-current-type window)))
+                                 (x-dnd-current-type window))
+              (x-dnd-forget-drop window))))
+      (let ((message-atom (aref client-message 0))
+           (frame (aref client-message 1))
+           (format (aref client-message 2))
+           (data (aref client-message 3)))
+        (cond ((equal "DndProtocol" message-atom)      ; Old KDE 1.x.
+              (x-dnd-handle-old-kde event frame window message-atom format data))
+
+             ((equal "_MOTIF_DRAG_AND_DROP_MESSAGE" message-atom)      ; Motif
+              (x-dnd-handle-motif event frame window message-atom format data))
+
+             ((and (> (length message-atom) 4) ; XDND protocol.
+                   (equal "Xdnd" (substring message-atom 0 4)))
+              (x-dnd-handle-xdnd event frame window message-atom format data)))))))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -425,8 +448,6 @@ otherwise return the frame coordinates."
 (declare-function x-get-atom-name "xselect.c" (value &optional frame))
 (declare-function x-send-client-message "xselect.c"
                  (display dest from message-type format values))
-(declare-function x-get-selection-internal "xselect.c"
-                 (selection-symbol target-type &optional time-stamp terminal))
 
 (defun x-dnd-version-from-flags (flags)
   "Return the version byte from the 32 bit FLAGS in an XDndEnter message."
index 6bd43511f8d8b2440bd94f4989b55bd8a01e42bc..deb6d62a27e4cf6269da87b0f422492a7b0b52a0 100644 (file)
@@ -1396,6 +1396,9 @@ x_dnd_send_enter (struct frame *f, Window target, int supported)
   int i;
   XEvent msg;
 
+  if (x_top_window_to_frame (dpyinfo, target))
+    return;
+
   msg.xclient.type = ClientMessage;
   msg.xclient.message_type = dpyinfo->Xatom_XdndEnter;
   msg.xclient.format = 32;
@@ -1443,6 +1446,9 @@ x_dnd_send_position (struct frame *f, Window target, int supported,
        return;
     }
 
+  if (x_top_window_to_frame (dpyinfo, target))
+    return;
+
   msg.xclient.type = ClientMessage;
   msg.xclient.message_type = dpyinfo->Xatom_XdndPosition;
   msg.xclient.format = 32;
@@ -1470,6 +1476,9 @@ x_dnd_send_leave (struct frame *f, Window target)
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   XEvent msg;
 
+  if (x_top_window_to_frame (dpyinfo, target))
+    return;
+
   msg.xclient.type = ClientMessage;
   msg.xclient.message_type = dpyinfo->Xatom_XdndLeave;
   msg.xclient.format = 32;
@@ -1491,6 +1500,62 @@ x_dnd_send_drop (struct frame *f, Window target, Time timestamp,
 {
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   XEvent msg;
+  struct input_event ie;
+  struct frame *self_frame;
+  int root_x, root_y, win_x, win_y, i;
+  unsigned int mask;
+  Window root, child;
+  Lisp_Object lval;
+  char **atom_names;
+  char *name;
+
+  self_frame = x_top_window_to_frame (dpyinfo, target);
+
+  if (self_frame)
+    {
+      /* Send a special drag-and-drop event when dropping on top of an
+        Emacs frame to avoid all the overhead involved with sending
+        client events.  */
+      EVENT_INIT (ie);
+
+      if (XQueryPointer (dpyinfo->display, FRAME_X_WINDOW (self_frame),
+                        &root, &child, &root_x, &root_y, &win_x, &win_y,
+                        &mask))
+       {
+         ie.kind = DRAG_N_DROP_EVENT;
+         XSETFRAME (ie.frame_or_window, self_frame);
+
+         lval = Qnil;
+         atom_names = alloca (x_dnd_n_targets * sizeof *atom_names);
+         name = XGetAtomName (dpyinfo->display, x_dnd_wanted_action);
+
+         if (!XGetAtomNames (dpyinfo->display, x_dnd_targets,
+                             x_dnd_n_targets, atom_names))
+           {
+             XFree (name);
+             return;
+           }
+
+         for (i = x_dnd_n_targets; i != 0; --i)
+           {
+             lval = Fcons (intern (atom_names[i - 1]), lval);
+             XFree (atom_names[i - 1]);
+           }
+
+         lval = Fcons (intern (name), lval);
+         lval = Fcons (QXdndSelection, lval);
+         ie.arg = lval;
+         ie.timestamp = CurrentTime;
+
+         XSETINT (ie.x, win_x);
+         XSETINT (ie.y, win_y);
+
+         XFree (name);
+         kbd_buffer_store_event (&ie);
+
+         return;
+       }
+    }
 
   msg.xclient.type = ClientMessage;
   msg.xclient.message_type = dpyinfo->Xatom_XdndDrop;