emacs-diffs
[Top][All Lists]
Advanced

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

master 5359062be6: Avoid ClientMessage overhead when dragging stuff to o


From: Po Lu
Subject: master 5359062be6: Avoid ClientMessage overhead when dragging stuff to other frames
Date: Fri, 25 Mar 2022 22:16:07 -0400 (EDT)

branch: master
commit 5359062be603e22d1ee07c21b0840fdb98a704a3
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Avoid ClientMessage overhead when dragging stuff to other frames
    
    * 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 |  7 +++++--
 lisp/x-dnd.el | 55 ++++++++++++++++++++++++++++++++++----------------
 src/xterm.c   | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 108 insertions(+), 19 deletions(-)

diff --git a/lisp/dired.el b/lisp/dired.el
index c5e389c9ce..3c37a887ba 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -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)
diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el
index 0529d223db..e801c4fdfc 100644
--- a/lisp/x-dnd.el
+++ b/lisp/x-dnd.el
@@ -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."
diff --git a/src/xterm.c b/src/xterm.c
index 6bd43511f8..deb6d62a27 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -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;



reply via email to

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