From e351e9037cbb7c63d7a022256bb87baa9990570d Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 2 Apr 2022 15:45:00 +0800 Subject: [PATCH] Add new option `mouse-drag-and-drop-region-scroll-margin' * etc/NEWS: Announce new user option. * lisp/mouse.el (mouse-drag-and-drop-region-scroll-margin): New user option. (mouse-drag-and-drop-region): Implement "scroll margin" like behavior during mouse movement. --- etc/NEWS | 5 +++++ lisp/mouse.el | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index 3df326aa5b3..9196e9fb909 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -190,6 +190,11 @@ methods instead. If non-nil, this option allows dragging text in the region from Emacs to another program. +--- +** New user option 'mouse-drag-and-drop-region-scroll-margin'. +If non-nil, this option allows scrolling a window while dragging text +around without a scroll wheel. + +++ ** New function 'command-query'. This function makes its argument command prompt the user for diff --git a/lisp/mouse.el b/lisp/mouse.el index 4d6acf0d926..5e56a9e9727 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el @@ -97,6 +97,14 @@ point at the click position." :type 'boolean :version "22.1") +(defcustom mouse-drag-and-drop-region-scroll-margin nil + "If non-nil, the scroll margin inside a window when dragging text. +If the mouse moves this many lines close to the top or bottom of +a window while dragging text, then that window will be scrolled +down and up respectively." + :type 'integer + :version "29.1") + (defvar mouse--last-down nil) (defun mouse--down-1-maybe-follows-link (&optional _prompt) @@ -3084,6 +3092,34 @@ is copied instead of being cut." ;; Handle `mouse-autoselect-window'. (memq (car event) '(select-window switch-frame)))) (catch 'drag-again + ;; If the mouse is in the drag scroll margin, scroll + ;; either up or down depending on which margin it is in. + (when mouse-drag-and-drop-region-scroll-margin + (let* ((row (cdr (posn-col-row (event-end event)))) + (window (posn-window (event-end event))) + (text-height (window-text-height window)) + ;; Make sure it's possible to scroll both up + ;; and down if the margin is too large for the + ;; window. + (margin (min (/ text-height 3) + mouse-drag-and-drop-region-scroll-margin))) + ;; At 2 lines, the window becomes too small for any + ;; meaningful scrolling. + (unless (<= text-height 2) + ;; We could end up at the beginning or end of the + ;; buffer. + (ignore-errors + (when (windowp window) + (cond + ;; Inside the bottom scroll margin, scroll up. + ((> row (- text-height margin)) + (with-selected-window window + (scroll-up 1))) + ;; Inside the top scroll margin, scroll down. + ((< row margin) + (with-selected-window window + (scroll-down 1))))))))) + ;; Obtain the dragged text in region. When the loop was ;; skipped, value-selection remains nil. (unless value-selection -- 2.39.2