From 5c0f2a1b40931824df75a620d2494f2031bf0f83 Mon Sep 17 00:00:00 2001 From: Cecilio Pardo Date: Wed, 23 Oct 2024 14:41:24 +0200 Subject: [PATCH] Improve drag and drop on MS-Windows (bug#3468) 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 an drag-n-drop event. * src/w32term.h (): Define new WM_EMACS_DRAGOVER message. --- lisp/term/w32-win.el | 54 ++++++++++++++++++++++++-------------------- src/w32fns.c | 17 +++++++++++++- src/w32term.c | 18 +++++++++++++++ src/w32term.h | 5 ++-- 4 files changed, 66 insertions(+), 28 deletions(-) diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el index 541fef2ced3..b47b5f21f05 100644 --- a/lisp/term/w32-win.el +++ b/lisp/term/w32-win.el @@ -137,35 +137,39 @@ w32-drag-n-drop 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. - (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. + (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 + (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. diff --git a/src/w32fns.c b/src/w32fns.c index 3ee13dcbbdd..eb42d3b61b2 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -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 @@ #define M(msg) { msg, # 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 } diff --git a/src/w32term.c b/src/w32term.c index 3a627308137..88622700386 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -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 = diff --git a/src/w32term.h b/src/w32term.h index 39e2262e2a8..cad9fcf8cb1 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -711,8 +711,9 @@ #define WM_EMACS_BRINGTOTOP (WM_EMACS_START + 23) #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) -- 2.35.1.windows.2