all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* bug#38013: [PATCH] Rectangular region selection with mouse
@ 2019-10-31 21:55 Mattias Engdegård
  2019-11-01  0:12 ` Drew Adams
  2019-11-01  7:51 ` Eli Zaretskii
  0 siblings, 2 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-10-31 21:55 UTC (permalink / raw)
  To: 38013

[-- Attachment #1: Type: text/plain, Size: 761 bytes --]

This is a proposal to add mouse-selection of rectangular regions. It turns out to be useful; Emacs should come with the facility built-in.

The main problem is what to bind it to. The common modifiers (shift, control, meta) are already taken. Platforms have different "standard" modifiers: Option on macOS, Alt on Windows, Control in Gnome (?).

Assuming that the secondary selection is somewhat of an anachronism which is likely to be less used today than the rectangular one would be, the patch uses Meta as default modifier. Both secondary and rectangular mouse selection have defcustoms permitting easy change.

The defaults could be different, for example if secondary mouse selection turns out to be very popular.
There is no documentation yet.


[-- Attachment #2: 0001-Mouse-rectangular-region-selection.patch --]
[-- Type: application/octet-stream, Size: 7307 bytes --]

From e8d781baf8ffd0cd911505a50ffefa0f54d2d185 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Fri, 25 Oct 2019 11:16:39 +0200
Subject: [PATCH] Mouse rectangular region selection

Make it possible to select a rectangular region using the mouse.
The modifier is customisable and defaults to meta.
The modifier for mouse secondary selection is now also customisable and
defaults to nil (disabled).

* lisp/mouse.el (mouse-scroll-subr): Add COLUMN argument.
(mouse-drag-region-rectangle): New.
(mouse--global-with-modifier)
(mouse--set-secondary-selection-bindings, mouse-secondary-selection-modifier)
(mouse--set-rectangular-region-selection-bindings)
(mouse-region-rectangle-modifier): New defcustoms with helper functions.
---
 lisp/mouse.el | 110 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 104 insertions(+), 6 deletions(-)

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 4a351f7be2..48ea109daa 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1045,10 +1045,11 @@ mouse-scroll-min-lines
 of lines specified by this variable."
   :type 'integer)
 
-(defun mouse-scroll-subr (window jump &optional overlay start)
+(defun mouse-scroll-subr (window jump &optional overlay start column)
   "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
 If OVERLAY is an overlay, let it stretch from START to the far edge of
 the newly visible text.
+If COLUMN is non-nil, try to keep point in that column when scrolling.
 Upon exit, point is at the far edge of the newly visible text."
   (cond
    ((and (> jump 0) (< jump mouse-scroll-min-lines))
@@ -1077,6 +1078,8 @@ mouse-scroll-subr
 		   ;; so that we don't mess up the selected window.
 		   (or (eq window (selected-window))
 		       (goto-char opoint))
+                   (when column
+                     (move-to-column column))
 		   (sit-for mouse-scroll-delay)))))
     (or (eq window (selected-window))
 	(goto-char opoint))))
@@ -1666,11 +1669,43 @@ mouse-save-then-kill
       (setq mouse-save-then-kill-posn click-pt)))))
 
 \f
