]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve drag and drop on MS-Windows (bug#3468)
authorCecilio Pardo <cpardo@imayhem.com>
Wed, 23 Oct 2024 12:41:24 +0000 (14:41 +0200)
committerEshel Yaron <me@eshelyaron.com>
Sat, 26 Oct 2024 16:44:41 +0000 (18:44 +0200)
Add support for 'dnd-scroll-margin' and 'dnd-indicate-insertion-point'
by calling 'dnd-handle-movement' when dragging the mouse.

* lisp/term/w32-win.el (w32-drag-n-drop): Call 'dnd-handle-movement'
when applicable.
* src/w32fns.c (w32_handle_drag_movement): New function, sends a
WM_EMACS_DRAGOVER message.
(w32_drop_target_DragEnter): Call 'w32_handle_drag_movement'.
(w32_drop_target_DragOver): Call 'w32_handle_drag_movement'.
* src/w32term.c: (w32_read_socket): Handle WM_EMACS_DRAGOVER,
sending a drag-n-drop event.
* src/w32term.h: Define new WM_EMACS_DRAGOVER message.

(cherry picked from commit 3eb2a85d10e0ad7b50e96ee4e80ba08b3a71b9ae)

etc/NEWS
lisp/term/w32-win.el
src/w32fns.c
src/w32term.c
src/w32term.h

index 3fd3623efb7064637a67ae04680b2c6cf72417be..4e8c9b86fc5d61010a9ce3e0d01dfec6202266f6 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -707,7 +707,9 @@ and later versions.
 
 ---
 ** Emacs on MS-Windows now supports drag-n-drop of text into a buffer.
-This is in addition to drag-n-drop of files, that was already supported.
+This is in addition to drag-n-drop of files, that was already
+supported. The configuration variables 'dnd-scroll-margin' and
+'dnd-indicate-insertion-point' can be used to customize the process.
 
 
 \f
index 541fef2ced3cacf2123ef41a773b51b7a9aa0901..75f8530010cab25737f43e93e951f6e8acd73ce8 100644 (file)
@@ -137,35 +137,40 @@ buffers, and switch to the buffer that visits the last dropped file.
 If EVENT is for text, insert that text at point into the buffer
 shown in the window that is the target of the drop; if that buffer is
 read-only, add the dropped text to kill-ring.
+If EVENT payload is nil, then this is a drag event.
 If the optional argument NEW-FRAME is non-nil, perform the
 drag-n-drop action in a newly-created frame using its selected-window
 and that window's buffer."
   (interactive "e")
-  (save-excursion
-    ;; Make sure the drop target has positive co-ords
-    ;; before setting the selected frame - otherwise it
-    ;; won't work.  <skx@tardis.ed.ac.uk>
-    (let* ((window (posn-window (event-start event)))
-          (coords (posn-x-y (event-start event)))
-           (arg (car (cdr (cdr event))))
-          (x (car coords))
-          (y (cdr coords)))
-      (if (and (> x 0) (> y 0))
-         (set-frame-selected-window nil window))
-
-      (when new-frame
-        (select-frame (make-frame)))
-      (raise-frame)
-      (setq window (selected-window))
-
-      ;; arg (the payload of the event) is a string when the drop is
-      ;; text, and a list of strings when the drop is one or more files.
-      (if (stringp arg)
-          (dnd-insert-text window 'copy arg)
-        (dnd-handle-multiple-urls
-         window
-         (mapcar #'w32-dropped-file-to-url arg)
-         'private)))))
+  ;; Make sure the drop target has positive co-ords
+  ;; before setting the selected frame - otherwise it
+  ;; won't work.  <skx@tardis.ed.ac.uk>
+  (let* ((window (posn-window (event-start event)))
+        (coords (posn-x-y (event-start event)))
+         (arg (car (cdr (cdr event))))
+        (x (car coords))
+        (y (cdr coords)))
+
+    (if (and (> x 0) (> y 0) (window-live-p window))
+        (set-frame-selected-window nil window))
+    ;; Don't create new frame if we are just dragging
+    (and arg new-frame
+         (select-frame (make-frame)))
+    (raise-frame)
+    (setq window (selected-window))
+
+    ;; arg (the payload of the event) is a string when the drop is
+    ;; text, and a list of strings when the drop is one or more files.
+    ;; It is nil if the event is a drag event.
+    (if arg
+        (save-excursion
+          (if (stringp arg)
+              (dnd-insert-text window 'copy arg)
+            (dnd-handle-multiple-urls
+             window
+             (mapcar #'w32-dropped-file-to-url arg)
+             'private)))
+      (dnd-handle-movement (event-start event)))))
 
 (defun w32-drag-n-drop-other-frame (event)
   "Edit the files listed in the drag-n-drop EVENT, in other frames.
index 3ee13dcbbdda8ce0a2f8a045940ef3ccbd29a439..eb42d3b61b2e041d0f580460ce6c3b606e62738c 100644 (file)
@@ -2505,7 +2505,6 @@ process_dropfiles (DROPFILES *files)
   return lisp_files;
 }
 
-
 /* This function can be called ONLY between calls to
    block_input/unblock_input.  It is used in w32_read_socket.  */
 Lisp_Object
@@ -2572,6 +2571,19 @@ w32_drop_target_Release (IDropTarget *This)
   return 0;
 }
 
+static void
+w32_handle_drag_movement (IDropTarget *This, POINTL pt)
+{
+  struct w32_drop_target *target = (struct w32_drop_target *)This;
+
+  W32Msg msg = {0};
+  msg.dwModifiers = w32_get_modifiers ();
+  msg.msg.time = GetMessageTime ();
+  msg.msg.pt.x = pt.x;
+  msg.msg.pt.y = pt.y;
+  my_post_msg (&msg, target->hwnd, WM_EMACS_DRAGOVER, 0, 0 );
+}
+
 static HRESULT STDMETHODCALLTYPE
 w32_drop_target_DragEnter (IDropTarget *This, IDataObject *pDataObj,
                           DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
@@ -2581,6 +2593,7 @@ w32_drop_target_DragEnter (IDropTarget *This, IDataObject *pDataObj,
      happen on drop.  We send COPY because our use cases don't modify
      or link to the original data.  */
   *pdwEffect = DROPEFFECT_COPY;
+  w32_handle_drag_movement (This, pt);
   return S_OK;
 }
 
@@ -2590,6 +2603,7 @@ w32_drop_target_DragOver (IDropTarget *This, DWORD grfKeyState, POINTL pt,
 {
   /* See comment in w32_drop_target_DragEnter.  */
   *pdwEffect = DROPEFFECT_COPY;
+  w32_handle_drag_movement (This, pt);
   return S_OK;
 }
 
@@ -3607,6 +3621,7 @@ w32_name_of_message (UINT msg)
       M (WM_EMACS_PAINT),
       M (WM_EMACS_IME_STATUS),
       M (WM_CHAR),
+      M (WM_EMACS_DRAGOVER),
       M (WM_EMACS_DROP),
 #undef M
       { 0, 0 }
index 3a627308137186bcbb7208151f319aeffd6a46bd..886227003866d5be48ab1721241aebfe511d7ee8 100644 (file)
@@ -5629,6 +5629,24 @@ w32_read_socket (struct terminal *terminal,
          }
          break;
 
+       case WM_EMACS_DRAGOVER:
+         {
+           f = w32_window_to_frame (dpyinfo, msg.msg.hwnd);
+           if (!f)
+             break;
+           XSETFRAME (inev.frame_or_window, f);
+           inev.kind = DRAG_N_DROP_EVENT;
+           inev.code = 0;
+           inev.timestamp = msg.msg.time;
+           inev.modifiers = msg.dwModifiers;
+           ScreenToClient (msg.msg.hwnd, &msg.msg.pt);
+           XSETINT (inev.x, msg.msg.pt.x);
+           XSETINT (inev.y, msg.msg.pt.y);
+           /* This is a drag movement.  */
+           inev.arg = Qnil;
+           break;
+         }
+
        case WM_HSCROLL:
          {
            struct scroll_bar *bar =
index 39e2262e2a84dd480bc20ddd8cec770c2e4d94e6..cad9fcf8cb11d32637967a5170b34d2c79160e25 100644 (file)
@@ -711,8 +711,9 @@ do { \
 #define WM_EMACS_INPUT_READY           (WM_EMACS_START + 24)
 #define WM_EMACS_FILENOTIFY            (WM_EMACS_START + 25)
 #define WM_EMACS_IME_STATUS            (WM_EMACS_START + 26)
-#define WM_EMACS_DROP                  (WM_EMACS_START + 27)
-#define WM_EMACS_END                   (WM_EMACS_START + 28)
+#define WM_EMACS_DRAGOVER              (WM_EMACS_START + 27)
+#define WM_EMACS_DROP                  (WM_EMACS_START + 28)
+#define WM_EMACS_END                   (WM_EMACS_START + 29)
 
 #define WND_FONTWIDTH_INDEX    (0)
 #define WND_LINEHEIGHT_INDEX   (4)