From: Cecilio Pardo Date: Wed, 23 Oct 2024 12:41:24 +0000 (+0200) Subject: Improve drag and drop on MS-Windows (bug#3468) X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=67273d2cc20fd0b9ed28d0ea2c97490462f21e35;p=emacs.git 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 a drag-n-drop event. * src/w32term.h: Define new WM_EMACS_DRAGOVER message. (cherry picked from commit 3eb2a85d10e0ad7b50e96ee4e80ba08b3a71b9ae) --- diff --git a/etc/NEWS b/etc/NEWS index 3fd3623efb7..4e8c9b86fc5 100644 --- 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. diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el index 541fef2ced3..75f8530010c 100644 --- a/lisp/term/w32-win.el +++ b/lisp/term/w32-win.el @@ -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. - (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 + (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. 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 @@ 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 } 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 @@ 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)