aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2019-10-25 11:16:39 +0200
committerMattias EngdegÄrd2019-11-27 13:40:29 +0100
commit4eb7db5d4b84708912c63a77569c8adeeff6c640 (patch)
treee4f014f3b2b2407ec74e875a8ef2ab3bc37b2225
parente7b4c248a6d2a2eca19a2a362103a7f24cfe30fc (diff)
downloademacs-4eb7db5d4b84708912c63a77569c8adeeff6c640.tar.gz
emacs-4eb7db5d4b84708912c63a77569c8adeeff6c640.zip
Mouse rectangular region selection (bug#38013)
Make it possible to select a rectangular region using the mouse. The standard binding is C-M-mouse-1. * lisp/mouse.el (mouse-scroll-subr): Add ADJUST argument. (mouse-drag-region-rectangle): New. * lisp/rect.el (rectangle--reset-point-crutches): New. (rectangle--reset-crutches): Use 'rectangle--reset-point-crutches'. * src/xdisp.c (remember_mouse_glyph, syms_of_xdisp): Add 'mouse-fine-grained-tracking'. * doc/lispref/commands.texi (Motion Events): Document 'mouse-fine-grained-tracking'. * doc/emacs/frames.texi (Mouse Commands): * doc/emacs/killing.texi (Rectangles): * etc/NEWS: Document rectangular selection with the mouse.
-rw-r--r--doc/emacs/frames.texi4
-rw-r--r--doc/emacs/killing.texi3
-rw-r--r--doc/lispref/commands.texi6
-rw-r--r--etc/NEWS3
-rw-r--r--lisp/mouse.el113
-rw-r--r--lisp/rect.el8
-rw-r--r--src/xdisp.c12
7 files changed, 146 insertions, 3 deletions
diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 091c011fb96..f6c2d239132 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -91,6 +91,10 @@ If the region is active, move the nearer end of the region to the
91click position; otherwise, set mark at the current value of point and 91click position; otherwise, set mark at the current value of point and
92point at the click position. Save the resulting region in the kill 92point at the click position. Save the resulting region in the kill
93ring; on a second click, kill it (@code{mouse-save-then-kill}). 93ring; on a second click, kill it (@code{mouse-save-then-kill}).
94
95@item C-M-mouse-1
96Activate a rectangular region around the text selected by dragging.
97@xref{Rectangles}.
94@end table 98@end table
95 99
96@findex mouse-set-point 100@findex mouse-set-point
diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi
index 80e2868908a..ce00cb38a74 100644
--- a/doc/emacs/killing.texi
+++ b/doc/emacs/killing.texi
@@ -732,6 +732,9 @@ region is controlled. But remember that a given combination of point
732and mark values can be interpreted either as a region or as a 732and mark values can be interpreted either as a region or as a
733rectangle, depending on the command that uses them. 733rectangle, depending on the command that uses them.
734 734
735 A rectangular region can also be marked using the mouse: click and drag
736@kbd{C-M-mouse-1} from one corner of the rectangle to the opposite.
737
735@table @kbd 738@table @kbd
736@item C-x r k 739@item C-x r k
737Kill the text of the region-rectangle, saving its contents as the 740Kill the text of the region-rectangle, saving its contents as the
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 0c848a80257..032f005e9c4 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -1661,6 +1661,12 @@ events within its body. Outside of @code{track-mouse} forms, Emacs
1661does not generate events for mere motion of the mouse, and these 1661does not generate events for mere motion of the mouse, and these
1662events do not appear. @xref{Mouse Tracking}. 1662events do not appear. @xref{Mouse Tracking}.
1663 1663
1664@defvar mouse-fine-grained-tracking
1665When non-@code{nil}, mouse motion events are generated even for very
1666small movements. Otherwise, motion events are not generated as long
1667as the mouse cursor remains pointing to the same glyph in the text.
1668@end defvar
1669
1664@node Focus Events 1670@node Focus Events
1665@subsection Focus Events 1671@subsection Focus Events
1666@cindex focus event 1672@cindex focus event
diff --git a/etc/NEWS b/etc/NEWS
index 98a35206225..8233328fa3c 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -614,6 +614,9 @@ arguments mitigating performance issues when operating on huge
614buffers. 614buffers.
615 615
616+++ 616+++
617** Dragging 'C-M-mouse-1' now marks rectangular regions.
618
619+++
617** The command 'delete-indentation' now operates on the active region. 620** The command 'delete-indentation' now operates on the active region.
618If the region is active, the command joins all the lines in the 621If the region is active, the command joins all the lines in the
619region. When there's no active region, the command works on the 622region. When there's no active region, the command works on the
diff --git a/lisp/mouse.el b/lisp/mouse.el
index c91760a7348..f076e90bd93 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1045,10 +1045,12 @@ the mouse has moved. However, it always scrolls at least the number
1045of lines specified by this variable." 1045of lines specified by this variable."
1046 :type 'integer) 1046 :type 'integer)
1047 1047
1048(defun mouse-scroll-subr (window jump &optional overlay start) 1048(defun mouse-scroll-subr (window jump &optional overlay start adjust)
1049 "Scroll the window WINDOW, JUMP lines at a time, until new input arrives. 1049 "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
1050If OVERLAY is an overlay, let it stretch from START to the far edge of 1050If OVERLAY is an overlay, let it stretch from START to the far edge of
1051the newly visible text. 1051the newly visible text.
1052ADJUST, if non-nil, is a function, without arguments, to call after
1053setting point.
1052Upon exit, point is at the far edge of the newly visible text." 1054Upon exit, point is at the far edge of the newly visible text."
1053 (cond 1055 (cond
1054 ((and (> jump 0) (< jump mouse-scroll-min-lines)) 1056 ((and (> jump 0) (< jump mouse-scroll-min-lines))
@@ -1077,6 +1079,8 @@ Upon exit, point is at the far edge of the newly visible text."
1077 ;; so that we don't mess up the selected window. 1079 ;; so that we don't mess up the selected window.
1078 (or (eq window (selected-window)) 1080 (or (eq window (selected-window))
1079 (goto-char opoint)) 1081 (goto-char opoint))
1082 (when adjust
1083 (funcall adjust))
1080 (sit-for mouse-scroll-delay))))) 1084 (sit-for mouse-scroll-delay)))))
1081 (or (eq window (selected-window)) 1085 (or (eq window (selected-window))
1082 (goto-char opoint)))) 1086 (goto-char opoint))))
@@ -1960,6 +1964,113 @@ When there is no region, this function does nothing."
1960 (move-overlay mouse-secondary-overlay (region-beginning) (region-end)))) 1964 (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
1961 1965
1962 1966
1967(defun mouse-drag-region-rectangle (start-event)
1968 "Set the region to the rectangle that the mouse is dragged over.
1969This must be bound to a button-down mouse event."
1970 (interactive "e")
1971 (let* ((scroll-margin 0)
1972 (start-pos (event-start start-event))
1973 (start-posn (event-start start-event))
1974 (start-point (posn-point start-posn))
1975 (start-window (posn-window start-posn))
1976 (start-hscroll (window-hscroll start-window))
1977 (start-col (+ (car (posn-col-row start-pos)) start-hscroll))
1978 (bounds (window-edges start-window))
1979 (top (nth 1 bounds))
1980 (bottom (if (window-minibuffer-p start-window)
1981 (nth 3 bounds)
1982 (1- (nth 3 bounds))))
1983 (dragged nil)
1984 (old-track-mouse track-mouse)
1985 (old-mouse-fine-grained-tracking mouse-fine-grained-tracking)
1986 ;; For right-to-left text, columns are counted from the right margin;
1987 ;; translate from mouse events, which always count from the left.
1988 (adjusted-col (lambda (col)
1989 (if (eq (current-bidi-paragraph-direction)
1990 'right-to-left)
1991 (- (frame-text-cols) col -1)
1992 col)))
1993 (map (make-sparse-keymap)))
1994 (define-key map [switch-frame] #'ignore)
1995 (define-key map [select-window] #'ignore)
1996 (define-key map [mouse-movement]
1997 (lambda (event)
1998 (interactive "e")
1999 (unless dragged
2000 ;; This is actually a drag.
2001 (setq dragged t)
2002 (mouse-minibuffer-check start-event)
2003 (deactivate-mark)
2004 (posn-set-point start-pos)
2005 (rectangle-mark-mode)
2006 ;; Only tell rectangle about the exact column if we are possibly
2007 ;; beyond end-of-line or in a tab, since the column we got from
2008 ;; the mouse position isn't necessarily accurate for use in
2009 ;; specifying a rectangle (which uses the `move-to-column'
2010 ;; measure).
2011 (when (or (eolp) (eq (following-char) ?\t))
2012 (let ((col (funcall adjusted-col start-col)))
2013 (rectangle--col-pos col 'mark)
2014 (rectangle--col-pos col 'point))))
2015
2016 (let* ((posn (event-end event))
2017 (window (posn-window posn))
2018 (hscroll (if (window-live-p window)
2019 (window-hscroll window)
2020 0))
2021 (mouse-pos (mouse-position))
2022 (mouse-col (+ (cadr mouse-pos) hscroll))
2023 (mouse-row (cddr mouse-pos))
2024 (set-col (lambda ()
2025 (if (or (eolp) (eq (following-char) ?\t))
2026 (rectangle--col-pos
2027 (funcall adjusted-col mouse-col) 'point)
2028 (rectangle--reset-point-crutches)))))
2029 (if (and (eq window start-window)
2030 mouse-row
2031 (<= top mouse-row (1- bottom)))
2032 ;; Drag inside the same window.
2033 (progn
2034 (posn-set-point posn)
2035 (funcall set-col))
2036 ;; Drag outside the window: scroll.
2037 (cond
2038 ((null mouse-row))
2039 ((< mouse-row top)
2040 (mouse-scroll-subr
2041 start-window (- mouse-row top) nil start-point
2042 set-col))
2043 ((>= mouse-row bottom)
2044 (mouse-scroll-subr
2045 start-window (1+ (- mouse-row bottom)) nil start-point
2046 set-col)))))))
2047 (condition-case err
2048 (progn
2049 (setq track-mouse t)
2050 (setq mouse-fine-grained-tracking t)
2051 (set-transient-map
2052 map t
2053 (lambda ()
2054 (setq track-mouse old-track-mouse)
2055 (setq mouse-fine-grained-tracking old-mouse-fine-grained-tracking)
2056 (when (or (not dragged)
2057 (not (mark))
2058 (equal (rectangle-dimensions (mark) (point)) '(0 . 1)))
2059 ;; No nontrivial region selected; deactivate rectangle mode.
2060 (deactivate-mark)))))
2061 ;; Clean up in case something went wrong.
2062 (error (setq track-mouse old-track-mouse)
2063 (setq mouse-fine-grained-tracking old-mouse-fine-grained-tracking)
2064 (signal (car err) (cdr err))))))
2065
2066;; The drag event must be bound to something but does not need any effect,
2067;; as everything takes place in `mouse-drag-region-rectangle'.
2068;; The click event can be anything; `mouse-set-point' is just a convenience.
2069(global-set-key [C-M-down-mouse-1] #'mouse-drag-region-rectangle)
2070(global-set-key [C-M-drag-mouse-1] #'ignore)
2071(global-set-key [C-M-mouse-1] #'mouse-set-point)
2072
2073
1963(defcustom mouse-buffer-menu-maxlen 20 2074(defcustom mouse-buffer-menu-maxlen 20
1964 "Number of buffers in one pane (submenu) of the buffer menu. 2075 "Number of buffers in one pane (submenu) of the buffer menu.
1965If we have lots of buffers, divide them into groups of 2076If we have lots of buffers, divide them into groups of
diff --git a/lisp/rect.el b/lisp/rect.el
index 4d4d6146f21..1109786fc5b 100644
--- a/lisp/rect.el
+++ b/lisp/rect.el
@@ -133,11 +133,15 @@ Point is at the end of the segment of this line within the rectangle."
133(defun rectangle--crutches () 133(defun rectangle--crutches ()
134 (cons rectangle--mark-crutches 134 (cons rectangle--mark-crutches
135 (window-parameter nil 'rectangle--point-crutches))) 135 (window-parameter nil 'rectangle--point-crutches)))
136(defun rectangle--reset-crutches () 136
137 (kill-local-variable 'rectangle--mark-crutches) 137(defun rectangle--reset-point-crutches ()
138 (if (window-parameter nil 'rectangle--point-crutches) 138 (if (window-parameter nil 'rectangle--point-crutches)
139 (setf (window-parameter nil 'rectangle--point-crutches) nil))) 139 (setf (window-parameter nil 'rectangle--point-crutches) nil)))
140 140
141(defun rectangle--reset-crutches ()
142 (kill-local-variable 'rectangle--mark-crutches)
143 (rectangle--reset-point-crutches))
144
141;;; Rectangle operations. 145;;; Rectangle operations.
142 146
143(defun apply-on-rectangle (function start end &rest args) 147(defun apply-on-rectangle (function start end &rest args)
diff --git a/src/xdisp.c b/src/xdisp.c
index 2b4dda27157..c4d23be4cde 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2491,6 +2491,12 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
2491 enum glyph_row_area area; 2491 enum glyph_row_area area;
2492 int x, y, width, height; 2492 int x, y, width, height;
2493 2493
2494 if (mouse_fine_grained_tracking)
2495 {
2496 STORE_NATIVE_RECT (*rect, gx, gy, 1, 1);
2497 return;
2498 }
2499
2494 /* Try to determine frame pixel position and size of the glyph under 2500 /* Try to determine frame pixel position and size of the glyph under
2495 frame pixel coordinates X/Y on frame F. */ 2501 frame pixel coordinates X/Y on frame F. */
2496 2502
@@ -34946,6 +34952,12 @@ The default is to use octal format (\200) whereas hexadecimal (\x80)
34946may be more familiar to users. */); 34952may be more familiar to users. */);
34947 display_raw_bytes_as_hex = false; 34953 display_raw_bytes_as_hex = false;
34948 34954
34955 DEFVAR_BOOL ("mouse-fine-grained-tracking", mouse_fine_grained_tracking,
34956 doc: /* Non-nil for pixel-wise mouse-movement.
34957When nil, mouse-movement events will not be generated as long as the
34958mouse stays within the extent of a single glyph (except for images). */);
34959 mouse_fine_grained_tracking = false;
34960
34949} 34961}
34950 34962
34951 34963