-(global-set-key [M-mouse-1] 'mouse-start-secondary)
-(global-set-key [M-drag-mouse-1] 'mouse-set-secondary)
-(global-set-key [M-down-mouse-1] 'mouse-drag-secondary)
-(global-set-key [M-mouse-3] 'mouse-secondary-save-then-kill)
-(global-set-key [M-mouse-2] 'mouse-yank-secondary)
+(defun mouse--global-with-modifier (base modifier command)
+  "Globally bind BASE + MODIFIER to COMMAND."
+  (global-set-key (vector (event-convert-list (list modifier base))) command))
+
+(defun mouse--set-secondary-selection-bindings (mod activate)
+  "Set global mouse bindings using MOD for secondary selection.
+If ACTIVATE is nil, remove those bindings."
+  (when mod
+    (mouse--global-with-modifier 'mouse-1 mod
+                                 (and activate 'mouse-start-secondary))
+    (mouse--global-with-modifier 'drag-mouse-1 mod
+                                 (and activate 'mouse-set-secondary))
+    (mouse--global-with-modifier 'down-mouse-1 mod
+                                 (and activate 'mouse-drag-secondary))
+    (mouse--global-with-modifier 'mouse-3 mod
+                                 (and activate 'mouse-secondary-save-then-kill))
+    (mouse--global-with-modifier 'mouse-2 mod
+                                 (and activate 'mouse-yank-secondary))))
+
+(defcustom mouse-secondary-selection-modifier nil
+  "The modifier key for secondary selection using the mouse.
+If nil, mouse secondary selection is disabled."
+  :group 'mouse
+  :type '(choice (const :tag "None (disabled)" nil)
+                 (const meta)
+                 (const control)
+                 (const shift)
+                 (const super)
+                 (const hyper))
+  :version "27.1"
+  :set (lambda (variable new-value)
+         (when (boundp 'mouse-secondary-selection-modifier)
+           (mouse--set-secondary-selection-bindings
+            mouse-secondary-selection-modifier nil))
+         (set-default variable new-value)
+         (mouse--set-secondary-selection-bindings
+          mouse-secondary-selection-modifier t)))
 
 (defconst mouse-secondary-overlay
   (let ((ol (make-overlay (point-min) (point-min))))
@@ -1960,6 +1995,69 @@ secondary-selection-from-region
     (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
 
 \f
+(defun mouse-drag-region-rectangle (start-event)
+  "Set the region to the rectangle that the mouse is dragged over.
+This must be bound to a button-down mouse event."
+  (interactive "e")
+  (deactivate-mark)
+  (mouse-set-point start-event)
+  (rectangle-mark-mode)
+  (let* ((scroll-margin 0)
+         (start-posn (event-start start-event))
+         (start-point (posn-point start-posn))
+         (start-window (posn-window start-posn))
+         (bounds (window-edges start-window))
+         (top (nth 1 bounds))
+         (bottom (if (window-minibuffer-p start-window)
+                     (nth 3 bounds)
+                   (1- (nth 3 bounds))))
+         event)
+    (track-mouse
+      (while (progn
+               (setq event (read-event))
+               (mouse-movement-p event))
+        (let ((window (posn-window (event-end event)))
+              (mouse-row (cddr (mouse-position))))
+          (if (and (eq window start-window)
+                   mouse-row
+                   (<= top mouse-row (1- bottom)))
+              (mouse-set-point event)
+            (cond
+             ((null mouse-row))
+             ((< mouse-row top)
+              (mouse-scroll-subr start-window (- mouse-row top)
+                                 nil start-point (current-column)))
+             ((>= mouse-row bottom)
+              (mouse-scroll-subr start-window (1+ (- mouse-row bottom))
+                                 nil start-point (current-column))))))))))
+
+(defun mouse--set-rectangular-region-selection-bindings (mod activate)
+  "Set global mouse bindings using MOD for rectangular selection.
+If ACTIVATE is nil, remove those bindings."
+  (when mod
+    (mouse--global-with-modifier 'down-mouse-1 mod
+                                 (and activate 'mouse-drag-region-rectangle))))
+
+(defcustom mouse-region-rectangle-modifier 'meta
+  "The modifier key for rectangular region selection using the mouse.
+If nil, mouse rectangular region selection is disabled."
+  :group 'mouse
+  :type '(choice (const :tag "None (disabled)" nil)
+                 (const meta)
+                 (const control)
+                 (const shift)
+                 (const super)
+                 (const hyper))
+  :version "27.1"
+  :set (lambda (variable new-value)
+         (when (boundp 'mouse-region-rectangle-modifier)
+           (mouse--set-rectangular-region-selection-bindings
+            mouse-region-rectangle-modifier nil))
+         (set-default variable new-value)
+         (mouse--set-rectangular-region-selection-bindings
+          mouse-region-rectangle-modifier t)))
+
+\f
 (defcustom mouse-buffer-menu-maxlen 20
   "Number of buffers in one pane (submenu) of the buffer menu.
 If we have lots of buffers, divide them into groups of
-- 
2.21.0 (Apple Git-122)


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-10-31 21:55 bug#38013: [PATCH] Rectangular region selection with mouse Mattias Engdegård
@ 2019-11-01  0:12 ` Drew Adams
  2019-11-01  7:51 ` Eli Zaretskii
  1 sibling, 0 replies; 55+ messages in thread
From: Drew Adams @ 2019-11-01  0:12 UTC (permalink / raw)
  To: Mattias Engdegård, 38013

> This is a proposal to add mouse-selection of rectangular regions. It
> turns out to be useful; Emacs should come with the facility built-in.
> 
> The main problem is what to bind it to. The common modifiers (shift,
> control, meta) are already taken. Platforms have different "standard"
> modifiers: Option on macOS, Alt on Windows, Control in Gnome (?).
> 
> Assuming that the secondary selection is somewhat of an anachronism
> which is likely to be less used today than the rectangular one would
> be, the patch uses Meta as default modifier. Both secondary and
> rectangular mouse selection have defcustoms permitting easy change.
> 
> The defaults could be different, for example if secondary mouse
> selection turns out to be very popular.
> There is no documentation yet.

FWIW -

1. I like the general idea of being able to use
the mouse to directly define a rectangular region.
_Good initiative_.

2. But I disagree completely that the secondary
selection is an anachronism.

IMO it is not used as much as it could (and should
and would) be used in Emacs only because it has no
_keyboard_ bindings, by default.

I use C-M-y to do all of this: 

* yank the secondary                 (no pref arg)
* select the secondary as the region (pref arg = 0)
* move the secondary to the region   (pref arg > 0)
* swap the secondary and the region  (pref arg < 0)

The 3rd and 4th of those set the secondary with just
the keyboard - from the region.  Another way to set
it using just the keyboard is to use C-x C-M-SPC to
start it and C-x C-M-<return> to end it.

(And I use C-M-y during Isearch to yank the secondary
to the end of the search string.)

The secondary selection is different from the region.
Its advantage, and its disadvantage, is that it is
liberated from point - it need not even be currently
visible in a window.  It doesn't change just because
you move the cursor around.

The region has a ring, `kill-ring', to let you get
previous selections.  I do the same thing for the
secondary selection, as well - give it a ring.  And
if the previous command yanked the secondary then
M-y yank-pops the secondary ring (not the kill-ring),
to replace that yank with the previous secondary on
the ring.

https://www.emacswiki.org/emacs/SecondarySelection#second-sel.el





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-10-31 21:55 bug#38013: [PATCH] Rectangular region selection with mouse Mattias Engdegård
  2019-11-01  0:12 ` Drew Adams
@ 2019-11-01  7:51 ` Eli Zaretskii
  2019-11-01 11:53   ` Mattias Engdegård
  1 sibling, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2019-11-01  7:51 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

> From: Mattias Engdegård <mattiase@acm.org>
> Date: Thu, 31 Oct 2019 22:55:26 +0100
> 
> This is a proposal to add mouse-selection of rectangular regions. It turns out to be useful; Emacs should come with the facility built-in.

Could you please tell how to try and test this feature?  The patch
comes without any documentation, so it's hard to understand quickly
what to do to see this in action.

> The main problem is what to bind it to. The common modifiers (shift, control, meta) are already taken. Platforms have different "standard" modifiers: Option on macOS, Alt on Windows, Control in Gnome (?).
> 
> Assuming that the secondary selection is somewhat of an anachronism which is likely to be less used today than the rectangular one would be, the patch uses Meta as default modifier. Both secondary and rectangular mouse selection have defcustoms permitting easy change.

I'd prefer not to step on another feature, if possible.  How about
defining a minor mode, and then using the usual mouse selection
gestures instead?  That would be more natural, IMO, and will not
require users to give up another feature.

Thanks.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-01  7:51 ` Eli Zaretskii
@ 2019-11-01 11:53   ` Mattias Engdegård
  2019-11-01 13:17     ` Eli Zaretskii
  2019-11-01 13:23     ` martin rudalics
  0 siblings, 2 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-01 11:53 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 38013

1 nov. 2019 kl. 08.51 skrev Eli Zaretskii <eliz@gnu.org>:

> Could you please tell how to try and test this feature?  The patch
> comes without any documentation, so it's hard to understand quickly
> what to do to see this in action.

With the default settings, click and drag (mouse button 1) with meta held to mark a rectangular region.
Sorry about the lack of documentation; it will be written once we agree on the design.

> I'd prefer not to step on another feature, if possible.  How about
> defining a minor mode, and then using the usual mouse selection
> gestures instead?  That would be more natural, IMO, and will not
> require users to give up another feature.

Very much agree that other features should be left alone, but in this case there seemed to be no really good unused binding.
A minor mode is less ideal: rectangular selection is something the user wants to be able to do on a whim, without having to plan ahead by activating a minor mode. It is also good to follow standard practice in other editors and terminal emulators

Competing mouse bindings are:

Meta: secondary selection
Shift: mouse-appearance-menu (mouse-save-then-kill for NS)
Control: mouse-buffer-menu

The secondary selection appeared weaker than the rest, in the sense that repurposing its binding would annoy fewer users than the alternatives. (Annoyed users can still regain the old behaviour by customisation.)

Other possibilities:

A. Unbind mouse-appearance-menu, mouse-save-then-kill or mouse-buffer-menu instead. The trade-offs are similar.
B. Combined modifiers (Shift-Meta etc). Less ergonomic; there may be platform restrictions.
C. Use a different mouse button. Diverges from other platforms; messy on Macs.
D. Less common modifiers (Super, Hyper). Many don't have them.
E. Follow the platform conventions. Not the Emacs tradition, and makes for more binding clashes.
F. Leaving rectangular selection unbound by default. This is tantamount to stating that it is less useful. Is it?







^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-01 11:53   ` Mattias Engdegård
@ 2019-11-01 13:17     ` Eli Zaretskii
  2019-11-01 13:30       ` Eli Zaretskii
  2019-11-01 13:23     ` martin rudalics
  1 sibling, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2019-11-01 13:17 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

> From: Mattias Engdegård <mattiase@acm.org>
> Date: Fri, 1 Nov 2019 12:53:44 +0100
> Cc: 38013@debbugs.gnu.org
> 
> With the default settings, click and drag (mouse button 1) with meta held to mark a rectangular region.

Thanks, I will try.

> A minor mode is less ideal: rectangular selection is something the user wants to be able to do on a whim, without having to plan ahead by activating a minor mode. It is also good to follow standard practice in other editors and terminal emulators

And yet cua-rect.el defined a command to enter this mode.

I don't really buy the "on a whim" argument; I think the user always
knows in advance whether the next selection will or won't be
rectangular.  So I still think a minor mode is the best solution, if
something like C-M-mouse-1 is not portable enough.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-01 11:53   ` Mattias Engdegård
  2019-11-01 13:17     ` Eli Zaretskii
@ 2019-11-01 13:23     ` martin rudalics
  1 sibling, 0 replies; 55+ messages in thread
From: martin rudalics @ 2019-11-01 13:23 UTC (permalink / raw)
  To: Mattias Engdegård, Eli Zaretskii; +Cc: 38013

9> Competing mouse bindings are:
 >
 > Meta: secondary selection

The meta combinations are bound to the secondary selection in a very
elaborate fashion and should be left alone.

 > Shift: mouse-appearance-menu (mouse-save-then-kill for NS)
 > Control: mouse-buffer-menu

I have no idea why these are bound to down events in the first place.
I would reserve S-down-mouse-1 for extending an existing selection and
provide C-down-mouse-1 for rectangular selection.  Some programs allow
C-down-mouse-1 to provide non-contiguous selections which we then
could accommodate easily by checking initially whether a selection is
already active.

 > B. Combined modifiers (Shift-Meta etc). Less ergonomic; there may be platform restrictions.

I'd consider these as viable alternatives.

martin





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-01 13:17     ` Eli Zaretskii
@ 2019-11-01 13:30       ` Eli Zaretskii
  2019-11-03 21:12         ` Mattias Engdegård
  0 siblings, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2019-11-01 13:30 UTC (permalink / raw)
  To: mattiase; +Cc: 38013

> Date: Fri, 01 Nov 2019 15:17:07 +0200
> From: Eli Zaretskii <eliz@gnu.org>
> Cc: 38013@debbugs.gnu.org
> 
> > From: Mattias Engdegård <mattiase@acm.org>
> > Date: Fri, 1 Nov 2019 12:53:44 +0100
> > Cc: 38013@debbugs.gnu.org
> > 
> > With the default settings, click and drag (mouse button 1) with meta held to mark a rectangular region.
> 
> Thanks, I will try.

Tried it.  I see 2 problems:

 . an annoying 1-pixel horizontal movement when I just press
   M-mouse-1, but don't move it; this doesn't happen in a "normal"
   selection by dragging mouse-1
 . problems when dragging the mouse across a TAB -- you cannot select
   just a "part" of the TAB's 8-column white space (see cua-rect.el
   for how this can be done better)

In addition, it looks like making the rectangular selection is very
error-prone: about 40% of the attempts I get a non-rectangular
selection instead, and sometimes the selection "jumps" to the other
side, i.e. I drag the mouse to the right, but get the text from the
mouse to the _left_ selected, and the selection extends to the BOB.

Thanks.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-01 13:30       ` Eli Zaretskii
@ 2019-11-03 21:12         ` Mattias Engdegård
  2019-11-03 21:51           ` Drew Adams
  2019-11-04  9:07           ` martin rudalics
  0 siblings, 2 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-03 21:12 UTC (permalink / raw)
  To: 38013

[-- Attachment #1: Type: text/plain, Size: 2624 bytes --]

1 nov. 2019 kl. 14.30 skrev Eli Zaretskii <eliz@gnu.org>:

> . an annoying 1-pixel horizontal movement when I just press
>   M-mouse-1, but don't move it; this doesn't happen in a "normal"
>   selection by dragging mouse-1

It also happens with C-x SPC and is a result of creating a zero-width selection that still has to be visible somehow. Now mitigated, so that it goes away if you release the button without selecting anything.

> . problems when dragging the mouse across a TAB -- you cannot select
>   just a "part" of the TAB's 8-column white space (see cua-rect.el
>   for how this can be done better)

> In addition, it looks like making the rectangular selection is very
> error-prone: about 40% of the attempts I get a non-rectangular
> selection instead, and sometimes the selection "jumps" to the other
> side, i.e. I drag the mouse to the right, but get the text from the
> mouse to the _left_ selected, and the selection extends to the BOB.

Quite right! Now fixed so that the rectangle corners, including the starting and ending corner, are no longer limited to points in the text. They can now be beyond EOL or in the middle of a TAB. Thank you for making it better!

The customisable variables for rectangular and secondary selection are now sets of modifiers, so that combinations like (shift meta) can be used.

1 nov. 2019 kl. 14.23 skrev martin rudalics <rudalics@gmx.at>:

> The meta combinations are bound to the secondary selection in a very
> elaborate fashion and should be left alone.

Abstracting the modifiers for the secondary selection seemed straightforward to me. Did I miss anything?

> > Shift: mouse-appearance-menu (mouse-save-then-kill for NS)
> > Control: mouse-buffer-menu
> 
> I have no idea why these are bound to down events in the first place.
> I would reserve S-down-mouse-1 for extending an existing selection and
> provide C-down-mouse-1 for rectangular selection.  Some programs allow
> C-down-mouse-1 to provide non-contiguous selections which we then
> could accommodate easily by checking initially whether a selection is
> already active.

It would be nice to avoid the automatic bias toward favouring existing bindings regardless of merit, but that requires a sound understanding of which operations are actually useful (or not). Picking some free multi-key modifier like shift-control would have nobody complain, but isn't necessarily optimal.

You seem to believe that mouse-buffer-menu and mouse-appearance-menu don't deserve their bindings. I'm neutral, but would be interested in what other people have to say about it.


[-- Attachment #2: 0001-Mouse-rectangular-region-selection-bug-38013.patch --]
[-- Type: application/octet-stream, Size: 7925 bytes --]

From 5db74b60fc263ec68de78542b2a334c1b19d70df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Fri, 25 Oct 2019 11:16:39 +0200
Subject: [PATCH] Mouse rectangular region selection (bug#38013)

Make it possible to select a rectangular region using the mouse.
The modifier is customisable and defaults to meta.
The modifier for mouse secondary selection is now also customisable and
defaults to nil (disabled).

* lisp/mouse.el (mouse-scroll-subr): Add ADJUST argument.
(mouse-drag-region-rectangle): New.
(mouse--global-with-modifiers, mouse--set-secondary-selection-bindings)
(mouse-secondary-selection-modifiers)
(mouse--set-rectangular-region-selection-bindings)
(mouse-region-rectangle-modifiers): New defcustoms with helper functions.
---
 lisp/mouse.el | 123 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 117 insertions(+), 6 deletions(-)

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 4a351f7be2..738f5403d8 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1045,10 +1045,12 @@ mouse-scroll-min-lines
 of lines specified by this variable."
   :type 'integer)
 
-(defun mouse-scroll-subr (window jump &optional overlay start)
+(defun mouse-scroll-subr (window jump &optional overlay start adjust)
   "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
 If OVERLAY is an overlay, let it stretch from START to the far edge of
 the newly visible text.
+ADJUST, if non-nil, is a function, without arguments, to call after
+setting point.
 Upon exit, point is at the far edge of the newly visible text."
   (cond
    ((and (> jump 0) (< jump mouse-scroll-min-lines))
@@ -1077,6 +1079,8 @@ mouse-scroll-subr
 		   ;; so that we don't mess up the selected window.
 		   (or (eq window (selected-window))
 		       (goto-char opoint))
+                   (when adjust
+                     (funcall adjust))
 		   (sit-for mouse-scroll-delay)))))
     (or (eq window (selected-window))
 	(goto-char opoint))))
@@ -1666,11 +1670,40 @@ mouse-save-then-kill
       (setq mouse-save-then-kill-posn click-pt)))))
 
 \f
-(global-set-key [M-mouse-1] 'mouse-start-secondary)
-(global-set-key [M-drag-mouse-1] 'mouse-set-secondary)
-(global-set-key [M-down-mouse-1] 'mouse-drag-secondary)
-(global-set-key [M-mouse-3] 'mouse-secondary-save-then-kill)
-(global-set-key [M-mouse-2] 'mouse-yank-secondary)
+(defun mouse--global-with-modifiers (base modifiers command)
+  "Globally bind BASE + MODIFIERS to COMMAND."
+  (global-set-key (vector (event-convert-list (append modifiers (list base))))
+                  command))
+
+(defun mouse--set-secondary-selection-bindings (mods activate)
+  "Set global mouse bindings using MODS for secondary selection.
+If ACTIVATE is nil, remove those bindings."
+  (when mods
+    (mouse--global-with-modifiers
+     'mouse-1 mods (and activate 'mouse-start-secondary))
+    (mouse--global-with-modifiers
+     'drag-mouse-1 mods (and activate 'mouse-set-secondary))
+    (mouse--global-with-modifiers
+     'down-mouse-1 mods (and activate 'mouse-drag-secondary))
+    (mouse--global-with-modifiers
+     'mouse-3 mods (and activate 'mouse-secondary-save-then-kill))
+    (mouse--global-with-modifiers
+     'mouse-2 mods (and activate 'mouse-yank-secondary))))
+
+(defcustom mouse-secondary-selection-modifiers '()
+  "The modifier keys for secondary selection using the mouse.
+If none, mouse secondary selection is disabled."
+  :group 'mouse
+  :type '(set (const meta) (const control) (const shift)
+              (const super) (const hyper))
+  :version "27.1"
+  :set (lambda (variable new-value)
+         (when (boundp 'mouse-secondary-selection-modifiers)
+           (mouse--set-secondary-selection-bindings
+            mouse-secondary-selection-modifiers nil))
+         (set-default variable new-value)
+         (mouse--set-secondary-selection-bindings
+          mouse-secondary-selection-modifiers t)))
 
 (defconst mouse-secondary-overlay
   (let ((ol (make-overlay (point-min) (point-min))))
@@ -1960,6 +1993,84 @@ secondary-selection-from-region
     (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
 
 \f
+(defun mouse-drag-region-rectangle (start-event)
+  "Set the region to the rectangle that the mouse is dragged over.
+This must be bound to a button-down mouse event."
+  (interactive "e")
+  (mouse-minibuffer-check start-event)
+  (deactivate-mark)
+  (let* ((start-pos (event-start start-event))
+         (col-row (posn-col-row start-pos)))
+    (posn-set-point start-pos)
+    (rectangle-mark-mode)
+    ;; Tell the rectangle selection about the exact column, since it might
+    ;; not correspond exactly to a valid position in the text.
+    (rectangle--col-pos (car col-row) 'mark)
+    (rectangle--col-pos (car col-row) 'point))
+  (let* ((scroll-margin 0)
+         (start-posn (event-start start-event))
+         (start-point (posn-point start-posn))
+         (start-window (posn-window start-posn))
+         (bounds (window-edges start-window))
+         (top (nth 1 bounds))
+         (bottom (if (window-minibuffer-p start-window)
+                     (nth 3 bounds)
+                   (1- (nth 3 bounds))))
+         event)
+    (track-mouse
+      (while (progn
+               (setq event (read-event))
+               (mouse-movement-p event))
+        (let* ((posn (event-end event))
+               (window (posn-window posn))
+               (mouse-pos (mouse-position))
+               (mouse-col (cadr mouse-pos))
+               (mouse-row (cddr mouse-pos)))
+          (if (and (eq window start-window)
+                   mouse-row
+                   (<= top mouse-row (1- bottom)))
+              ;; Drag inside the same window.
+              (progn
+                (posn-set-point posn)
+                (rectangle--col-pos mouse-col 'point))
+            ;; Drag outside the window: scroll.
+            (cond
+             ((null mouse-row))
+             ((< mouse-row top)
+              (mouse-scroll-subr
+               start-window (- mouse-row top) nil start-point
+               (lambda () (rectangle--col-pos mouse-col 'point))))
+             ((>= mouse-row bottom)
+              (mouse-scroll-subr
+               start-window (1+ (- mouse-row bottom)) nil start-point
+               (lambda () (rectangle--col-pos mouse-col 'point)))))))))
+    (when (equal (rectangle-dimensions (mark) (point)) '(0 . 1))
+      ;; No nontrivial region selected; deactivate rectangle mode.
+      (rectangle-mark-mode -1))))
+
+(defun mouse--set-rectangular-region-selection-bindings (mods activate)
+  "Set global mouse bindings using MODS for rectangular selection.
+If ACTIVATE is nil, remove those bindings."
+  (when mods
+    (mouse--global-with-modifiers 'down-mouse-1 mods
+                                  (and activate 'mouse-drag-region-rectangle))))
+
+(defcustom mouse-region-rectangle-modifiers '(meta)
+  "The modifier keys for rectangular region selection using the mouse.
+If none, mouse rectangular region selection is disabled."
+  :group 'mouse
+  :type '(set (const meta) (const control) (const shift)
+              (const super) (const hyper))
+  :version "27.1"
+  :set (lambda (variable new-value)
+         (when (boundp 'mouse-region-rectangle-modifiers)
+           (mouse--set-rectangular-region-selection-bindings
+            mouse-region-rectangle-modifiers nil))
+         (set-default variable new-value)
+         (mouse--set-rectangular-region-selection-bindings
+          mouse-region-rectangle-modifiers t)))
+
+\f
 (defcustom mouse-buffer-menu-maxlen 20
   "Number of buffers in one pane (submenu) of the buffer menu.
 If we have lots of buffers, divide them into groups of
-- 
2.21.0 (Apple Git-122)


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-03 21:12         ` Mattias Engdegård
@ 2019-11-03 21:51           ` Drew Adams
  2019-11-04  9:07           ` martin rudalics
  1 sibling, 0 replies; 55+ messages in thread
From: Drew Adams @ 2019-11-03 21:51 UTC (permalink / raw)
  To: Mattias Engdegård, 38013

Sorry, but I don't see why you did any of what you
did that affects the secondary selection.  Why all
of that?  Why not just continue to provide the same
default mouse key bindings for it?

It's always been easy for a user to change those
default mouse key bindings.  How are things easier
for users after the proposed changes?

Searching your patch for "second", it seems that the
only changes affecting the secondary affect just the
(mouse) key bindings for it.  How is any of that
related to rectangular region selection?

I really don't see what has been gained by the
changes that affect the secondary selection.  Can
you please explain?  What's the aim - what's the
problem that this is trying to solve?

How about just removing all of the code in the
patch that deals with the secondary selection?
Is any of that needed, to provide mouse selection
of a rectangular region?

And I disagree with removing the longstanding
default mouse key bindings for the secondary.
You've done that in a roundabout way (defaulting
a new user option to nil), but you've done it,
AFAICT.

[BTW, there's no need to use '(); just () suffices.] 





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-03 21:12         ` Mattias Engdegård
  2019-11-03 21:51           ` Drew Adams
@ 2019-11-04  9:07           ` martin rudalics
  2019-11-04 11:33             ` Mattias Engdegård
  1 sibling, 1 reply; 55+ messages in thread
From: martin rudalics @ 2019-11-04  9:07 UTC (permalink / raw)
  To: Mattias Engdegård, 38013

 >> The meta combinations are bound to the secondary selection in a very
 >> elaborate fashion and should be left alone.
 >
 > Abstracting the modifiers for the secondary selection seemed
 > straightforward to me. Did I miss anything?

I meant that the code for working with the secondary selection has
been set up in a quite meticulous way so I would never mess with it
(including the modifiers it uses).

 > Picking some free multi-key modifier like shift-control would
 > have nobody complain, but isn't necessarily optimal.

I usually shift-control with my pinkie alone so I would consider it
optimal and use it for many key combinations all the time.

 > You seem to believe that mouse-buffer-menu and mouse-appearance-menu
 > don't deserve their bindings. I'm neutral, but would be interested
 > in what other people have to say about it.

These deserve their bindings though I would not pop up a menu from a
mouse-down event alone.  What I am obviously assuming is that the
rectangular region selection code is based on mouse-dragging from one
corner of the rectangle to the opposite one, so a mouse-drag is easily
distinguishable from a click for a pop-up-menu.  If this assumption is
wrong, my rebinding proposal is clearly void.

martin





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-04  9:07           ` martin rudalics
@ 2019-11-04 11:33             ` Mattias Engdegård
  2019-11-04 15:25               ` Drew Adams
  2019-11-04 18:27               ` martin rudalics
  0 siblings, 2 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-04 11:33 UTC (permalink / raw)
  To: martin rudalics; +Cc: 38013

4 nov. 2019 kl. 10.07 skrev martin rudalics <rudalics@gmx.at>:

> I meant that the code for working with the secondary selection has
> been set up in a quite meticulous way so I would never mess with it
> (including the modifiers it uses).

Not here to mess with it, but if the user prefers to free up the Meta modifier for something else but still have access to the secondary selection, it seems to be perfectly possible. The current patch applies the modifier in a consistent way on all related bindings.

Even better would be a unified binding interface that also takes care of clashes in an automated way.

(Drew, don't worry --- the bindings are placeholders so that people can try out the selection mechanism. The default bindings are yet to be determined.)

> I usually shift-control with my pinkie alone so I would consider it
> optimal and use it for many key combinations all the time.

Geometry of hands and keyboards varies; I find single-key modifiers easier (but not necessarily difficult) to use.

However, shift-control could be a reasonable default value, if we dare not alter anything else. Is there any reason to prefer one of {shift-control, shift-meta, control-meta} to the rest?

> These deserve their bindings though I would not pop up a menu from a
> mouse-down event alone.  What I am obviously assuming is that the
> rectangular region selection code is based on mouse-dragging from one
> corner of the rectangle to the opposite one, so a mouse-drag is easily
> distinguishable from a click for a pop-up-menu.  If this assumption is
> wrong, my rebinding proposal is clearly void.

Thanks for explaining. Unfortunately, region selection and menu pop-up do not seem to be compatible in that way --- at least I didn't manage to use the same modifier for both. Perhaps the events could be multiplexed somehow, but it seems to be on the hacky side.







^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-04 11:33             ` Mattias Engdegård
@ 2019-11-04 15:25               ` Drew Adams
  2019-11-04 18:27               ` martin rudalics
  1 sibling, 0 replies; 55+ messages in thread
From: Drew Adams @ 2019-11-04 15:25 UTC (permalink / raw)
  To: Mattias Engdegård, martin rudalics; +Cc: 38013

> (Drew, don't worry --- the bindings are placeholders so that people can
> try out the selection mechanism. The default bindings are yet to be
> determined.)

My latest question was why we would add all of that
stuff - options for choosing modifiers etc.  _Users
have control_ over key bindings now.  Just what's
the point of adding this other stuff?

And what exactly does that have to do with selecting
a rectangular region with the mouse?  Why should that
be mixed in with providing the possibility of using
a mouse to select a rectangular region?

And why provide any binding, by default, for doing
that?  The feature hasn't even been introduced to
users yet.  Why would we sacrifice a default binding
for it at this time?





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-04 11:33             ` Mattias Engdegård
  2019-11-04 15:25               ` Drew Adams
@ 2019-11-04 18:27               ` martin rudalics
  2019-11-04 20:18                 ` Mattias Engdegård
  1 sibling, 1 reply; 55+ messages in thread
From: martin rudalics @ 2019-11-04 18:27 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

 > Thanks for explaining. Unfortunately, region selection and menu
 > pop-up do not seem to be compatible in that way --- at least I
 > didn't manage to use the same modifier for both. Perhaps the events
 > could be multiplexed somehow, but it seems to be on the hacky side.

If you bind it to the control key you should at least be able to pop
up the buffer menu yourself if the up event occurs at the same
position as the down event.

But here I can simply do

(global-set-key [C-down-mouse-1] 'mouse-drag-region)
(global-set-key [C-drag-mouse-1] 'mouse-set-region)
(global-set-key [C-mouse-1] 'mouse-buffer-menu)

and get both, normal mouse dragging and the buffer menu.  What more
would you need?

martin





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-04 18:27               ` martin rudalics
@ 2019-11-04 20:18                 ` Mattias Engdegård
  2019-11-05  9:35                   ` martin rudalics
  0 siblings, 1 reply; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-04 20:18 UTC (permalink / raw)
  To: martin rudalics; +Cc: 38013

4 nov. 2019 kl. 19.27 skrev martin rudalics <rudalics@gmx.at>:

> If you bind it to the control key you should at least be able to pop
> up the buffer menu yourself if the up event occurs at the same
> position as the down event.
> 
> But here I can simply do
> 
> (global-set-key [C-down-mouse-1] 'mouse-drag-region)
> (global-set-key [C-drag-mouse-1] 'mouse-set-region)
> (global-set-key [C-mouse-1] 'mouse-buffer-menu)
> 
> and get both, normal mouse dragging and the buffer menu.  What more
> would you need?

The rectangle-mark code can perhaps be rewritten to work that way, but doesn't it force the pop-up menu to be used with click-release-select-click-release instead of the quicker click-select-release?






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-04 20:18                 ` Mattias Engdegård
@ 2019-11-05  9:35                   ` martin rudalics
  2019-11-07 17:48                     ` Mattias Engdegård
  0 siblings, 1 reply; 55+ messages in thread
From: martin rudalics @ 2019-11-05  9:35 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

 > The rectangle-mark code can perhaps be rewritten to work that way,

Any code based on mouse dragging should be written in such way that
the corresponding click event can be easily handed over to a separate
command.  That's what the drag- prefix is for.

 > but doesn't it force the pop-up menu to be used with
 > click-release-select-click-release instead of the quicker
 > click-select-release?

Yes and I think that the former is the correct and expected behavior.
I don't use the buffer menu but if I did I were much more annoyed by
the fact that when I abandon the selection by clicking somewhere else
I get an active region which I then have to click away in a further
step.

Note that even the Emacs manual itself confuses down-mouse events and
clicks as

   ‘C-mouse-1’
      This menu is for selecting a buffer.

      The MSB (“mouse select buffer”) global minor mode makes this menu
      smarter and more customizable.  *Note Buffer Menus::.

and

   It replaces the ‘mouse-buffer-menu’ commands, normally bound to
   ‘C-Down-mouse-1’

IMHO the rule should be that non-dragging commands are always bound to
clicks (including double and triple ones) and never to a down- event.
The menu bar might be an exception (Firefox even pops up an entry when
the mouse just hovers over it) but the various (non-)toolkits Emacs
uses for it apparently defeat a common unified behavior anway.

And personally, I'd reserve C-drag-mouse for marking arbitrary
non-contiguous text (like, for example, Firefox does) and use
C-S-drag-mouse for marking rectangular regions.

martin






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-05  9:35                   ` martin rudalics
@ 2019-11-07 17:48                     ` Mattias Engdegård
  2019-11-07 17:53                       ` Drew Adams
  2019-11-07 19:08                       ` martin rudalics
  0 siblings, 2 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-07 17:48 UTC (permalink / raw)
  To: martin rudalics; +Cc: 38013

[-- Attachment #1: Type: text/plain, Size: 2907 bytes --]

5 nov. 2019 kl. 10.35 skrev martin rudalics <rudalics@gmx.at>:

> Any code based on mouse dragging should be written in such way that
> the corresponding click event can be easily handed over to a separate
> command.  That's what the drag- prefix is for.

All right, I re-wrote the patch to allow for independent use for X-mouse-N, but...

> > but doesn't it force the pop-up menu to be used with
> > click-release-select-click-release instead of the quicker
> > click-select-release?
> 
> Yes and I think that the former is the correct and expected behavior.
> I don't use the buffer menu but if I did I were much more annoyed by
> the fact that when I abandon the selection by clicking somewhere else
> I get an active region which I then have to click away in a further
> step.

I don't think so; being able to select from a menu with a single dragging movement is not only more ergonomic, it's the expected behaviour of pop-up menus. mouse.el even contains a comment to that effect:

 ;; By binding these to down-going events, we let the user use the up-going
 ;; event to make the selection, saving a click.

You can try for yourself: with the patch applied, bind M-mouse-1 to a menu:

 (global-set-key [M-mouse-1] 'mouse-buffer-menu)

Now a single meta-click will open the menu, and meta-drag will mark a rectangle. This sort of multiplexing doesn't feel right, and affects both uses negatively.

For example, suppose you have marked a rectangle and change your mind. Intuitively, you will click somewhere to make the mark go away, using the same modifiers. But that doesn't work, because now you get a pop-up menu.

> IMHO the rule should be that non-dragging commands are always bound to
> clicks (including double and triple ones) and never to a down- event.

My patch now follows that rule, but it doesn't seem to solve any problem.

> And personally, I'd reserve C-drag-mouse for marking arbitrary
> non-contiguous text (like, for example, Firefox does) and use
> C-S-drag-mouse for marking rectangular regions.

Emacs's mouse bindings seem rather haphazard and organised mainly on the principle of first-come, enshrining a fair bit of historical baggage. For example, there are two different buffer menus (one for font and one for everything else). There is also the secondary selection, of which there seems to be much fewer actual users than people who just want to know how to disable it.

We could do worse than following some conventions that have become more or less universal, such as right-clicking (control-click on macOS) for a context menu.

That said, do you have any particular reason (precedence, ergonomics) for suggesting control-shift? I'd rather use meta and move secondary selection to shift-meta (say).

(As before, the attached patch uses meta but that is just a placeholder and should not be interpreted as the final word.)


[-- Attachment #2: 0001-Mouse-rectangular-region-selection-bug-38013.patch --]
[-- Type: application/octet-stream, Size: 9192 bytes --]

From 0d71173e6409de45629806b10cc11f6f06c7c992 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Fri, 25 Oct 2019 11:16:39 +0200
Subject: [PATCH] Mouse rectangular region selection (bug#38013)

Make it possible to select a rectangular region using the mouse.
The modifier is customisable and defaults to meta.
The modifier for mouse secondary selection is now also customisable and
defaults to nil (disabled).

* lisp/mouse.el (mouse-scroll-subr): Add ADJUST argument.
(mouse-drag-region-rectangle): New.
(mouse--global-with-modifiers, mouse--set-secondary-selection-bindings)
(mouse-secondary-selection-modifiers)
(mouse--set-rectangular-region-selection-bindings)
(mouse-region-rectangle-modifiers): New defcustoms with helper functions.
---
 lisp/mouse.el | 150 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 144 insertions(+), 6 deletions(-)

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 4a351f7be2..2ac9ff3e66 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1045,10 +1045,12 @@ mouse-scroll-min-lines
 of lines specified by this variable."
   :type 'integer)
 
-(defun mouse-scroll-subr (window jump &optional overlay start)
+(defun mouse-scroll-subr (window jump &optional overlay start adjust)
   "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
 If OVERLAY is an overlay, let it stretch from START to the far edge of
 the newly visible text.
+ADJUST, if non-nil, is a function, without arguments, to call after
+setting point.
 Upon exit, point is at the far edge of the newly visible text."
   (cond
    ((and (> jump 0) (< jump mouse-scroll-min-lines))
@@ -1077,6 +1079,8 @@ mouse-scroll-subr
 		   ;; so that we don't mess up the selected window.
 		   (or (eq window (selected-window))
 		       (goto-char opoint))
+                   (when adjust
+                     (funcall adjust))
 		   (sit-for mouse-scroll-delay)))))
     (or (eq window (selected-window))
 	(goto-char opoint))))
@@ -1666,11 +1670,40 @@ mouse-save-then-kill
       (setq mouse-save-then-kill-posn click-pt)))))
 
 \f
-(global-set-key [M-mouse-1] 'mouse-start-secondary)
-(global-set-key [M-drag-mouse-1] 'mouse-set-secondary)
-(global-set-key [M-down-mouse-1] 'mouse-drag-secondary)
-(global-set-key [M-mouse-3] 'mouse-secondary-save-then-kill)
-(global-set-key [M-mouse-2] 'mouse-yank-secondary)
+(defun mouse--global-with-modifiers (base modifiers command)
+  "Globally bind BASE + MODIFIERS to COMMAND."
+  (global-set-key (vector (event-convert-list (append modifiers (list base))))
+                  command))
+
+(defun mouse--set-secondary-selection-bindings (mods activate)
+  "Set global mouse bindings using MODS for secondary selection.
+If ACTIVATE is nil, remove those bindings."
+  (when mods
+    (mouse--global-with-modifiers
+     'mouse-1 mods (and activate 'mouse-start-secondary))
+    (mouse--global-with-modifiers
+     'drag-mouse-1 mods (and activate 'mouse-set-secondary))
+    (mouse--global-with-modifiers
+     'down-mouse-1 mods (and activate 'mouse-drag-secondary))
+    (mouse--global-with-modifiers
+     'mouse-3 mods (and activate 'mouse-secondary-save-then-kill))
+    (mouse--global-with-modifiers
+     'mouse-2 mods (and activate 'mouse-yank-secondary))))
+
+(defcustom mouse-secondary-selection-modifiers '(shift meta)
+  "The modifier keys for secondary selection using the mouse.
+If none, mouse secondary selection is disabled."
+  :group 'mouse
+  :type '(set (const meta) (const control) (const shift)
+              (const super) (const hyper))
+  :version "27.1"
+  :set (lambda (variable new-value)
+         (when (boundp 'mouse-secondary-selection-modifiers)
+           (mouse--set-secondary-selection-bindings
+            mouse-secondary-selection-modifiers nil))
+         (set-default variable new-value)
+         (mouse--set-secondary-selection-bindings
+          mouse-secondary-selection-modifiers t)))
 
 (defconst mouse-secondary-overlay
   (let ((ol (make-overlay (point-min) (point-min))))
@@ -1960,6 +1993,111 @@ secondary-selection-from-region
     (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
 
 \f
+(defun mouse-drag-region-rectangle (start-event)
+  "Set the region to the rectangle that the mouse is dragged over.
+This must be bound to a button-down mouse event."
+  (interactive "e")
+  (let* ((scroll-margin 0)
+         (start-pos (event-start start-event))
+         (start-posn (event-start start-event))
+         (start-point (posn-point start-posn))
+         (start-window (posn-window start-posn))
+         (start-hscroll (window-hscroll start-window))
+         (start-col (+ (car (posn-col-row start-pos)) start-hscroll))
+         (bounds (window-edges start-window))
+         (top (nth 1 bounds))
+         (bottom (if (window-minibuffer-p start-window)
+                     (nth 3 bounds)
+                   (1- (nth 3 bounds))))
+         (dragged nil)
+         (old-track-mouse track-mouse))
+    (setq track-mouse t)
+    (set-transient-map
+     (let ((map (make-sparse-keymap)))
+       (define-key map [switch-frame] #'ignore)
+       (define-key map [select-window] #'ignore)
+       (define-key map [mouse-movement]
+         (lambda (event)
+           (interactive "e")
+           (unless dragged
+             ;; This is actually a drag.
+             (mouse-minibuffer-check start-event)
+             (deactivate-mark)
+             (posn-set-point start-pos)
+             (rectangle-mark-mode)
+             ;; Tell the rectangle selection about the exact column,
+             ;; since it might not correspond exactly to a valid
+             ;; position in the text.
+             (rectangle--col-pos start-col 'mark)
+             (rectangle--col-pos start-col 'point)
+
+             (setq dragged t))
+
+           (let* ((posn (event-end event))
+                  (window (posn-window posn))
+                  (hscroll (if (window-live-p window)
+                               (window-hscroll window)
+                             0))
+                  (mouse-pos (mouse-position))
+                  (mouse-col (+ (cadr mouse-pos) hscroll))
+                  (mouse-row (cddr mouse-pos)))
+             (if (and (eq window start-window)
+                      mouse-row
+                      (<= top mouse-row (1- bottom)))
+                 ;; Drag inside the same window.
+                 (progn
+                   (posn-set-point posn)
+                   (rectangle--col-pos mouse-col 'point))
+               ;; Drag outside the window: scroll.
+               (cond
+                ((null mouse-row))
+                ((< mouse-row top)
+                 (mouse-scroll-subr
+                  start-window (- mouse-row top) nil start-point
+                  (lambda () (rectangle--col-pos mouse-col 'point))))
+                ((>= mouse-row bottom)
+                 (mouse-scroll-subr
+                  start-window (1+ (- mouse-row bottom)) nil start-point
+                  (lambda () (rectangle--col-pos mouse-col 'point)))))))))
+       map)
+     t
+     (lambda ()
+       (setq track-mouse old-track-mouse)
+       (when (or (not dragged)
+                 (not (mark))
+                 (equal (rectangle-dimensions (mark) (point)) '(0 . 1)))
+         ;; No nontrivial region selected; deactivate rectangle mode.
+         (deactivate-mark))))))
+
+(defun mouse--set-rectangular-region-selection-bindings (mods activate)
+  "Set global mouse bindings using MODS for rectangular selection.
+If ACTIVATE is nil, remove those bindings."
+  (when mods
+    ;; For rectangular selection to work, down-mouse-N must be bound to
+    ;; `mouse-drag-region-rectangle', and drag-mouse-N to ignore.
+    ;; mouse-N can be bound to anything but `mouse-set-selection' is
+    ;; probably the most ergonomic binding.
+    (mouse--global-with-modifiers 'down-mouse-1 mods
+                                  (and activate 'mouse-drag-region-rectangle))
+    (mouse--global-with-modifiers 'drag-mouse-1 mods
+                                  (and activate 'ignore))))
+
+(defcustom mouse-region-rectangle-modifiers '(meta)
+  "The modifier keys for rectangular region selection using the mouse.
+If none, mouse rectangular region selection is disabled."
+  :group 'mouse
+  :type '(set (const meta) (const control) (const shift)
+              (const super) (const hyper))
+  :version "27.1"
+  :set (lambda (variable new-value)
+         (when (boundp 'mouse-region-rectangle-modifiers)
+           (mouse--set-rectangular-region-selection-bindings
+            mouse-region-rectangle-modifiers nil))
+         (set-default variable new-value)
+         (mouse--set-rectangular-region-selection-bindings
+          mouse-region-rectangle-modifiers t)))
+
+\f
 (defcustom mouse-buffer-menu-maxlen 20
   "Number of buffers in one pane (submenu) of the buffer menu.
 If we have lots of buffers, divide them into groups of
-- 
2.21.0 (Apple Git-122)


[-- Attachment #3: Type: text/plain, Size: 2 bytes --]




^ permalink raw reply related	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-07 17:48                     ` Mattias Engdegård
@ 2019-11-07 17:53                       ` Drew Adams
  2019-11-07 18:27                         ` Mattias Engdegård
  2019-11-07 19:08                       ` martin rudalics
  1 sibling, 1 reply; 55+ messages in thread
From: Drew Adams @ 2019-11-07 17:53 UTC (permalink / raw)
  To: Mattias Engdegård, martin rudalics; +Cc: 38013

> All right, I re-wrote the patch to allow for
> independent use for X-mouse-N, but...

I have the same comments as before, FWIW.

  My latest question was why we would add all of that
  stuff - options for choosing modifiers etc.  _Users
  have control_ over key bindings now.  Just what's
  the point of adding this other stuff?

  And what exactly does that have to do with selecting
  a rectangular region with the mouse?  Why should that
  be mixed in with providing the possibility of using
  a mouse to select a rectangular region?

  And why provide any binding, by default, for doing
  that?  The feature hasn't even been introduced to
  users yet.  Why would we sacrifice a default binding
  for it at this time?





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-07 17:53                       ` Drew Adams
@ 2019-11-07 18:27                         ` Mattias Engdegård
  0 siblings, 0 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-07 18:27 UTC (permalink / raw)
  To: Drew Adams; +Cc: 38013

7 nov. 2019 kl. 18.53 skrev Drew Adams <drew.adams@oracle.com>:

>  My latest question was why we would add all of that
>  stuff - options for choosing modifiers etc.  _Users
>  have control_ over key bindings now.  Just what's
>  the point of adding this other stuff?

That the least important part of the patch --- it was mainly to make it easier to change the bindings in a consistent way, since there are multiple bindings that go together.

>  And what exactly does that have to do with selecting
>  a rectangular region with the mouse?  Why should that
>  be mixed in with providing the possibility of using
>  a mouse to select a rectangular region?

The Meta modifier was already used by the secondary selection. Shift or control could have been used as well; I just picked the one that appeared to be used the least. It's not worth arguing about either, particular not at this stage; let's get the basics right first.

>  And why provide any binding, by default, for doing
>  that?  The feature hasn't even been introduced to
>  users yet.  Why would we sacrifice a default binding
>  for it at this time?

I'm not sure what you mean. Of course rectangular selection needs a binding. We just have to select one that is less bad than the alternatives.







^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-07 17:48                     ` Mattias Engdegård
  2019-11-07 17:53                       ` Drew Adams
@ 2019-11-07 19:08                       ` martin rudalics
  2019-11-07 20:46                         ` Drew Adams
  2019-11-08 17:33                         ` Mattias Engdegård
  1 sibling, 2 replies; 55+ messages in thread
From: martin rudalics @ 2019-11-07 19:08 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

 > I don't think so; being able to select from a menu with a single
 > dragging movement is not only more ergonomic, it's the expected
 > behaviour of pop-up menus.

But by doing so it usurps all combinations of the control key and
mouse-1.  So we pay a high price for such a small convenience.  And
since I have never anywhere else seen a "context" menu pop up right
after a mouse press I would not consider it the expected behavior.

 > mouse.el even contains a comment to that
 > effect:
 >
 >   ;; By binding these to down-going events, we let the user use the up-going
 >   ;; event to make the selection, saving a click.

In all those 25 or more years it hasn't found its way into the Emacs
manual though.

 > You can try for yourself: with the patch applied, bind M-mouse-1 to a menu:
 >
 >   (global-set-key [M-mouse-1] 'mouse-buffer-menu)
 >
 > Now a single meta-click will open the menu, and meta-drag will mark
 > a rectangle. This sort of multiplexing doesn't feel right, and
 > affects both uses negatively.

But the same "multiplexing" already applies for operating the mouse
without any modifiers.  And I sometimes use it in a different context:
When I prematurely press the mouse button on a browser link, I can
always bow out by slightly moving the mouse, thus avoiding the
semantics of a click.

 > For example, suppose you have marked a rectangle and change your
 > mind. Intuitively, you will click somewhere to make the mark go
 > away, using the same modifiers. But that doesn't work, because now
 > you get a pop-up menu.

The menu should pop up iff the down and up events happen at the same
location.  Can we agree that this is hard to achieve after having
marked a rectangle?

 > Emacs's mouse bindings seem rather haphazard and organised mainly on
 > the principle of first-come, enshrining a fair bit of historical
 > baggage. For example, there are two different buffer menus (one for
 > font and one for everything else). There is also the secondary
 > selection, of which there seems to be much fewer actual users than
 > people who just want to know how to disable it.

Most applications I know do not even distinguish mouse and meta mouse
clicks so I doubt that many users will see this as a problem.

 > We could do worse than following some conventions that have become
 > more or less universal, such as right-clicking (control-click on
 > macOS) for a context menu.

For me mouse-3 is the preferred button to pop up a menu.  I never use
mouse-3 to extend the selection because I'm not used to switch mouse
buttons during one and the same action.

 > That said, do you have any particular reason (precedence,
 > ergonomics) for suggesting control-shift? I'd rather use meta and
 > move secondary selection to shift-meta (say).

I suggested control-shift because it's IMHO the most convenient
combination with two modifiers (at least on my past and present
keyboards).  And I wouldn't change default key bindings that have
existed for decades.  But since I never use the secondary selection I
cannot really defend it either.

martin





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-07 19:08                       ` martin rudalics
@ 2019-11-07 20:46                         ` Drew Adams
  2019-11-08 17:33                         ` Mattias Engdegård
  1 sibling, 0 replies; 55+ messages in thread
From: Drew Adams @ 2019-11-07 20:46 UTC (permalink / raw)
  To: martin rudalics, Mattias Engdegård; +Cc: 38013

> For me mouse-3 is the preferred button to pop up a menu.  I never use
> mouse-3 to extend the selection because I'm not used to switch mouse
> buttons during one and the same action.

(Replying just about this: mouse-3.)

Vanilla Emacs hard-wires the behavior to kill or
delete the region (depending on the value of
`mouse-drag-copy-region').  That action can be
handy, but it's sometimes inappropriate (e.g., in
a read-only buffer).  In any case, it is only one
possible action; there are often other actions on
the selected text that you might want to take.

See `mouse3.el'.  You can use mouse-3 for both
a contextual pop-up menu and for extending the
selection.

https://www.emacswiki.org/emacs/Mouse3





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-07 19:08                       ` martin rudalics
  2019-11-07 20:46                         ` Drew Adams
@ 2019-11-08 17:33                         ` Mattias Engdegård
  2019-11-08 18:28                           ` martin rudalics
  1 sibling, 1 reply; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-08 17:33 UTC (permalink / raw)
  To: martin rudalics; +Cc: 38013

7 nov. 2019 kl. 20.08 skrev martin rudalics <rudalics@gmx.at>:

> But by doing so it usurps all combinations of the control key and
> mouse-1.  So we pay a high price for such a small convenience.  And
> since I have never anywhere else seen a "context" menu pop up right
> after a mouse press I would not consider it the expected behavior.

I can assure you that press-select-release semantics for popup menus is very common, and has been for several decades. Most applications also support the click-select-click model.

However, I think we largely agree that the current buffer and face menus are of limited utility and that their bindings should not be considered sacred territory.

> For me mouse-3 is the preferred button to pop up a menu.  I never use
> mouse-3 to extend the selection because I'm not used to switch mouse
> buttons during one and the same action.

Finally something we seem to agree on.

> I suggested control-shift because it's IMHO the most convenient
> combination with two modifiers (at least on my past and present
> keyboards).

Thank you; it's not very convenient on my keyboards, so I'd rather use control-meta, but plain meta is of course better still.
In decreasing order of preference: meta, control, shift, control-meta, shift-meta, shift-control.






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-08 17:33                         ` Mattias Engdegård
@ 2019-11-08 18:28                           ` martin rudalics
  2019-11-09 15:35                             ` Mattias Engdegård
  0 siblings, 1 reply; 55+ messages in thread
From: martin rudalics @ 2019-11-08 18:28 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

 > I can assure you that press-select-release semantics for popup menus
 > is very common,

At least here on Windows pressing the right mouse button does nothing
with Firefox, Thunderbird or the desktop.

 > and has been for several decades. Most applications also support the
 > click-select-click model.
 >
 > However, I think we largely agree that the current buffer and face
 > menus are of limited utility and that their bindings should not be
 > considered sacred territory.

I fully agree but obviously cannot speak for the others.  It would be
nice though to settle this very issue in order to free the down
bindings for good.

 > Thank you; it's not very convenient on my keyboards, so I'd rather
 > use control-meta, but plain meta is of course better still.  In
 > decreasing order of preference: meta, control, shift, control-meta,
 > shift-meta, shift-control.

It's clearly up to you to propose any of them.

martin





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-08 18:28                           ` martin rudalics
@ 2019-11-09 15:35                             ` Mattias Engdegård
  2019-11-09 17:54                               ` Eli Zaretskii
  2019-11-10  3:48                               ` Richard Stallman
  0 siblings, 2 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-09 15:35 UTC (permalink / raw)
  To: martin rudalics; +Cc: 38013

[-- Attachment #1: Type: text/plain, Size: 1057 bytes --]

8 nov. 2019 kl. 19.28 skrev martin rudalics <rudalics@gmx.at>:

> At least here on Windows pressing the right mouse button does nothing
> with Firefox, Thunderbird or the desktop.

Not much of a Windows user myself. Firefox on Linux allows press-drag-release.

> > However, I think we largely agree that the current buffer and face
> > menus are of limited utility and that their bindings should not be
> > considered sacred territory.
> 
> I fully agree but obviously cannot speak for the others.  It would be
> nice though to settle this very issue in order to free the down
> bindings for good.

Right. To avoid conflating issues, I propose using control-meta for rectangular selection at least as the initial binding. The attached patch also contains documentation updates.

Not sure what to do about the menus. Combining the buffer and appearance menus would free up a binding.

Eli had some concerns regarding the behaviour of an early patch, so I'll wait for him to take another look whenever he can spare a moment. (No hurry.)


[-- Attachment #2: 0001-Mouse-rectangular-region-selection-bug-38013.patch --]
[-- Type: application/octet-stream, Size: 7537 bytes --]

From 0e5430492a900e9396b5a40a03dca06ae94c8e04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Fri, 25 Oct 2019 11:16:39 +0200
Subject: [PATCH] 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.
* doc/emacs/frames.texi (Mouse Commands):
* doc/emacs/killing.texi (Rectangles):
* etc/NEWS (value): Document.
---
 doc/emacs/frames.texi  |  4 ++
 doc/emacs/killing.texi |  3 ++
 etc/NEWS               |  3 ++
 lisp/mouse.el          | 90 +++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 99 insertions(+), 1 deletion(-)

diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 091c011fb9..f6c2d23913 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -91,6 +91,10 @@ Mouse Commands
 click position; otherwise, set mark at the current value of point and
 point at the click position.  Save the resulting region in the kill
 ring; on a second click, kill it (@code{mouse-save-then-kill}).
+
+@item C-M-mouse-1
+Activate a rectangular region around the text selected by dragging.
+@xref{Rectangles}.
 @end table
 
 @findex mouse-set-point
diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi
index 80e2868908..ce00cb38a7 100644
--- a/doc/emacs/killing.texi
+++ b/doc/emacs/killing.texi
@@ -732,6 +732,9 @@ Rectangles
 and mark values can be interpreted either as a region or as a
 rectangle, depending on the command that uses them.
 
+  A rectangular region can also be marked using the mouse: click and drag
+@kbd{C-M-mouse-1} from one corner of the rectangle to the opposite.
+
 @table @kbd
 @item C-x r k
 Kill the text of the region-rectangle, saving its contents as the
diff --git a/etc/NEWS b/etc/NEWS
index 61b9f933f1..3d181b32da 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -582,6 +582,9 @@ region using a given replacement-function in a non-destructive manner
 arguments mitigating performance issues when operating on huge
 buffers.
 
++++
+** Dragging 'C-M-mouse-1' now marks rectangular regions.
+
 +++
 ** The command 'delete-indentation' now operates on the active region.
 If the region is active, the command joins all the lines in the
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 238852ffdc..5db1690eef 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1045,10 +1045,12 @@ mouse-scroll-min-lines
 of lines specified by this variable."
   :type 'integer)
 
-(defun mouse-scroll-subr (window jump &optional overlay start)
+(defun mouse-scroll-subr (window jump &optional overlay start adjust)
   "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
 If OVERLAY is an overlay, let it stretch from START to the far edge of
 the newly visible text.
+ADJUST, if non-nil, is a function, without arguments, to call after
+setting point.
 Upon exit, point is at the far edge of the newly visible text."
   (cond
    ((and (> jump 0) (< jump mouse-scroll-min-lines))
@@ -1077,6 +1079,8 @@ mouse-scroll-subr
 		   ;; so that we don't mess up the selected window.
 		   (or (eq window (selected-window))
 		       (goto-char opoint))
+                   (when adjust
+                     (funcall adjust))
 		   (sit-for mouse-scroll-delay)))))
     (or (eq window (selected-window))
 	(goto-char opoint))))
@@ -1960,6 +1964,90 @@ secondary-selection-from-region
     (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
 
 \f
+(defun mouse-drag-region-rectangle (start-event)
+  "Set the region to the rectangle that the mouse is dragged over.
+This must be bound to a button-down mouse event."
+  (interactive "e")
+  (let* ((scroll-margin 0)
+         (start-pos (event-start start-event))
+         (start-posn (event-start start-event))
+         (start-point (posn-point start-posn))
+         (start-window (posn-window start-posn))
+         (start-hscroll (window-hscroll start-window))
+         (start-col (+ (car (posn-col-row start-pos)) start-hscroll))
+         (bounds (window-edges start-window))
+         (top (nth 1 bounds))
+         (bottom (if (window-minibuffer-p start-window)
+                     (nth 3 bounds)
+                   (1- (nth 3 bounds))))
+         (dragged nil)
+         (old-track-mouse track-mouse))
+    (setq track-mouse t)
+    (set-transient-map
+     (let ((map (make-sparse-keymap)))
+       (define-key map [switch-frame] #'ignore)
+       (define-key map [select-window] #'ignore)
+       (define-key map [mouse-movement]
+         (lambda (event)
+           (interactive "e")
+           (unless dragged
+             ;; This is actually a drag.
+             (mouse-minibuffer-check start-event)
+             (deactivate-mark)
+             (posn-set-point start-pos)
+             (rectangle-mark-mode)
+             ;; Tell the rectangle selection about the exact column,
+             ;; since it might not correspond exactly to a valid
+             ;; position in the text.
+             (rectangle--col-pos start-col 'mark)
+             (rectangle--col-pos start-col 'point)
+
+             (setq dragged t))
+
+           (let* ((posn (event-end event))
+                  (window (posn-window posn))
+                  (hscroll (if (window-live-p window)
+                               (window-hscroll window)
+                             0))
+                  (mouse-pos (mouse-position))
+                  (mouse-col (+ (cadr mouse-pos) hscroll))
+                  (mouse-row (cddr mouse-pos)))
+             (if (and (eq window start-window)
+                      mouse-row
+                      (<= top mouse-row (1- bottom)))
+                 ;; Drag inside the same window.
+                 (progn
+                   (posn-set-point posn)
+                   (rectangle--col-pos mouse-col 'point))
+               ;; Drag outside the window: scroll.
+               (cond
+                ((null mouse-row))
+                ((< mouse-row top)
+                 (mouse-scroll-subr
+                  start-window (- mouse-row top) nil start-point
+                  (lambda () (rectangle--col-pos mouse-col 'point))))
+                ((>= mouse-row bottom)
+                 (mouse-scroll-subr
+                  start-window (1+ (- mouse-row bottom)) nil start-point
+                  (lambda () (rectangle--col-pos mouse-col 'point)))))))))
+       map)
+     t
+     (lambda ()
+       (setq track-mouse old-track-mouse)
+       (when (or (not dragged)
+                 (not (mark))
+                 (equal (rectangle-dimensions (mark) (point)) '(0 . 1)))
+         ;; No nontrivial region selected; deactivate rectangle mode.
+         (deactivate-mark))))))
+
+;; The drag event must be bound to something but does not need any effect,
+;; as everything takes place in `mouse-drag-region-rectangle'.
+;; The click event can be anything; `mouse-set-point' is just a convenience.
+(global-set-key [C-M-down-mouse-1] #'mouse-drag-region-rectangle)
+(global-set-key [C-M-drag-mouse-1] #'ignore)
+(global-set-key [C-M-mouse-1]      #'mouse-set-point)
+
+\f
 (defcustom mouse-buffer-menu-maxlen 20
   "Number of buffers in one pane (submenu) of the buffer menu.
 If we have lots of buffers, divide them into groups of
-- 
2.21.0 (Apple Git-122)


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-09 15:35                             ` Mattias Engdegård
@ 2019-11-09 17:54                               ` Eli Zaretskii
  2019-11-09 19:32                                 ` Mattias Engdegård
  2019-11-10  3:48                               ` Richard Stallman
  1 sibling, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2019-11-09 17:54 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

> From: Mattias Engdegård <mattiase@acm.org>
> Date: Sat, 9 Nov 2019 16:35:56 +0100
> Cc: 38013@debbugs.gnu.org, Eli Zaretskii <eliz@gnu.org>
> 
> Eli had some concerns regarding the behaviour of an early patch, so I'll wait for him to take another look whenever he can spare a moment. (No hurry.)

Not sure what I'm missing, but those issues I described before are
still there.  Can you tell what you changed and how?





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-09 17:54                               ` Eli Zaretskii
@ 2019-11-09 19:32                                 ` Mattias Engdegård
  2019-11-09 20:04                                   ` Eli Zaretskii
  0 siblings, 1 reply; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-09 19:32 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 38013

9 nov. 2019 kl. 18.54 skrev Eli Zaretskii <eliz@gnu.org>:

> Not sure what I'm missing, but those issues I described before are
> still there.  Can you tell what you changed and how?

In the first patch, the start and end corners of the rectangle had to be a point in the buffer; ie, not a position beyond the end of a line or in the middle of a tab character. That was not only unnecessarily restrictive but also made the rectangle flutter back and forth as the dragged corner passed through lines of different length. Now the rectangle corners can be any character cell.

If that was not the reason for your concern, would you mind describing the problem more in detail and how to reproduce it? 






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-09 19:32                                 ` Mattias Engdegård
@ 2019-11-09 20:04                                   ` Eli Zaretskii
  2019-11-10 13:49                                     ` Mattias Engdegård
  0 siblings, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2019-11-09 20:04 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

> From: Mattias Engdegård <mattiase@acm.org>
> Date: Sat, 9 Nov 2019 20:32:46 +0100
> Cc: rudalics@gmx.at, 38013@debbugs.gnu.org
> 
> In the first patch, the start and end corners of the rectangle had to be a point in the buffer; ie, not a position beyond the end of a line or in the middle of a tab character. That was not only unnecessarily restrictive but also made the rectangle flutter back and forth as the dragged corner passed through lines of different length. Now the rectangle corners can be any character cell.

OK, that's good.

> If that was not the reason for your concern, would you mind describing the problem more in detail and how to reproduce it? 

I still see a 1-pixel thin "region" sometimes, which causes the text
to move horizontally.  More importantly, if I drag the mouse through a
TAB, it moves in jumps of several columns, not one column at a time.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-09 15:35                             ` Mattias Engdegård
  2019-11-09 17:54                               ` Eli Zaretskii
@ 2019-11-10  3:48                               ` Richard Stallman
  1 sibling, 0 replies; 55+ messages in thread
From: Richard Stallman @ 2019-11-10  3:48 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > Not much of a Windows user myself.

Good for you!  When someone uses Windows (or MacOS, or Android, or iOS),
that is an instance of the unjust power that free software aims to
free people from.

				       Firefox on GNU/Linux allows press-drag-release.

-- 
Dr Richard Stallman
Founder, Free Software Foundation (https://gnu.org, https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-09 20:04                                   ` Eli Zaretskii
@ 2019-11-10 13:49                                     ` Mattias Engdegård
  2019-11-12 14:26                                       ` Mattias Engdegård
  2019-11-16 12:35                                       ` Eli Zaretskii
  0 siblings, 2 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-10 13:49 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 38013

9 nov. 2019 kl. 21.04 skrev Eli Zaretskii <eliz@gnu.org>:

> I still see a 1-pixel thin "region" sometimes, which causes the text
> to move horizontally.

Such 'thin' regions (0 cells wide) are legitimate and useful for marking a vertical span of insertion points. For example, they can be used with 'C-x r t' or 'C-x r N'. They are produced in keyboard-based rectangle selection (C-x SPC C-n C-n C-n) as well.

>  More importantly, if I drag the mouse through a
> TAB, it moves in jumps of several columns, not one column at a time.

The reason is that 'mouse-movement' events are not generated as long as the mouse stays within the same glyph, and a tab counts as a (suitably wide) single glyph. It can be worked around by zig-zagging the mouse a bit, but I agree it's untidy.

Fixing this requires some work on the lower-level plumbing which I'd hoped to avoid. One possibility is to add a global flag that forces 'remember_mouse_glyph' to consider all text glyphs to have nominal char width, or just zero width.

Or even simpler: assuming that STRETCH_GLYPHS are mostly tabs, we can treat them as image glyphs for 'remember_mouse_glyph' purposes. What about:

--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2572,7 +2572,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
 
 	  if (g < end)
 	    {
-	      if (g->type == IMAGE_GLYPH)
+	      if (g->type == IMAGE_GLYPH || g->type == STRETCH_GLYPH)







^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-10 13:49                                     ` Mattias Engdegård
@ 2019-11-12 14:26                                       ` Mattias Engdegård
  2019-11-12 15:39                                         ` Drew Adams
  2019-11-14 13:56                                         ` Mattias Engdegård
  2019-11-16 12:35                                       ` Eli Zaretskii
  1 sibling, 2 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-12 14:26 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 38013

[-- Attachment #1: Type: text/plain, Size: 312 bytes --]

This revised patch includes fine-grained mouse-movement events inside stretch glyphs, controlled by 'mouse-movement-in-tab'. Eli, does this fix the problems you observed?

If desired, the variable could be generalised to 'fine-grained-mouse-movement' and affect all movement (not just over stretch glyphs).


[-- Attachment #2: 0001-Mouse-rectangular-region-selection-bug-38013.patch --]
[-- Type: application/octet-stream, Size: 9030 bytes --]

From eb5c272a373310cc039cd6e55b29367d4c076f66 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Fri, 25 Oct 2019 11:16:39 +0200
Subject: [PATCH] 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.
* src/xdisp.c (remember_mouse_glyph):
(syms_of_xdisp): Add mouse-movement-in-tab, to allow fine-grained
mouse-movement events inside tabs on the screen (stretch glyphs
actually).
* doc/emacs/frames.texi (Mouse Commands):
* doc/emacs/killing.texi (Rectangles):
* etc/NEWS (value): Document.
---
 doc/emacs/frames.texi  |  4 ++
 doc/emacs/killing.texi |  3 ++
 etc/NEWS               |  3 ++
 lisp/mouse.el          | 93 +++++++++++++++++++++++++++++++++++++++++-
 src/xdisp.c            | 13 ++++--
 5 files changed, 112 insertions(+), 4 deletions(-)

diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 091c011fb9..f6c2d23913 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -91,6 +91,10 @@ Mouse Commands
 click position; otherwise, set mark at the current value of point and
 point at the click position.  Save the resulting region in the kill
 ring; on a second click, kill it (@code{mouse-save-then-kill}).
+
+@item C-M-mouse-1
+Activate a rectangular region around the text selected by dragging.
+@xref{Rectangles}.
 @end table
 
 @findex mouse-set-point
diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi
index 80e2868908..ce00cb38a7 100644
--- a/doc/emacs/killing.texi
+++ b/doc/emacs/killing.texi
@@ -732,6 +732,9 @@ Rectangles
 and mark values can be interpreted either as a region or as a
 rectangle, depending on the command that uses them.
 
+  A rectangular region can also be marked using the mouse: click and drag
+@kbd{C-M-mouse-1} from one corner of the rectangle to the opposite.
+
 @table @kbd
 @item C-x r k
 Kill the text of the region-rectangle, saving its contents as the
diff --git a/etc/NEWS b/etc/NEWS
index 61b9f933f1..3d181b32da 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -582,6 +582,9 @@ region using a given replacement-function in a non-destructive manner
 arguments mitigating performance issues when operating on huge
 buffers.
 
++++
+** Dragging 'C-M-mouse-1' now marks rectangular regions.
+
 +++
 ** The command 'delete-indentation' now operates on the active region.
 If the region is active, the command joins all the lines in the
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 238852ffdc..4de9684173 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1045,10 +1045,12 @@ mouse-scroll-min-lines
 of lines specified by this variable."
   :type 'integer)
 
-(defun mouse-scroll-subr (window jump &optional overlay start)
+(defun mouse-scroll-subr (window jump &optional overlay start adjust)
   "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
 If OVERLAY is an overlay, let it stretch from START to the far edge of
 the newly visible text.
+ADJUST, if non-nil, is a function, without arguments, to call after
+setting point.
 Upon exit, point is at the far edge of the newly visible text."
   (cond
    ((and (> jump 0) (< jump mouse-scroll-min-lines))
@@ -1077,6 +1079,8 @@ mouse-scroll-subr
 		   ;; so that we don't mess up the selected window.
 		   (or (eq window (selected-window))
 		       (goto-char opoint))
+                   (when adjust
+                     (funcall adjust))
 		   (sit-for mouse-scroll-delay)))))
     (or (eq window (selected-window))
 	(goto-char opoint))))
@@ -1960,6 +1964,93 @@ secondary-selection-from-region
     (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
 
 \f
+(defun mouse-drag-region-rectangle (start-event)
+  "Set the region to the rectangle that the mouse is dragged over.
+This must be bound to a button-down mouse event."
+  (interactive "e")
+  (let* ((scroll-margin 0)
+         (start-pos (event-start start-event))
+         (start-posn (event-start start-event))
+         (start-point (posn-point start-posn))
+         (start-window (posn-window start-posn))
+         (start-hscroll (window-hscroll start-window))
+         (start-col (+ (car (posn-col-row start-pos)) start-hscroll))
+         (bounds (window-edges start-window))
+         (top (nth 1 bounds))
+         (bottom (if (window-minibuffer-p start-window)
+                     (nth 3 bounds)
+                   (1- (nth 3 bounds))))
+         (dragged nil)
+         (old-track-mouse track-mouse)
+         (old-mouse-movement-in-tab mouse-movement-in-tab))
+    (setq track-mouse t)
+    (setq mouse-movement-in-tab t)
+    (set-transient-map
+     (let ((map (make-sparse-keymap)))
+       (define-key map [switch-frame] #'ignore)
+       (define-key map [select-window] #'ignore)
+       (define-key map [mouse-movement]
+         (lambda (event)
+           (interactive "e")
+           (unless dragged
+             ;; This is actually a drag.
+             (mouse-minibuffer-check start-event)
+             (deactivate-mark)
+             (posn-set-point start-pos)
+             (rectangle-mark-mode)
+             ;; Tell the rectangle selection about the exact column,
+             ;; since it might not correspond exactly to a valid
+             ;; position in the text.
+             (rectangle--col-pos start-col 'mark)
+             (rectangle--col-pos start-col 'point)
+
+             (setq dragged t))
+
+           (let* ((posn (event-end event))
+                  (window (posn-window posn))
+                  (hscroll (if (window-live-p window)
+                               (window-hscroll window)
+                             0))
+                  (mouse-pos (mouse-position))
+                  (mouse-col (+ (cadr mouse-pos) hscroll))
+                  (mouse-row (cddr mouse-pos)))
+             (if (and (eq window start-window)
+                      mouse-row
+                      (<= top mouse-row (1- bottom)))
+                 ;; Drag inside the same window.
+                 (progn
+                   (posn-set-point posn)
+                   (rectangle--col-pos mouse-col 'point))
+               ;; Drag outside the window: scroll.
+               (cond
+                ((null mouse-row))
+                ((< mouse-row top)
+                 (mouse-scroll-subr
+                  start-window (- mouse-row top) nil start-point
+                  (lambda () (rectangle--col-pos mouse-col 'point))))
+                ((>= mouse-row bottom)
+                 (mouse-scroll-subr
+                  start-window (1+ (- mouse-row bottom)) nil start-point
+                  (lambda () (rectangle--col-pos mouse-col 'point)))))))))
+       map)
+     t
+     (lambda ()
+       (setq track-mouse old-track-mouse)
+       (setq mouse-movement-in-tab old-mouse-movement-in-tab)
+       (when (or (not dragged)
+                 (not (mark))
+                 (equal (rectangle-dimensions (mark) (point)) '(0 . 1)))
+         ;; No nontrivial region selected; deactivate rectangle mode.
+         (deactivate-mark))))))
+
+;; The drag event must be bound to something but does not need any effect,
+;; as everything takes place in `mouse-drag-region-rectangle'.
+;; The click event can be anything; `mouse-set-point' is just a convenience.
+(global-set-key [C-M-down-mouse-1] #'mouse-drag-region-rectangle)
+(global-set-key [C-M-drag-mouse-1] #'ignore)
+(global-set-key [C-M-mouse-1]      #'mouse-set-point)
+
+\f
 (defcustom mouse-buffer-menu-maxlen 20
   "Number of buffers in one pane (submenu) of the buffer menu.
 If we have lots of buffers, divide them into groups of
diff --git a/src/xdisp.c b/src/xdisp.c
index 8aefab964a..717a94e385 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2572,10 +2572,11 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
 
 	  if (g < end)
 	    {
-	      if (g->type == IMAGE_GLYPH)
+	      if (g->type == IMAGE_GLYPH
+                  || (g->type == STRETCH_GLYPH && mouse_movement_in_tab))
 		{
-		  /* Don't remember when mouse is over image, as
-		     image may have hot-spots.  */
+		  /* Don't remember when mouse is over an image, as
+		     images may have hot-spots.  */
 		  STORE_NATIVE_RECT (*rect, 0, 0, 0, 0);
 		  return;
 		}
@@ -34939,6 +34940,12 @@ syms_of_xdisp (void)
 may be more familiar to users.  */);
   display_raw_bytes_as_hex = false;
 
+  DEFVAR_BOOL ("mouse-movement-in-tab", mouse_movement_in_tab,
+    doc: /* Non-nil means generate mouse-movement events inside tab chars.
+When nil, mouse-movement events will not be generated as long as the
+mouse stays within the extent of a single tab character.  */);
+  mouse_movement_in_tab = false;
+
 }
 
 
-- 
2.21.0 (Apple Git-122)


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-12 14:26                                       ` Mattias Engdegård
@ 2019-11-12 15:39                                         ` Drew Adams
  2019-11-14 13:56                                         ` Mattias Engdegård
  1 sibling, 0 replies; 55+ messages in thread
From: Drew Adams @ 2019-11-12 15:39 UTC (permalink / raw)
  To: Mattias Engdegård, Eli Zaretskii; +Cc: 38013

Again, this is wrong:

 "Dragging 'C-M-mouse-1' now marks rectangular regions."

This shouldn't be done, IMO.  No default
binding should be made for this.

After years of user experience, we can, if
appropriate, provide a default binding based
on what users actually use.  There's no good
excuse for doing that now, IMHO. 





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-12 14:26                                       ` Mattias Engdegård
  2019-11-12 15:39                                         ` Drew Adams
@ 2019-11-14 13:56                                         ` Mattias Engdegård
  1 sibling, 0 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-14 13:56 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 38013

[-- Attachment #1: Type: text/plain, Size: 134 bytes --]

Slightly polished patch, where the variable is now 'fine-grained-mouse-movement' which seems more generally useful. Please review.


[-- Attachment #2: 0001-Mouse-rectangular-region-selection-bug-38013.patch --]
[-- Type: application/octet-stream, Size: 9593 bytes --]

From b18836b6a23843ce5ca4cdb3524b0b1a3f210f8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Fri, 25 Oct 2019 11:16:39 +0200
Subject: [PATCH] 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.
* src/xdisp.c (remember_mouse_glyph, syms_of_xdisp):
Add 'fine-grained-mouse-movement'.
* doc/emacs/frames.texi (Mouse Commands):
* doc/emacs/killing.texi (Rectangles):
* doc/lispref/commands.texi (Motion Events):
* etc/NEWS: Document.
---
 doc/emacs/frames.texi     |  4 ++
 doc/emacs/killing.texi    |  3 ++
 doc/lispref/commands.texi |  6 +++
 etc/NEWS                  |  3 ++
 lisp/mouse.el             | 93 ++++++++++++++++++++++++++++++++++++++-
 src/xdisp.c               | 12 +++++
 6 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 091c011fb9..f6c2d23913 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -91,6 +91,10 @@ Mouse Commands
 click position; otherwise, set mark at the current value of point and
 point at the click position.  Save the resulting region in the kill
 ring; on a second click, kill it (@code{mouse-save-then-kill}).
+
+@item C-M-mouse-1
+Activate a rectangular region around the text selected by dragging.
+@xref{Rectangles}.
 @end table
 
 @findex mouse-set-point
diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi
index 80e2868908..ce00cb38a7 100644
--- a/doc/emacs/killing.texi
+++ b/doc/emacs/killing.texi
@@ -732,6 +732,9 @@ Rectangles
 and mark values can be interpreted either as a region or as a
 rectangle, depending on the command that uses them.
 
+  A rectangular region can also be marked using the mouse: click and drag
+@kbd{C-M-mouse-1} from one corner of the rectangle to the opposite.
+
 @table @kbd
 @item C-x r k
 Kill the text of the region-rectangle, saving its contents as the
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 0c848a8025..8a614c721f 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -1661,6 +1661,12 @@ Motion Events
 does not generate events for mere motion of the mouse, and these
 events do not appear.  @xref{Mouse Tracking}.
 
+@defvar fine-grained-mouse-movement
+When non-@code{nil}, mouse motion events are generated even for very
+small movements.  Otherwise, motion events are not generated as long
+as the mouse cursor remains pointing to the same glyph in the text.
+@end defvar
+
 @node Focus Events
 @subsection Focus Events
 @cindex focus event
diff --git a/etc/NEWS b/etc/NEWS
index 485d2b1fdf..db00d40bb6 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -582,6 +582,9 @@ region using a given replacement-function in a non-destructive manner
 arguments mitigating performance issues when operating on huge
 buffers.
 
++++
+** Dragging 'C-M-mouse-1' now marks rectangular regions.
+
 +++
 ** The command 'delete-indentation' now operates on the active region.
 If the region is active, the command joins all the lines in the
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 238852ffdc..b4c297d0b4 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1045,10 +1045,12 @@ mouse-scroll-min-lines
 of lines specified by this variable."
   :type 'integer)
 
-(defun mouse-scroll-subr (window jump &optional overlay start)
+(defun mouse-scroll-subr (window jump &optional overlay start adjust)
   "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
 If OVERLAY is an overlay, let it stretch from START to the far edge of
 the newly visible text.
+ADJUST, if non-nil, is a function, without arguments, to call after
+setting point.
 Upon exit, point is at the far edge of the newly visible text."
   (cond
    ((and (> jump 0) (< jump mouse-scroll-min-lines))
@@ -1077,6 +1079,8 @@ mouse-scroll-subr
 		   ;; so that we don't mess up the selected window.
 		   (or (eq window (selected-window))
 		       (goto-char opoint))
+                   (when adjust
+                     (funcall adjust))
 		   (sit-for mouse-scroll-delay)))))
     (or (eq window (selected-window))
 	(goto-char opoint))))
@@ -1960,6 +1964,93 @@ secondary-selection-from-region
     (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
 
 \f
+(defun mouse-drag-region-rectangle (start-event)
+  "Set the region to the rectangle that the mouse is dragged over.
+This must be bound to a button-down mouse event."
+  (interactive "e")
+  (let* ((scroll-margin 0)
+         (start-pos (event-start start-event))
+         (start-posn (event-start start-event))
+         (start-point (posn-point start-posn))
+         (start-window (posn-window start-posn))
+         (start-hscroll (window-hscroll start-window))
+         (start-col (+ (car (posn-col-row start-pos)) start-hscroll))
+         (bounds (window-edges start-window))
+         (top (nth 1 bounds))
+         (bottom (if (window-minibuffer-p start-window)
+                     (nth 3 bounds)
+                   (1- (nth 3 bounds))))
+         (dragged nil)
+         (old-track-mouse track-mouse)
+         (old-fine-grained-mouse-movement fine-grained-mouse-movement))
+    (setq track-mouse t)
+    (setq fine-grained-mouse-movement t)
+    (set-transient-map
+     (let ((map (make-sparse-keymap)))
+       (define-key map [switch-frame] #'ignore)
+       (define-key map [select-window] #'ignore)
+       (define-key map [mouse-movement]
+         (lambda (event)
+           (interactive "e")
+           (unless dragged
+             ;; This is actually a drag.
+             (mouse-minibuffer-check start-event)
+             (deactivate-mark)
+             (posn-set-point start-pos)
+             (rectangle-mark-mode)
+             ;; Tell the rectangle selection about the exact column,
+             ;; since it might not correspond exactly to a valid
+             ;; position in the text.
+             (rectangle--col-pos start-col 'mark)
+             (rectangle--col-pos start-col 'point)
+
+             (setq dragged t))
+
+           (let* ((posn (event-end event))
+                  (window (posn-window posn))
+                  (hscroll (if (window-live-p window)
+                               (window-hscroll window)
+                             0))
+                  (mouse-pos (mouse-position))
+                  (mouse-col (+ (cadr mouse-pos) hscroll))
+                  (mouse-row (cddr mouse-pos)))
+             (if (and (eq window start-window)
+                      mouse-row
+                      (<= top mouse-row (1- bottom)))
+                 ;; Drag inside the same window.
+                 (progn
+                   (posn-set-point posn)
+                   (rectangle--col-pos mouse-col 'point))
+               ;; Drag outside the window: scroll.
+               (cond
+                ((null mouse-row))
+                ((< mouse-row top)
+                 (mouse-scroll-subr
+                  start-window (- mouse-row top) nil start-point
+                  (lambda () (rectangle--col-pos mouse-col 'point))))
+                ((>= mouse-row bottom)
+                 (mouse-scroll-subr
+                  start-window (1+ (- mouse-row bottom)) nil start-point
+                  (lambda () (rectangle--col-pos mouse-col 'point)))))))))
+       map)
+     t
+     (lambda ()
+       (setq track-mouse old-track-mouse)
+       (setq fine-grained-mouse-movement old-fine-grained-mouse-movement)
+       (when (or (not dragged)
+                 (not (mark))
+                 (equal (rectangle-dimensions (mark) (point)) '(0 . 1)))
+         ;; No nontrivial region selected; deactivate rectangle mode.
+         (deactivate-mark))))))
+
+;; The drag event must be bound to something but does not need any effect,
+;; as everything takes place in `mouse-drag-region-rectangle'.
+;; The click event can be anything; `mouse-set-point' is just a convenience.
+(global-set-key [C-M-down-mouse-1] #'mouse-drag-region-rectangle)
+(global-set-key [C-M-drag-mouse-1] #'ignore)
+(global-set-key [C-M-mouse-1]      #'mouse-set-point)
+
+\f
 (defcustom mouse-buffer-menu-maxlen 20
   "Number of buffers in one pane (submenu) of the buffer menu.
 If we have lots of buffers, divide them into groups of
diff --git a/src/xdisp.c b/src/xdisp.c
index 8aefab964a..9b4484e899 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)
   enum glyph_row_area area;
   int x, y, width, height;
 
+  if (fine_grained_mouse_movement)
+    {
+      STORE_NATIVE_RECT (*rect, gx, gy, 1, 1);
+      return;
+    }
+
   /* Try to determine frame pixel position and size of the glyph under
      frame pixel coordinates X/Y on frame F.  */
 
@@ -34939,6 +34945,12 @@ syms_of_xdisp (void)
 may be more familiar to users.  */);
   display_raw_bytes_as_hex = false;
 
+  DEFVAR_BOOL ("fine-grained-mouse-movement", fine_grained_mouse_movement,
+    doc: /* Non-nil for pixel-wise mouse-movement.
+When nil, mouse-movement events will not be generated as long as the
+mouse stays within the extent of a single glyph (except for images).  */);
+  fine_grained_mouse_movement = false;
+
 }
 
 
-- 
2.21.0 (Apple Git-122)


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-10 13:49                                     ` Mattias Engdegård
  2019-11-12 14:26                                       ` Mattias Engdegård
@ 2019-11-16 12:35                                       ` Eli Zaretskii
  2019-11-17 12:11                                         ` Mattias Engdegård
  1 sibling, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2019-11-16 12:35 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

> From: Mattias Engdegård <mattiase@acm.org>
> Date: Sun, 10 Nov 2019 14:49:11 +0100
> Cc: rudalics@gmx.at, 38013@debbugs.gnu.org
> 
> Or even simpler: assuming that STRETCH_GLYPHS are mostly tabs, we can treat them as image glyphs for 'remember_mouse_glyph' purposes. What about:
> 
> --- a/src/xdisp.c
> +++ b/src/xdisp.c
> @@ -2572,7 +2572,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
>  
>  	  if (g < end)
>  	    {
> -	      if (g->type == IMAGE_GLYPH)
> +	      if (g->type == IMAGE_GLYPH || g->type == STRETCH_GLYPH)

Sorry for a late response.

Did you try this with stretch glyphs generated by the likes of
:align-to display 'space' properties?  Also, what about stretch glyphs
generated by the display engine in R2L screen lines (you can get those
easily by visiting TUTORIAL.he: each line that has white space at its
left end has a stretch glyph there)?

IOW, it might be necessary to add more conditions here, and just the
mouse_movement_in_tab thingy you added in a later version might not be
enough.  E.g., we may need a condition that verifies that this is a
TAB (should be easy by looking at glyph->object, I think).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-16 12:35                                       ` Eli Zaretskii
@ 2019-11-17 12:11                                         ` Mattias Engdegård
  2019-11-18 18:08                                           ` Mattias Engdegård
  0 siblings, 1 reply; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-17 12:11 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 38013

[-- Attachment #1: Type: text/plain, Size: 1181 bytes --]

16 nov. 2019 kl. 13.35 skrev Eli Zaretskii <eliz@gnu.org>:

> Did you try this with stretch glyphs generated by the likes of
> :align-to display 'space' properties?  Also, what about stretch glyphs
> generated by the display engine in R2L screen lines (you can get those
> easily by visiting TUTORIAL.he: each line that has white space at its
> left end has a stretch glyph there)?

I didn't try right-to-left text until now --- thanks for prodding --- and the behaviour was predictably awful. An updated patch (attached) tries to do better (up to what is possible with the underlying rect.el machinery).

> IOW, it might be necessary to add more conditions here, and just the
> mouse_movement_in_tab thingy you added in a later version might not be
> enough.  E.g., we may need a condition that verifies that this is a
> TAB (should be easy by looking at glyph->object, I think).

After some false starts, I settled on the simpler 'fine-grained-mouse-movement' solution, giving pixel-wise events no matter what the mouse is pointing at. The extra cost for this is imperceptibly slight, and it feels more generally useful than the 'mouse-movement-in-tab' thingy.


[-- Attachment #2: 0001-Mouse-rectangular-region-selection-bug-38013.patch --]
[-- Type: application/octet-stream, Size: 10129 bytes --]

From ae6f97f70ad7d76359a5746c68ec53e9f285c7fa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Fri, 25 Oct 2019 11:16:39 +0200
Subject: [PATCH] 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.
* src/xdisp.c (remember_mouse_glyph, syms_of_xdisp):
Add 'fine-grained-mouse-movement'.
* doc/emacs/frames.texi (Mouse Commands):
* doc/emacs/killing.texi (Rectangles):
* doc/lispref/commands.texi (Motion Events):
* etc/NEWS: Document.
---
 doc/emacs/frames.texi     |   4 ++
 doc/emacs/killing.texi    |   3 ++
 doc/lispref/commands.texi |   6 +++
 etc/NEWS                  |   3 ++
 lisp/mouse.el             | 104 +++++++++++++++++++++++++++++++++++++-
 src/xdisp.c               |  12 +++++
 6 files changed, 131 insertions(+), 1 deletion(-)

diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 091c011fb9..f6c2d23913 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -91,6 +91,10 @@ Mouse Commands
 click position; otherwise, set mark at the current value of point and
 point at the click position.  Save the resulting region in the kill
 ring; on a second click, kill it (@code{mouse-save-then-kill}).
+
+@item C-M-mouse-1
+Activate a rectangular region around the text selected by dragging.
+@xref{Rectangles}.
 @end table
 
 @findex mouse-set-point
diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi
index 80e2868908..ce00cb38a7 100644
--- a/doc/emacs/killing.texi
+++ b/doc/emacs/killing.texi
@@ -732,6 +732,9 @@ Rectangles
 and mark values can be interpreted either as a region or as a
 rectangle, depending on the command that uses them.
 
+  A rectangular region can also be marked using the mouse: click and drag
+@kbd{C-M-mouse-1} from one corner of the rectangle to the opposite.
+
 @table @kbd
 @item C-x r k
 Kill the text of the region-rectangle, saving its contents as the
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 0c848a8025..8a614c721f 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -1661,6 +1661,12 @@ Motion Events
 does not generate events for mere motion of the mouse, and these
 events do not appear.  @xref{Mouse Tracking}.
 
+@defvar fine-grained-mouse-movement
+When non-@code{nil}, mouse motion events are generated even for very
+small movements.  Otherwise, motion events are not generated as long
+as the mouse cursor remains pointing to the same glyph in the text.
+@end defvar
+
 @node Focus Events
 @subsection Focus Events
 @cindex focus event
diff --git a/etc/NEWS b/etc/NEWS
index 485d2b1fdf..db00d40bb6 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -582,6 +582,9 @@ region using a given replacement-function in a non-destructive manner
 arguments mitigating performance issues when operating on huge
 buffers.
 
++++
+** Dragging 'C-M-mouse-1' now marks rectangular regions.
+
 +++
 ** The command 'delete-indentation' now operates on the active region.
 If the region is active, the command joins all the lines in the
diff --git a/lisp/mouse.el b/lisp/mouse.el
index c91760a734..befa85d80d 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1045,10 +1045,12 @@ mouse-scroll-min-lines
 of lines specified by this variable."
   :type 'integer)
 
-(defun mouse-scroll-subr (window jump &optional overlay start)
+(defun mouse-scroll-subr (window jump &optional overlay start adjust)
   "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
 If OVERLAY is an overlay, let it stretch from START to the far edge of
 the newly visible text.
+ADJUST, if non-nil, is a function, without arguments, to call after
+setting point.
 Upon exit, point is at the far edge of the newly visible text."
   (cond
    ((and (> jump 0) (< jump mouse-scroll-min-lines))
@@ -1077,6 +1079,8 @@ mouse-scroll-subr
 		   ;; so that we don't mess up the selected window.
 		   (or (eq window (selected-window))
 		       (goto-char opoint))
+                   (when adjust
+                     (funcall adjust))
 		   (sit-for mouse-scroll-delay)))))
     (or (eq window (selected-window))
 	(goto-char opoint))))
@@ -1960,6 +1964,104 @@ secondary-selection-from-region
     (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
 
 \f
+(defun mouse-drag-region-rectangle (start-event)
+  "Set the region to the rectangle that the mouse is dragged over.
+This must be bound to a button-down mouse event."
+  (interactive "e")
+  (let* ((scroll-margin 0)
+         (start-pos (event-start start-event))
+         (start-posn (event-start start-event))
+         (start-point (posn-point start-posn))
+         (start-window (posn-window start-posn))
+         (start-hscroll (window-hscroll start-window))
+         (start-col (+ (car (posn-col-row start-pos)) start-hscroll))
+         (bounds (window-edges start-window))
+         (top (nth 1 bounds))
+         (bottom (if (window-minibuffer-p start-window)
+                     (nth 3 bounds)
+                   (1- (nth 3 bounds))))
+         (dragged nil)
+         (old-track-mouse track-mouse)
+         (old-fine-grained-mouse-movement fine-grained-mouse-movement)
+         ;; For right-to-left text, columns are counted from the right margin;
+         ;; translate from mouse events, which always count from the left.
+         (adjusted-col (lambda (col)
+                         (if (eq (current-bidi-paragraph-direction)
+                                 'right-to-left)
+                             (- (frame-text-cols) col -1)
+                           col))))
+    (setq track-mouse t)
+    (setq fine-grained-mouse-movement t)
+    (set-transient-map
+     (let ((map (make-sparse-keymap)))
+       (define-key map [switch-frame] #'ignore)
+       (define-key map [select-window] #'ignore)
+       (define-key map [mouse-movement]
+         (lambda (event)
+           (interactive "e")
+           (unless dragged
+             ;; This is actually a drag.
+             (mouse-minibuffer-check start-event)
+             (deactivate-mark)
+             (posn-set-point start-pos)
+             (rectangle-mark-mode)
+             ;; Tell the rectangle selection about the exact column,
+             ;; since it might not correspond exactly to a valid
+             ;; position in the text.
+             (let ((col (funcall adjusted-col start-col)))
+               (rectangle--col-pos col 'mark)
+               (rectangle--col-pos col 'point))
+
+             (setq dragged t))
+
+           (let* ((posn (event-end event))
+                  (window (posn-window posn))
+                  (hscroll (if (window-live-p window)
+                               (window-hscroll window)
+                             0))
+                  (mouse-pos (mouse-position))
+                  (mouse-col (+ (cadr mouse-pos) hscroll))
+                  (mouse-row (cddr mouse-pos))
+                  (set-col (lambda ()
+                             (rectangle--col-pos
+                              (funcall adjusted-col mouse-col) 'point))))
+             (if (and (eq window start-window)
+                      mouse-row
+                      (<= top mouse-row (1- bottom)))
+                 ;; Drag inside the same window.
+                 (progn
+                   (posn-set-point posn)
+                   (funcall set-col))
+               ;; Drag outside the window: scroll.
+               (cond
+                ((null mouse-row))
+                ((< mouse-row top)
+                 (mouse-scroll-subr
+                  start-window (- mouse-row top) nil start-point
+                  set-col))
+                ((>= mouse-row bottom)
+                 (mouse-scroll-subr
+                  start-window (1+ (- mouse-row bottom)) nil start-point
+                  set-col)))))))
+       map)
+     t
+     (lambda ()
+       (setq track-mouse old-track-mouse)
+       (setq fine-grained-mouse-movement old-fine-grained-mouse-movement)
+       (when (or (not dragged)
+                 (not (mark))
+                 (equal (rectangle-dimensions (mark) (point)) '(0 . 1)))
+         ;; No nontrivial region selected; deactivate rectangle mode.
+         (deactivate-mark))))))
+
+;; The drag event must be bound to something but does not need any effect,
+;; as everything takes place in `mouse-drag-region-rectangle'.
+;; The click event can be anything; `mouse-set-point' is just a convenience.
+(global-set-key [C-M-down-mouse-1] #'mouse-drag-region-rectangle)
+(global-set-key [C-M-drag-mouse-1] #'ignore)
+(global-set-key [C-M-mouse-1]      #'mouse-set-point)
+
+\f
 (defcustom mouse-buffer-menu-maxlen 20
   "Number of buffers in one pane (submenu) of the buffer menu.
 If we have lots of buffers, divide them into groups of
diff --git a/src/xdisp.c b/src/xdisp.c
index c5676b3e17..384827c94e 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)
   enum glyph_row_area area;
   int x, y, width, height;
 
+  if (fine_grained_mouse_movement)
+    {
+      STORE_NATIVE_RECT (*rect, gx, gy, 1, 1);
+      return;
+    }
+
   /* Try to determine frame pixel position and size of the glyph under
      frame pixel coordinates X/Y on frame F.  */
 
@@ -34943,6 +34949,12 @@ syms_of_xdisp (void)
 may be more familiar to users.  */);
   display_raw_bytes_as_hex = false;
 
+  DEFVAR_BOOL ("fine-grained-mouse-movement", fine_grained_mouse_movement,
+    doc: /* Non-nil for pixel-wise mouse-movement.
+When nil, mouse-movement events will not be generated as long as the
+mouse stays within the extent of a single glyph (except for images).  */);
+  fine_grained_mouse_movement = false;
+
 }
 
 
-- 
2.21.0 (Apple Git-122)


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-17 12:11                                         ` Mattias Engdegård
@ 2019-11-18 18:08                                           ` Mattias Engdegård
  2019-11-18 19:22                                             ` Drew Adams
  2019-11-23 11:57                                             ` Eli Zaretskii
  0 siblings, 2 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-18 18:08 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 38013

[-- Attachment #1: Type: text/plain, Size: 326 bytes --]

Here is an updated patch that makes the selection work better with characters that aren't a multiple of the standard font width. 

The underlying rect.el isn't really geared for this sort of thing, leading to ragged rectangle edges and other effects, but at least it is not a new problem; this is not the time to fix it.


[-- Attachment #2: 0001-Mouse-rectangular-region-selection-bug-38013.patch --]
[-- Type: application/octet-stream, Size: 11528 bytes --]

From 38cc3baa7f01f418653e36cc5d8e4cf5b151d26e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Fri, 25 Oct 2019 11:16:39 +0200
Subject: [PATCH] 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 'fine-grained-mouse-movement'.
* doc/lispref/commands.texi (Motion Events):
Document 'fine-grained-mouse-movement'.
* doc/emacs/frames.texi (Mouse Commands):
* doc/emacs/killing.texi (Rectangles):
* etc/NEWS: Document rectangular selection with the mouse.
---
 doc/emacs/frames.texi     |   4 ++
 doc/emacs/killing.texi    |   3 ++
 doc/lispref/commands.texi |   6 +++
 etc/NEWS                  |   3 ++
 lisp/mouse.el             | 109 +++++++++++++++++++++++++++++++++++++-
 lisp/rect.el              |   8 ++-
 src/xdisp.c               |  12 +++++
 7 files changed, 142 insertions(+), 3 deletions(-)

diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 091c011fb9..f6c2d23913 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -91,6 +91,10 @@ Mouse Commands
 click position; otherwise, set mark at the current value of point and
 point at the click position.  Save the resulting region in the kill
 ring; on a second click, kill it (@code{mouse-save-then-kill}).
+
+@item C-M-mouse-1
+Activate a rectangular region around the text selected by dragging.
+@xref{Rectangles}.
 @end table
 
 @findex mouse-set-point
diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi
index 80e2868908..ce00cb38a7 100644
--- a/doc/emacs/killing.texi
+++ b/doc/emacs/killing.texi
@@ -732,6 +732,9 @@ Rectangles
 and mark values can be interpreted either as a region or as a
 rectangle, depending on the command that uses them.
 
+  A rectangular region can also be marked using the mouse: click and drag
+@kbd{C-M-mouse-1} from one corner of the rectangle to the opposite.
+
 @table @kbd
 @item C-x r k
 Kill the text of the region-rectangle, saving its contents as the
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 0c848a8025..8a614c721f 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -1661,6 +1661,12 @@ Motion Events
 does not generate events for mere motion of the mouse, and these
 events do not appear.  @xref{Mouse Tracking}.
 
+@defvar fine-grained-mouse-movement
+When non-@code{nil}, mouse motion events are generated even for very
+small movements.  Otherwise, motion events are not generated as long
+as the mouse cursor remains pointing to the same glyph in the text.
+@end defvar
+
 @node Focus Events
 @subsection Focus Events
 @cindex focus event
diff --git a/etc/NEWS b/etc/NEWS
index 485d2b1fdf..db00d40bb6 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -582,6 +582,9 @@ region using a given replacement-function in a non-destructive manner
 arguments mitigating performance issues when operating on huge
 buffers.
 
++++
+** Dragging 'C-M-mouse-1' now marks rectangular regions.
+
 +++
 ** The command 'delete-indentation' now operates on the active region.
 If the region is active, the command joins all the lines in the
diff --git a/lisp/mouse.el b/lisp/mouse.el
index c91760a734..29cb9716c3 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1045,10 +1045,12 @@ mouse-scroll-min-lines
 of lines specified by this variable."
   :type 'integer)
 
-(defun mouse-scroll-subr (window jump &optional overlay start)
+(defun mouse-scroll-subr (window jump &optional overlay start adjust)
   "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
 If OVERLAY is an overlay, let it stretch from START to the far edge of
 the newly visible text.
+ADJUST, if non-nil, is a function, without arguments, to call after
+setting point.
 Upon exit, point is at the far edge of the newly visible text."
   (cond
    ((and (> jump 0) (< jump mouse-scroll-min-lines))
@@ -1077,6 +1079,8 @@ mouse-scroll-subr
 		   ;; so that we don't mess up the selected window.
 		   (or (eq window (selected-window))
 		       (goto-char opoint))
+                   (when adjust
+                     (funcall adjust))
 		   (sit-for mouse-scroll-delay)))))
     (or (eq window (selected-window))
 	(goto-char opoint))))
@@ -1960,6 +1964,109 @@ secondary-selection-from-region
     (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
 
 \f
+(defun mouse-drag-region-rectangle (start-event)
+  "Set the region to the rectangle that the mouse is dragged over.
+This must be bound to a button-down mouse event."
+  (interactive "e")
+  (let* ((scroll-margin 0)
+         (start-pos (event-start start-event))
+         (start-posn (event-start start-event))
+         (start-point (posn-point start-posn))
+         (start-window (posn-window start-posn))
+         (start-hscroll (window-hscroll start-window))
+         (start-col (+ (car (posn-col-row start-pos)) start-hscroll))
+         (bounds (window-edges start-window))
+         (top (nth 1 bounds))
+         (bottom (if (window-minibuffer-p start-window)
+                     (nth 3 bounds)
+                   (1- (nth 3 bounds))))
+         (dragged nil)
+         (old-track-mouse track-mouse)
+         (old-fine-grained-mouse-movement fine-grained-mouse-movement)
+         ;; For right-to-left text, columns are counted from the right margin;
+         ;; translate from mouse events, which always count from the left.
+         (adjusted-col (lambda (col)
+                         (if (eq (current-bidi-paragraph-direction)
+                                 'right-to-left)
+                             (- (frame-text-cols) col -1)
+                           col))))
+    (setq track-mouse t)
+    (setq fine-grained-mouse-movement t)
+    (set-transient-map
+     (let ((map (make-sparse-keymap)))
+       (define-key map [switch-frame] #'ignore)
+       (define-key map [select-window] #'ignore)
+       (define-key map [mouse-movement]
+         (lambda (event)
+           (interactive "e")
+           (unless dragged
+             ;; This is actually a drag.
+             (mouse-minibuffer-check start-event)
+             (deactivate-mark)
+             (posn-set-point start-pos)
+             (rectangle-mark-mode)
+             ;; Only tell rectangle about the exact column if we are possibly
+             ;; beyond end-of-line or in a tab, since the column we got from
+             ;; the mouse position isn't necessarily accurate for use in
+             ;; specifying a rectangle (which uses the `move-to-column'
+             ;; measure).
+             (when (or (eolp) (eq (following-char) ?\t))
+               (let ((col (funcall adjusted-col start-col)))
+                 (rectangle--col-pos col 'mark)
+                 (rectangle--col-pos col 'point)))
+
+             (setq dragged t))
+
+           (let* ((posn (event-end event))
+                  (window (posn-window posn))
+                  (hscroll (if (window-live-p window)
+                               (window-hscroll window)
+                             0))
+                  (mouse-pos (mouse-position))
+                  (mouse-col (+ (cadr mouse-pos) hscroll))
+                  (mouse-row (cddr mouse-pos))
+                  (set-col (lambda ()
+                             (if (or (eolp) (eq (following-char) ?\t))
+                                 (rectangle--col-pos
+                                  (funcall adjusted-col mouse-col) 'point)
+                               (rectangle--reset-point-crutches)))))
+             (if (and (eq window start-window)
+                      mouse-row
+                      (<= top mouse-row (1- bottom)))
+                 ;; Drag inside the same window.
+                 (progn
+                   (posn-set-point posn)
+                   (funcall set-col))
+               ;; Drag outside the window: scroll.
+               (cond
+                ((null mouse-row))
+                ((< mouse-row top)
+                 (mouse-scroll-subr
+                  start-window (- mouse-row top) nil start-point
+                  set-col))
+                ((>= mouse-row bottom)
+                 (mouse-scroll-subr
+                  start-window (1+ (- mouse-row bottom)) nil start-point
+                  set-col)))))))
+       map)
+     t
+     (lambda ()
+       (setq track-mouse old-track-mouse)
+       (setq fine-grained-mouse-movement old-fine-grained-mouse-movement)
+       (when (or (not dragged)
+                 (not (mark))
+                 (equal (rectangle-dimensions (mark) (point)) '(0 . 1)))
+         ;; No nontrivial region selected; deactivate rectangle mode.
+         (deactivate-mark))))))
+
+;; The drag event must be bound to something but does not need any effect,
+;; as everything takes place in `mouse-drag-region-rectangle'.
+;; The click event can be anything; `mouse-set-point' is just a convenience.
+(global-set-key [C-M-down-mouse-1] #'mouse-drag-region-rectangle)
+(global-set-key [C-M-drag-mouse-1] #'ignore)
+(global-set-key [C-M-mouse-1]      #'mouse-set-point)
+
+\f
 (defcustom mouse-buffer-menu-maxlen 20
   "Number of buffers in one pane (submenu) of the buffer menu.
 If we have lots of buffers, divide them into groups of
diff --git a/lisp/rect.el b/lisp/rect.el
index 4d4d6146f2..1109786fc5 100644
--- a/lisp/rect.el
+++ b/lisp/rect.el
@@ -133,11 +133,15 @@ rectangle--point-col
 (defun rectangle--crutches ()
   (cons rectangle--mark-crutches
         (window-parameter nil 'rectangle--point-crutches)))
-(defun rectangle--reset-crutches ()
-  (kill-local-variable 'rectangle--mark-crutches)
+
+(defun rectangle--reset-point-crutches ()
   (if (window-parameter nil 'rectangle--point-crutches)
       (setf (window-parameter nil 'rectangle--point-crutches) nil)))
 
+(defun rectangle--reset-crutches ()
+  (kill-local-variable 'rectangle--mark-crutches)
+  (rectangle--reset-point-crutches))
+
 ;;; Rectangle operations.
 
 (defun apply-on-rectangle (function start end &rest args)
diff --git a/src/xdisp.c b/src/xdisp.c
index c5676b3e17..384827c94e 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)
   enum glyph_row_area area;
   int x, y, width, height;
 
+  if (fine_grained_mouse_movement)
+    {
+      STORE_NATIVE_RECT (*rect, gx, gy, 1, 1);
+      return;
+    }
+
   /* Try to determine frame pixel position and size of the glyph under
      frame pixel coordinates X/Y on frame F.  */
 
@@ -34943,6 +34949,12 @@ syms_of_xdisp (void)
 may be more familiar to users.  */);
   display_raw_bytes_as_hex = false;
 
+  DEFVAR_BOOL ("fine-grained-mouse-movement", fine_grained_mouse_movement,
+    doc: /* Non-nil for pixel-wise mouse-movement.
+When nil, mouse-movement events will not be generated as long as the
+mouse stays within the extent of a single glyph (except for images).  */);
+  fine_grained_mouse_movement = false;
+
 }
 
 
-- 
2.21.0 (Apple Git-122)


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-18 18:08                                           ` Mattias Engdegård
@ 2019-11-18 19:22                                             ` Drew Adams
  2019-11-18 21:29                                               ` Juri Linkov
  2019-11-23 11:57                                             ` Eli Zaretskii
  1 sibling, 1 reply; 55+ messages in thread
From: Drew Adams @ 2019-11-18 19:22 UTC (permalink / raw)
  To: Mattias Engdegård, Eli Zaretskii; +Cc: 38013

Please don't bind any mouse buttons for
this, by default.

E.g., please don't bind `C-M-(down-)mouse-1'.

In the doc, just refer to the command, not
a pre-imposed binding for it.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-18 19:22                                             ` Drew Adams
@ 2019-11-18 21:29                                               ` Juri Linkov
  2019-11-19  7:57                                                 ` martin rudalics
  0 siblings, 1 reply; 55+ messages in thread
From: Juri Linkov @ 2019-11-18 21:29 UTC (permalink / raw)
  To: Drew Adams; +Cc: Mattias Engdegård, 38013

> please don't bind `C-M-(down-)mouse-1'.

I agree.  We need to use the same keys as in other applications:
`C-down-mouse-1' to select the rectangular region, then move
its current binding of `mouse-buffer-menu' to the context popup menu
bound to `<mouse-3>' like on all other applications.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-18 21:29                                               ` Juri Linkov
@ 2019-11-19  7:57                                                 ` martin rudalics
  2019-11-19 13:57                                                   ` Mattias Engdegård
  2019-11-19 23:07                                                   ` Juri Linkov
  0 siblings, 2 replies; 55+ messages in thread
From: martin rudalics @ 2019-11-19  7:57 UTC (permalink / raw)
  To: Juri Linkov, Drew Adams; +Cc: Mattias Engdegård, 38013

 > I agree.  We need to use the same keys as in other applications:
 > `C-down-mouse-1' to select the rectangular region, then move
 > its current binding of `mouse-buffer-menu' to the context popup menu
 > bound to `<mouse-3>' like on all other applications.

As I tried to explain before: Other applications use 'C-down-mouse-1'
for building non-contiguous regions that do _not_ necessarily form a
rectangle.

martin





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-19  7:57                                                 ` martin rudalics
@ 2019-11-19 13:57                                                   ` Mattias Engdegård
  2019-11-19 15:09                                                     ` Drew Adams
  2019-11-19 23:07                                                   ` Juri Linkov
  1 sibling, 1 reply; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-19 13:57 UTC (permalink / raw)
  To: martin rudalics; +Cc: 38013, Juri Linkov

19 nov. 2019 kl. 08.57 skrev martin rudalics <rudalics@gmx.at>:

> > I agree.  We need to use the same keys as in other applications:
> > `C-down-mouse-1' to select the rectangular region, then move
> > its current binding of `mouse-buffer-menu' to the context popup menu
> > bound to `<mouse-3>' like on all other applications.
> 
> As I tried to explain before: Other applications use 'C-down-mouse-1'
> for building non-contiguous regions that do _not_ necessarily form a
> rectangle.

You are both right, and I, too, would prefer a better modifier than control-meta.
Platform conventions vary, although right-button is clearly dominant for context menus today. There is no similarly agreed way to select rectangles of text.

Nevertheless, I would like this patch to be pushed as long as there is no objection to the design and implementation of the feature itself. It uses nobody's favourite binding, but at least the feature is accessible in a useful way. With it in place, we can argue about shuffling bindings around.






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-19 13:57                                                   ` Mattias Engdegård
@ 2019-11-19 15:09                                                     ` Drew Adams
  2019-11-19 15:37                                                       ` Mattias Engdegård
  0 siblings, 1 reply; 55+ messages in thread
From: Drew Adams @ 2019-11-19 15:09 UTC (permalink / raw)
  To: Mattias Engdegård, martin rudalics; +Cc: 38013, Juri Linkov

> You are both right, and I, too, would prefer a better modifier than
> control-meta.
> Platform conventions vary, although right-button is clearly dominant
> for context menus today. There is no similarly agreed way to select
> rectangles of text.
> 
> Nevertheless, I would like this patch to be pushed as long as there is
> no objection to the design and implementation of the feature itself.

The feature itself does not include imposing a
binding by default.  The feature is not the problem.

> It uses nobody's favourite binding, but at least
> the feature is accessible in a useful way.

The feature is accessible without a default binding.

> With it in place, we can argue about shuffling
> bindings around.

No.  We should argue, if that's needed, only after
the feature has been used by users for quite a while
and users have called for a default binding.

Please do not bind this feature by default at all.
Users can bind it as they see fit.

This is a new feature.  Binding can be considered
after a (hopefully long) period of use and experimentation.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-19 15:09                                                     ` Drew Adams
@ 2019-11-19 15:37                                                       ` Mattias Engdegård
  2019-11-19 16:08                                                         ` Drew Adams
  0 siblings, 1 reply; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-19 15:37 UTC (permalink / raw)
  To: Drew Adams; +Cc: 38013, Juri Linkov

19 nov. 2019 kl. 16.09 skrev Drew Adams <drew.adams@oracle.com>:

> No.  We should argue, if that's needed, only after
> the feature has been used by users for quite a while
> and users have called for a default binding.

Of course rectangular selection should have a binding by default. This is not controversial in the slightest.






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-19 15:37                                                       ` Mattias Engdegård
@ 2019-11-19 16:08                                                         ` Drew Adams
  2019-11-19 16:26                                                           ` Mattias Engdegård
  2019-11-19 17:30                                                           ` Eli Zaretskii
  0 siblings, 2 replies; 55+ messages in thread
From: Drew Adams @ 2019-11-19 16:08 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013, Juri Linkov

> > No.  We should argue, if that's needed, only after
> > the feature has been used by users for quite a while
> > and users have called for a default binding.
> 
> Of course rectangular selection should have a binding by default. This
> is not controversial in the slightest.

Count me as one user who disagrees that this deserves
a default binding.

Eli suggested defining a minor mode, as does CUA.

That mode could be global, and it could have a default
binding for this, like CUA.  That's the right approach,
IMHO.

When CUA (including CUA rectangle) was introduced, it
wasn't foisted on all Emacs users by imposing its
bindings.  It's coexisted politely in a minor mode.

Lots of users liked CUA and used it.  And eventually
its rectangle selection was introduced outside CUA.

I see no reason why Emacs should precipitously bind
mouse actions to this new feature by default.  Anyone
who wants to use it could just turn on the minor mode
once, and leave it on, getting whatever default
bindings you want for that.

That shouldn't be "controversial in the slightest".





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-19 16:08                                                         ` Drew Adams
@ 2019-11-19 16:26                                                           ` Mattias Engdegård
  2019-11-19 17:30                                                           ` Eli Zaretskii
  1 sibling, 0 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-19 16:26 UTC (permalink / raw)
  To: Drew Adams; +Cc: 38013, Juri Linkov

19 nov. 2019 kl. 17.08 skrev Drew Adams <drew.adams@oracle.com>:

> Count me as one user who disagrees that this deserves
> a default binding.

We'll have to disagree then. A mode is useful when a different set of behaviour is desired, but it's not the case here.






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-19 16:08                                                         ` Drew Adams
  2019-11-19 16:26                                                           ` Mattias Engdegård
@ 2019-11-19 17:30                                                           ` Eli Zaretskii
  2019-11-20 22:38                                                             ` Juri Linkov
  1 sibling, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2019-11-19 17:30 UTC (permalink / raw)
  To: Drew Adams; +Cc: mattiase, 38013, juri

> Date: Tue, 19 Nov 2019 08:08:32 -0800 (PST)
> From: Drew Adams <drew.adams@oracle.com>
> Cc: 38013@debbugs.gnu.org, Juri Linkov <juri@linkov.net>
> 
> > Of course rectangular selection should have a binding by default. This
> > is not controversial in the slightest.
> 
> Count me as one user who disagrees that this deserves
> a default binding.

A command that needs to drag the mouse makes no sense without a
binding to some mouse gesture.

> Eli suggested defining a minor mode, as does CUA.

I suggested a minor mode as a way to allow us using the same binding
as used for another command by default.  I did NOT suggest to have a
minor mode _instead_ of a binding.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
       [not found]                                                     ` <<83lfsb22pb.fsf@gnu.org>
@ 2019-11-19 18:32                                                       ` Drew Adams
  2019-11-19 19:24                                                         ` Eli Zaretskii
  0 siblings, 1 reply; 55+ messages in thread
From: Drew Adams @ 2019-11-19 18:32 UTC (permalink / raw)
  To: Eli Zaretskii, Drew Adams; +Cc: mattiase, 38013, juri

> > Count me as one user who disagrees that this deserves
> > a default binding.
> 
> A command that needs to drag the mouse makes no sense without a
> binding to some mouse gesture.

That's what we did (and do) with CUA mouse bindings: put
them in a minor mode keymap.

> > Eli suggested defining a minor mode, as does CUA.
> 
> I suggested a minor mode as a way to allow us using the same binding
> as used for another command by default.  I did NOT suggest to have a
> minor mode _instead_ of a binding.

I was (and I thought you were) suggesting putting the
key binding in a minor-mode keymap.  Users can turn
on the (global) mode and get that binding - and leave
the mode on forever, if they like.

So no, I too did not suggest having a minor mode
_instead_ of a key binding.  I had in mind a minor
mode that has its own key bindings.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-19 18:32                                                       ` Drew Adams
@ 2019-11-19 19:24                                                         ` Eli Zaretskii
  0 siblings, 0 replies; 55+ messages in thread
From: Eli Zaretskii @ 2019-11-19 19:24 UTC (permalink / raw)
  To: Drew Adams; +Cc: mattiase, 38013, juri

> Date: Tue, 19 Nov 2019 10:32:49 -0800 (PST)
> From: Drew Adams <drew.adams@oracle.com>
> Cc: mattiase@acm.org, 38013@debbugs.gnu.org, juri@linkov.net
> 
> > I suggested a minor mode as a way to allow us using the same binding
> > as used for another command by default.  I did NOT suggest to have a
> > minor mode _instead_ of a binding.
> 
> I was (and I thought you were) suggesting putting the
> key binding in a minor-mode keymap.  Users can turn
> on the (global) mode and get that binding - and leave
> the mode on forever, if they like.
> 
> So no, I too did not suggest having a minor mode
> _instead_ of a key binding.  I had in mind a minor
> mode that has its own key bindings.

Again, I suggested that only as a way to allow using a mouse gesture
that is already taken today.  If we use another gesture, which isn't
taken today, I see no reason not to bind it by default.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
       [not found]                                                         ` <<83d0dn1xfd.fsf@gnu.org>
@ 2019-11-19 19:34                                                           ` Drew Adams
  2019-11-19 19:48                                                             ` Eli Zaretskii
  0 siblings, 1 reply; 55+ messages in thread
From: Drew Adams @ 2019-11-19 19:34 UTC (permalink / raw)
  To: Eli Zaretskii, Drew Adams; +Cc: mattiase, 38013, juri

> > I was (and I thought you were) suggesting putting the
> > key binding in a minor-mode keymap.  Users can turn
> > on the (global) mode and get that binding - and leave
> > the mode on forever, if they like.
> >
> > So no, I too did not suggest having a minor mode
> > _instead_ of a key binding.  I had in mind a minor
> > mode that has its own key bindings.
> 
> Again, I suggested that only as a way to allow using a mouse gesture
> that is already taken today.  If we use another gesture, which isn't
> taken today, I see no reason not to bind it by default.

OK.  I thought perhaps we agreed, but we don't.

I do see a reason not to bind it globally by
default - the same reason we didn't do that for CUA.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-19 19:34                                                           ` Drew Adams
@ 2019-11-19 19:48                                                             ` Eli Zaretskii
  0 siblings, 0 replies; 55+ messages in thread
From: Eli Zaretskii @ 2019-11-19 19:48 UTC (permalink / raw)
  To: Drew Adams; +Cc: mattiase, 38013, juri

> Date: Tue, 19 Nov 2019 11:34:45 -0800 (PST)
> From: Drew Adams <drew.adams@oracle.com>
> Cc: mattiase@acm.org, 38013@debbugs.gnu.org, juri@linkov.net
> 
> I do see a reason not to bind it globally by
> default - the same reason we didn't do that for CUA.

CUA changed a lot of bindings, so it couldn't be the default.  This is
different: only one command and one binding, so if the binding is not
taken by default, we have nothing to fear, nothing at all.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-19  7:57                                                 ` martin rudalics
  2019-11-19 13:57                                                   ` Mattias Engdegård
@ 2019-11-19 23:07                                                   ` Juri Linkov
  2019-11-20  7:57                                                     ` martin rudalics
  1 sibling, 1 reply; 55+ messages in thread
From: Juri Linkov @ 2019-11-19 23:07 UTC (permalink / raw)
  To: martin rudalics; +Cc: Mattias Engdegård, 38013

>> I agree.  We need to use the same keys as in other applications:
>> `C-down-mouse-1' to select the rectangular region, then move
>> its current binding of `mouse-buffer-menu' to the context popup menu
>> bound to `<mouse-3>' like on all other applications.
>
> As I tried to explain before: Other applications use 'C-down-mouse-1'
> for building non-contiguous regions that do _not_ necessarily form a
> rectangle.

Indeed Emacs could use the same 'C-down-mouse-1' to select non-contiguous
regions.  In fact the Emacs rectangular region is a special case of the
non-contiguous region.  So implementing the non-contiguous region selection
would require just writing a pair of short functions.

Regarding a mouse binding for the rectangular region selection,
maybe 'C-M-down-mouse-1' still would be a good choice after all,
while 'C-down-mouse-1' should be reserved for the more general
non-contiguous region selection.

Another variant is not to bind 'C-M-down-mouse-1', but use just
'mouse-1' after the rectangle selection mode is activated by its
current key sequence 'C-x RET'.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-19 23:07                                                   ` Juri Linkov
@ 2019-11-20  7:57                                                     ` martin rudalics
  0 siblings, 0 replies; 55+ messages in thread
From: martin rudalics @ 2019-11-20  7:57 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Mattias Engdegård, 38013

 > Regarding a mouse binding for the rectangular region selection,
 > maybe 'C-M-down-mouse-1' still would be a good choice after all,
 > while 'C-down-mouse-1' should be reserved for the more general
 > non-contiguous region selection.
 >
 > Another variant is not to bind 'C-M-down-mouse-1', but use just
 > 'mouse-1' after the rectangle selection mode is activated by its
 > current key sequence 'C-x RET'.

We probably should provide both in a customizable way.  I already lack
the ability to reliably move the mouse cursor between characters, so I
have no preference.

martin





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-19 17:30                                                           ` Eli Zaretskii
@ 2019-11-20 22:38                                                             ` Juri Linkov
  0 siblings, 0 replies; 55+ messages in thread
From: Juri Linkov @ 2019-11-20 22:38 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: mattiase, 38013

>> Eli suggested defining a minor mode, as does CUA.
>
> I suggested a minor mode as a way to allow us using the same binding
> as used for another command by default.  I did NOT suggest to have a
> minor mode _instead_ of a binding.

Such minor mode already exists, it's called 'rectangle-mark-mode'
and is enabled by 'C-x SPC'.  It could also have additional bindings
for 'mouse-1' to allow selecting a rectangular region using the mouse.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-18 18:08                                           ` Mattias Engdegård
  2019-11-18 19:22                                             ` Drew Adams
@ 2019-11-23 11:57                                             ` Eli Zaretskii
  2019-11-23 12:46                                               ` Mattias Engdegård
  1 sibling, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2019-11-23 11:57 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

> From: Mattias Engdegård <mattiase@acm.org>
> Date: Mon, 18 Nov 2019 19:08:24 +0100
> Cc: rudalics@gmx.at, 38013@debbugs.gnu.org
> 
> Here is an updated patch that makes the selection work better with characters that aren't a multiple of the standard font width. 

Thanks, a few minor comments:

> +@defvar fine-grained-mouse-movement

I think this variable's name should start with "mouse-".  Like
mouse-fine-grained-movement or something.

> +    (setq fine-grained-mouse-movement t)

What happens if this function signals an error? won't
fine-grained-mouse-movement be left at its non-nil value?





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-23 11:57                                             ` Eli Zaretskii
@ 2019-11-23 12:46                                               ` Mattias Engdegård
  2019-11-23 14:53                                                 ` Eli Zaretskii
  0 siblings, 1 reply; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-23 12:46 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 38013

23 nov. 2019 kl. 12.57 skrev Eli Zaretskii <eliz@gnu.org>:

>> +@defvar fine-grained-mouse-movement
> 
> I think this variable's name should start with "mouse-".  Like
> mouse-fine-grained-movement or something.

True, but since the variable pertains to the 'mouse-movement' event in particular and not to moving the mouse about in general, it is also useful to have the name reflect that relation.
'mouse-movement-fine-grained' is possible but a bit awkward. What about 'mouse-fine-grained-tracking'?

>> +    (setq fine-grained-mouse-movement t)
> 
> What happens if this function signals an error? won't
> fine-grained-mouse-movement be left at its non-nil value?

Good question. Ideally, the variable (and 'track-mouse') would be dynamically bound during the drag. However, since the function, mouse-drag-region-rectangle, returns as the drag commences, this is not possible.

The code follows the pattern of other functions in the same file in that it trusts the exit function of the transient map to be executed eventually, and the first thing done in that exit function is to reset the variables.

All these functions have a small hole between setting the variables and the successful return of set-transient-map, during which an error will not result in the variables being reset. We could wrap the set-transient-map calls in condition-case everywhere, if we think that this would increase robustness. Basically,

(condition-case err
    (set-transient-map ...)
  (error (setq fine-grained-mouse-movement nil)
         (setq track-mouse nil)
         (signal (car err) (cdr err))))

An earlier version of the patch used the 'track-mouse' macro instead, which does not have this problem, but I changed after complaints that it does not permit independent use of the mouse click event. (For instance, if the selection uses M-down-mouse-1 and M-drag-mouse-1, M-mouse-1 could not be used for anything else.) However, I'm not convinced that this would be much of a limitation.

(Some code in mouse.el uses the track-mouse macro: mouse-drag-and-drop-region and mouse-drag-secondary.)






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-23 12:46                                               ` Mattias Engdegård
@ 2019-11-23 14:53                                                 ` Eli Zaretskii
  2019-11-23 15:17                                                   ` Mattias Engdegård
  2019-11-27 14:04                                                   ` Mattias Engdegård
  0 siblings, 2 replies; 55+ messages in thread
From: Eli Zaretskii @ 2019-11-23 14:53 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 38013

> From: Mattias Engdegård <mattiase@acm.org>
> Date: Sat, 23 Nov 2019 13:46:08 +0100
> Cc: rudalics@gmx.at, 38013@debbugs.gnu.org
> 
> > I think this variable's name should start with "mouse-".  Like
> > mouse-fine-grained-movement or something.
> 
> True, but since the variable pertains to the 'mouse-movement' event in particular and not to moving the mouse about in general, it is also useful to have the name reflect that relation.
> 'mouse-movement-fine-grained' is possible but a bit awkward. What about 'mouse-fine-grained-tracking'?

Fine with me.

> The code follows the pattern of other functions in the same file in that it trusts the exit function of the transient map to be executed eventually, and the first thing done in that exit function is to reset the variables.
> 
> All these functions have a small hole between setting the variables and the successful return of set-transient-map, during which an error will not result in the variables being reset. We could wrap the set-transient-map calls in condition-case everywhere, if we think that this would increase robustness. Basically,
> 
> (condition-case err
>     (set-transient-map ...)
>   (error (setq fine-grained-mouse-movement nil)
>          (setq track-mouse nil)
>          (signal (car err) (cdr err))))

I think this would be better.  IME, such small windows eventually
cause strange and hard to debug bugs, so any measures to make the
window smaller or eliminate it are welcome.

Thanks.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-23 14:53                                                 ` Eli Zaretskii
@ 2019-11-23 15:17                                                   ` Mattias Engdegård
  2019-11-27 14:04                                                   ` Mattias Engdegård
  1 sibling, 0 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-23 15:17 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 38013

[-- Attachment #1: Type: text/plain, Size: 452 bytes --]

23 nov. 2019 kl. 15.53 skrev Eli Zaretskii <eliz@gnu.org>:

> Fine with me.

Good, mouse-fine-grained-tracking it is then.

> I think this would be better.  IME, such small windows eventually
> cause strange and hard to debug bugs, so any measures to make the
> window smaller or eliminate it are welcome.

The window has now been shrunk to almost nothing, and condition-case added for good measure. (Old code in mouse.el left untouched.)


[-- Attachment #2: 0001-Mouse-rectangular-region-selection-bug-38013.patch --]
[-- Type: application/octet-stream, Size: 11701 bytes --]

From 528bf08d5dc448cbeff0db67188be5093eec98a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Fri, 25 Oct 2019 11:16:39 +0200
Subject: [PATCH] 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.
---
 doc/emacs/frames.texi     |   4 ++
 doc/emacs/killing.texi    |   3 +
 doc/lispref/commands.texi |   6 ++
 etc/NEWS                  |   3 +
 lisp/mouse.el             | 114 +++++++++++++++++++++++++++++++++++++-
 lisp/rect.el              |   8 ++-
 src/xdisp.c               |  12 ++++
 7 files changed, 147 insertions(+), 3 deletions(-)

diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 091c011fb9..f6c2d23913 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -91,6 +91,10 @@ Mouse Commands
 click position; otherwise, set mark at the current value of point and
 point at the click position.  Save the resulting region in the kill
 ring; on a second click, kill it (@code{mouse-save-then-kill}).
+
+@item C-M-mouse-1
+Activate a rectangular region around the text selected by dragging.
+@xref{Rectangles}.
 @end table
 
 @findex mouse-set-point
diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi
index 80e2868908..ce00cb38a7 100644
--- a/doc/emacs/killing.texi
+++ b/doc/emacs/killing.texi
@@ -732,6 +732,9 @@ Rectangles
 and mark values can be interpreted either as a region or as a
 rectangle, depending on the command that uses them.
 
+  A rectangular region can also be marked using the mouse: click and drag
+@kbd{C-M-mouse-1} from one corner of the rectangle to the opposite.
+
 @table @kbd
 @item C-x r k
 Kill the text of the region-rectangle, saving its contents as the
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 0c848a8025..032f005e9c 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -1661,6 +1661,12 @@ Motion Events
 does not generate events for mere motion of the mouse, and these
 events do not appear.  @xref{Mouse Tracking}.
 
+@defvar mouse-fine-grained-tracking
+When non-@code{nil}, mouse motion events are generated even for very
+small movements.  Otherwise, motion events are not generated as long
+as the mouse cursor remains pointing to the same glyph in the text.
+@end defvar
+
 @node Focus Events
 @subsection Focus Events
 @cindex focus event
diff --git a/etc/NEWS b/etc/NEWS
index ad349b1613..80f0fa5e4e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -585,6 +585,9 @@ region using a given replacement-function in a non-destructive manner
 arguments mitigating performance issues when operating on huge
 buffers.
 
++++
+** Dragging 'C-M-mouse-1' now marks rectangular regions.
+
 +++
 ** The command 'delete-indentation' now operates on the active region.
 If the region is active, the command joins all the lines in the
diff --git a/lisp/mouse.el b/lisp/mouse.el
index c91760a734..e2be8e6ee3 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1045,10 +1045,12 @@ mouse-scroll-min-lines
 of lines specified by this variable."
   :type 'integer)
 
-(defun mouse-scroll-subr (window jump &optional overlay start)
+(defun mouse-scroll-subr (window jump &optional overlay start adjust)
   "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
 If OVERLAY is an overlay, let it stretch from START to the far edge of
 the newly visible text.
+ADJUST, if non-nil, is a function, without arguments, to call after
+setting point.
 Upon exit, point is at the far edge of the newly visible text."
   (cond
    ((and (> jump 0) (< jump mouse-scroll-min-lines))
@@ -1077,6 +1079,8 @@ mouse-scroll-subr
 		   ;; so that we don't mess up the selected window.
 		   (or (eq window (selected-window))
 		       (goto-char opoint))
+                   (when adjust
+                     (funcall adjust))
 		   (sit-for mouse-scroll-delay)))))
     (or (eq window (selected-window))
 	(goto-char opoint))))
@@ -1960,6 +1964,114 @@ secondary-selection-from-region
     (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
 
 \f
+(defun mouse-drag-region-rectangle (start-event)
+  "Set the region to the rectangle that the mouse is dragged over.
+This must be bound to a button-down mouse event."
+  (interactive "e")
+  (let* ((scroll-margin 0)
+         (start-pos (event-start start-event))
+         (start-posn (event-start start-event))
+         (start-point (posn-point start-posn))
+         (start-window (posn-window start-posn))
+         (start-hscroll (window-hscroll start-window))
+         (start-col (+ (car (posn-col-row start-pos)) start-hscroll))
+         (bounds (window-edges start-window))
+         (top (nth 1 bounds))
+         (bottom (if (window-minibuffer-p start-window)
+                     (nth 3 bounds)
+                   (1- (nth 3 bounds))))
+         (dragged nil)
+         (old-track-mouse track-mouse)
+         (old-mouse-fine-grained-tracking mouse-fine-grained-tracking)
+         ;; For right-to-left text, columns are counted from the right margin;
+         ;; translate from mouse events, which always count from the left.
+         (adjusted-col (lambda (col)
+                         (if (eq (current-bidi-paragraph-direction)
+                                 'right-to-left)
+                             (- (frame-text-cols) col -1)
+                           col)))
+         (map (make-sparse-keymap)))
+    (define-key map [switch-frame] #'ignore)
+    (define-key map [select-window] #'ignore)
+    (define-key map [mouse-movement]
+      (lambda (event)
+        (interactive "e")
+        (unless dragged
+          ;; This is actually a drag.
+          (mouse-minibuffer-check start-event)
+          (deactivate-mark)
+          (posn-set-point start-pos)
+          (rectangle-mark-mode)
+          ;; Only tell rectangle about the exact column if we are possibly
+          ;; beyond end-of-line or in a tab, since the column we got from
+          ;; the mouse position isn't necessarily accurate for use in
+          ;; specifying a rectangle (which uses the `move-to-column'
+          ;; measure).
+          (when (or (eolp) (eq (following-char) ?\t))
+            (let ((col (funcall adjusted-col start-col)))
+              (rectangle--col-pos col 'mark)
+              (rectangle--col-pos col 'point)))
+
+          (setq dragged t))
+
+        (let* ((posn (event-end event))
+               (window (posn-window posn))
+               (hscroll (if (window-live-p window)
+                            (window-hscroll window)
+                          0))
+               (mouse-pos (mouse-position))
+               (mouse-col (+ (cadr mouse-pos) hscroll))
+               (mouse-row (cddr mouse-pos))
+               (set-col (lambda ()
+                          (if (or (eolp) (eq (following-char) ?\t))
+                              (rectangle--col-pos
+                               (funcall adjusted-col mouse-col) 'point)
+                            (rectangle--reset-point-crutches)))))
+          (if (and (eq window start-window)
+                   mouse-row
+                   (<= top mouse-row (1- bottom)))
+              ;; Drag inside the same window.
+              (progn
+                (posn-set-point posn)
+                (funcall set-col))
+            ;; Drag outside the window: scroll.
+            (cond
+             ((null mouse-row))
+             ((< mouse-row top)
+              (mouse-scroll-subr
+               start-window (- mouse-row top) nil start-point
+               set-col))
+             ((>= mouse-row bottom)
+              (mouse-scroll-subr
+               start-window (1+ (- mouse-row bottom)) nil start-point
+               set-col)))))))
+    (condition-case err
+        (progn
+          (setq track-mouse t)
+          (setq mouse-fine-grained-tracking t)
+          (set-transient-map
+           map t
+           (lambda ()
+             (setq track-mouse old-track-mouse)
+             (setq mouse-fine-grained-tracking old-mouse-fine-grained-tracking)
+             (when (or (not dragged)
+                       (not (mark))
+                       (equal (rectangle-dimensions (mark) (point)) '(0 . 1)))
+               ;; No nontrivial region selected; deactivate rectangle mode.
+               (deactivate-mark)))))
+      ;; Clean up in case something went wrong.
+      (error (setq track-mouse old-track-mouse)
+             (setq mouse-fine-grained-tracking old-mouse-fine-grained-tracking)
+             (signal (car err) (cdr err))))))
+
+;; The drag event must be bound to something but does not need any effect,
+;; as everything takes place in `mouse-drag-region-rectangle'.
+;; The click event can be anything; `mouse-set-point' is just a convenience.
+(global-set-key [C-M-down-mouse-1] #'mouse-drag-region-rectangle)
+(global-set-key [C-M-drag-mouse-1] #'ignore)
+(global-set-key [C-M-mouse-1]      #'mouse-set-point)
+
+\f
 (defcustom mouse-buffer-menu-maxlen 20
   "Number of buffers in one pane (submenu) of the buffer menu.
 If we have lots of buffers, divide them into groups of
diff --git a/lisp/rect.el b/lisp/rect.el
index 4d4d6146f2..1109786fc5 100644
--- a/lisp/rect.el
+++ b/lisp/rect.el
@@ -133,11 +133,15 @@ rectangle--point-col
 (defun rectangle--crutches ()
   (cons rectangle--mark-crutches
         (window-parameter nil 'rectangle--point-crutches)))
-(defun rectangle--reset-crutches ()
-  (kill-local-variable 'rectangle--mark-crutches)
+
+(defun rectangle--reset-point-crutches ()
   (if (window-parameter nil 'rectangle--point-crutches)
       (setf (window-parameter nil 'rectangle--point-crutches) nil)))
 
+(defun rectangle--reset-crutches ()
+  (kill-local-variable 'rectangle--mark-crutches)
+  (rectangle--reset-point-crutches))
+
 ;;; Rectangle operations.
 
 (defun apply-on-rectangle (function start end &rest args)
diff --git a/src/xdisp.c b/src/xdisp.c
index c5676b3e17..507d055fc9 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)
   enum glyph_row_area area;
   int x, y, width, height;
 
+  if (mouse_fine_grained_tracking)
+    {
+      STORE_NATIVE_RECT (*rect, gx, gy, 1, 1);
+      return;
+    }
+
   /* Try to determine frame pixel position and size of the glyph under
      frame pixel coordinates X/Y on frame F.  */
 
@@ -34943,6 +34949,12 @@ syms_of_xdisp (void)
 may be more familiar to users.  */);
   display_raw_bytes_as_hex = false;
 
+  DEFVAR_BOOL ("mouse-fine-grained-tracking", mouse_fine_grained_tracking,
+    doc: /* Non-nil for pixel-wise mouse-movement.
+When nil, mouse-movement events will not be generated as long as the
+mouse stays within the extent of a single glyph (except for images).  */);
+  mouse_fine_grained_tracking = false;
+
 }
 
 
-- 
2.21.0 (Apple Git-122.2)


^ permalink raw reply related	[flat|nested] 55+ messages in thread

* bug#38013: [PATCH] Rectangular region selection with mouse
  2019-11-23 14:53                                                 ` Eli Zaretskii
  2019-11-23 15:17                                                   ` Mattias Engdegård
@ 2019-11-27 14:04                                                   ` Mattias Engdegård
  1 sibling, 0 replies; 55+ messages in thread
From: Mattias Engdegård @ 2019-11-27 14:04 UTC (permalink / raw)
  To: 38013

It seems that we are done; pushed.
It would still be nice to have a simpler binding.






^ permalink raw reply	[flat|nested] 55+ messages in thread

end of thread, other threads:[~2019-11-27 14:04 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-10-31 21:55 bug#38013: [PATCH] Rectangular region selection with mouse Mattias Engdegård
2019-11-01  0:12 ` Drew Adams
2019-11-01  7:51 ` Eli Zaretskii
2019-11-01 11:53   ` Mattias Engdegård
2019-11-01 13:17     ` Eli Zaretskii
2019-11-01 13:30       ` Eli Zaretskii
2019-11-03 21:12         ` Mattias Engdegård
2019-11-03 21:51           ` Drew Adams
2019-11-04  9:07           ` martin rudalics
2019-11-04 11:33             ` Mattias Engdegård
2019-11-04 15:25               ` Drew Adams
2019-11-04 18:27               ` martin rudalics
2019-11-04 20:18                 ` Mattias Engdegård
2019-11-05  9:35                   ` martin rudalics
2019-11-07 17:48                     ` Mattias Engdegård
2019-11-07 17:53                       ` Drew Adams
2019-11-07 18:27                         ` Mattias Engdegård
2019-11-07 19:08                       ` martin rudalics
2019-11-07 20:46                         ` Drew Adams
2019-11-08 17:33                         ` Mattias Engdegård
2019-11-08 18:28                           ` martin rudalics
2019-11-09 15:35                             ` Mattias Engdegård
2019-11-09 17:54                               ` Eli Zaretskii
2019-11-09 19:32                                 ` Mattias Engdegård
2019-11-09 20:04                                   ` Eli Zaretskii
2019-11-10 13:49                                     ` Mattias Engdegård
2019-11-12 14:26                                       ` Mattias Engdegård
2019-11-12 15:39                                         ` Drew Adams
2019-11-14 13:56                                         ` Mattias Engdegård
2019-11-16 12:35                                       ` Eli Zaretskii
2019-11-17 12:11                                         ` Mattias Engdegård
2019-11-18 18:08                                           ` Mattias Engdegård
2019-11-18 19:22                                             ` Drew Adams
2019-11-18 21:29                                               ` Juri Linkov
2019-11-19  7:57                                                 ` martin rudalics
2019-11-19 13:57                                                   ` Mattias Engdegård
2019-11-19 15:09                                                     ` Drew Adams
2019-11-19 15:37                                                       ` Mattias Engdegård
2019-11-19 16:08                                                         ` Drew Adams
2019-11-19 16:26                                                           ` Mattias Engdegård
2019-11-19 17:30                                                           ` Eli Zaretskii
2019-11-20 22:38                                                             ` Juri Linkov
2019-11-19 23:07                                                   ` Juri Linkov
2019-11-20  7:57                                                     ` martin rudalics
2019-11-23 11:57                                             ` Eli Zaretskii
2019-11-23 12:46                                               ` Mattias Engdegård
2019-11-23 14:53                                                 ` Eli Zaretskii
2019-11-23 15:17                                                   ` Mattias Engdegård
2019-11-27 14:04                                                   ` Mattias Engdegård
2019-11-10  3:48                               ` Richard Stallman
2019-11-01 13:23     ` martin rudalics
     [not found] <<C2CEADBB-4388-45A5-9D4D-8963314B2913@acm.org>
     [not found] ` <<83v9s3lo5f.fsf@gnu.org>
     [not found]   ` <<75EC4FBC-F636-4D75-BAC4-982D85188794@acm.org>
     [not found]     ` <<9b9222ad-ead7-d0a0-0602-780d0680f070@gmx.at>
     [not found]       ` <<DEA04CF5-72AC-4251-B10B-06291BDAECC2@acm.org>
     [not found]         ` <<6bf229f4-c22f-c3c2-5158-5235f908de3c@gmx.at>
     [not found]           ` <<A13CC15C-D255-4A38-B8EA-5FE818BB45D5@acm.org>
     [not found]             ` <<8ec84837-172c-1ce5-cab0-b4c96a86274e@gmx.at>
     [not found]               ` <<411EAB4E-B666-4263-8514-5F47391268B1@acm.org>
     [not found]                 ` <<2df02c1f-fea4-f764-eba6-fd67de581755@gmx.at>
     [not found]                   ` <<B6A6755E-2981-4369-9A6B-A0E752C69A77@acm.org>
     [not found]                     ` <<3b74a108-28e3-fd01-64a5-7c4302e3d979@gmx.at>
     [not found]                       ` <<9A9D13F2-1F4F-4DD4-B92F-96FC4D91DFBD@acm.org>
     [not found]                         ` <<83pni17x5b.fsf@gnu.org>
     [not found]                           ` <<8B95D2D3-8E00-45BF-B57D-EFD49D79EB6A@acm.org>
     [not found]                             ` <<83bltk95p7.fsf@gnu.org>
     [not found]                               ` <<60DD9D65-C3F0-470E-8489-B333E1889D32@acm.org>
     [not found]                                 ` <<83ftio6lsy.fsf@gnu.org>
     [not found]                                   ` <<290E5E66-964B-4E29-B141-166447AD5556@acm.org>
     [not found]                                     ` <<175E5B2E-2256-4FCD-AA8E-9E5BC6DE7907@acm.org>
     [not found]                                       ` <<7d94fa94-94e4-46dc-8df0-c40ccf052ee9@default>
     [not found]                                         ` <<87imngub40.fsf@mail.linkov.net>
     [not found]                                           ` <<60fa6496-c057-b69d-21c1-3b1de85b4b9f@gmx.at>
     [not found]                                             ` <<DE4EC019-FA36-434E-882C-D80192512DDB@acm.org>
     [not found]                                               ` <<9302a9ac-e64c-41ed-898b-24d59465fba4@default>
     [not found]                                                 ` <<EACDBDF2-FB23-475A-BCE9-3447DECBABC8@acm.org>
     [not found]                                                   ` <<ba3f1c42-91a9-4985-9376-6a84196167e8@default>
     [not found]                                                     ` <<83lfsb22pb.fsf@gnu.org>
2019-11-19 18:32                                                       ` Drew Adams
2019-11-19 19:24                                                         ` Eli Zaretskii
     [not found] <<<C2CEADBB-4388-45A5-9D4D-8963314B2913@acm.org>
     [not found] ` <<<83v9s3lo5f.fsf@gnu.org>
     [not found]   ` <<<75EC4FBC-F636-4D75-BAC4-982D85188794@acm.org>
     [not found]     ` <<<9b9222ad-ead7-d0a0-0602-780d0680f070@gmx.at>
     [not found]       ` <<<DEA04CF5-72AC-4251-B10B-06291BDAECC2@acm.org>
     [not found]         ` <<<6bf229f4-c22f-c3c2-5158-5235f908de3c@gmx.at>
     [not found]           ` <<<A13CC15C-D255-4A38-B8EA-5FE818BB45D5@acm.org>
     [not found]             ` <<<8ec84837-172c-1ce5-cab0-b4c96a86274e@gmx.at>
     [not found]               ` <<<411EAB4E-B666-4263-8514-5F47391268B1@acm.org>
     [not found]                 ` <<<2df02c1f-fea4-f764-eba6-fd67de581755@gmx.at>
     [not found]                   ` <<<B6A6755E-2981-4369-9A6B-A0E752C69A77@acm.org>
     [not found]                     ` <<<3b74a108-28e3-fd01-64a5-7c4302e3d979@gmx.at>
     [not found]                       ` <<<9A9D13F2-1F4F-4DD4-B92F-96FC4D91DFBD@acm.org>
     [not found]                         ` <<<83pni17x5b.fsf@gnu.org>
     [not found]                           ` <<<8B95D2D3-8E00-45BF-B57D-EFD49D79EB6A@acm.org>
     [not found]                             ` <<<83bltk95p7.fsf@gnu.org>
     [not found]                               ` <<<60DD9D65-C3F0-470E-8489-B333E1889D32@acm.org>
     [not found]                                 ` <<<83ftio6lsy.fsf@gnu.org>
     [not found]                                   ` <<<290E5E66-964B-4E29-B141-166447AD5556@acm.org>
     [not found]                                     ` <<<175E5B2E-2256-4FCD-AA8E-9E5BC6DE7907@acm.org>
     [not found]                                       ` <<<7d94fa94-94e4-46dc-8df0-c40ccf052ee9@default>
     [not found]                                         ` <<<87imngub40.fsf@mail.linkov.net>
     [not found]                                           ` <<<60fa6496-c057-b69d-21c1-3b1de85b4b9f@gmx.at>
     [not found]                                             ` <<<DE4EC019-FA36-434E-882C-D80192512DDB@acm.org>
     [not found]                                               ` <<<9302a9ac-e64c-41ed-898b-24d59465fba4@default>
     [not found]                                                 ` <<<EACDBDF2-FB23-475A-BCE9-3447DECBABC8@acm.org>
     [not found]                                                   ` <<<ba3f1c42-91a9-4985-9376-6a84196167e8@default>
     [not found]                                                     ` <<<83lfsb22pb.fsf@gnu.org>
     [not found]                                                       ` <<dc319e8e-42b3-4db8-b8d4-1580e6397174@default>
     [not found]                                                         ` <<83d0dn1xfd.fsf@gnu.org>
2019-11-19 19:34                                                           ` Drew Adams
2019-11-19 19:48                                                             ` Eli Zaretskii

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.