Subject: bug#69915: 30.0.50; mouse-autoselect-window has no effect in terminal

From: Olaf Rogalsky <[email-masked]>
Date: Sat, 30 Mar 2024 18:03:37 +0100

Hi Jared and Eli,

Jared Finder <[email-masked]> writes:
> On 2024-03-26 16:50, Olaf Rogalsky wrote:
>> Hi Jared,
>> 
>>> >> <select-window> events shouldn't be generated while the mouse is being
>>> >> dragged. This probably is reflected in fully by track-mouse, but I'd
>>> >> suggest looking at the native code that generates the event to confirm.
>>> > Truly understanding xterm.c unfortunately is beyond my expertise. Nevertheless I
>>> > tested, the behavior. Dragging the mouse from one window to the next
>>> > (while passing over
>>> > the modeline) gives the following sequence of events:
> ... elided comments ...
>>> > Can't follow you here. At which occasion two events might be generated
>>> > and which ones?
>>> > I was thinking that if both a mouse movement and select window
>>> > event should both be returned, like if track-mouse is non-nil and
>>> > you switch windows.  Can you test this case?
>> Test case 1:
>> (track-mouse
>>   (setq mouse-autoselect-window t)
>>   (let (e)
>>     (while (not (eq e ?q))
>>       (setq e (read-key))
>>       (when (and (consp e) (symbolp (car e)))
>>           (message "%s to %s at posn %s" (car e) (caadr e) (posn-x-y
>> (cadr e)))))))
>> Result with patched terminal:
> ... elided results ...
>> For the second test case I use read-key-sequence instead of read-key
>> Test case 2:
>> (track-mouse
>>   (let ((can-return-switch-frame t) e)
>>     (while (not (equal e "q"))
>>       (setq e (read-key-sequence nil nil t can-return-switch-frame
>> nil))
>>       (when (not (stringp e))
>>           (setq e (seq-elt e 0))
>>           (message "%s to %s at posn %s" (car e) (caadr e) (posn-x-y
>> (cadr e)))))))
>> Result with patched terminal:
> ... elided results ...
>> So, read-key behaves differently in the terminal compared to X11:
>> In the terminal, the can-return-switch-frame parameter of
>> read-key-sequence
...
>> But apparently these lines are never executed in the case of the
>> terminal input.
...
> One last experiment is worth trying here.  If this doesn't work out, I
> think a FIXME will be sufficient.  Instead of returning the
> <select-window> event, try pushing the <select-window> event onto
> unread-command-events.  My thought is that this will let native code
> dequeue and handle the event normally, including taking
> can_return_switch_frame into account.  Can you please try this?

Good idea, this solved the inconsistency.

> Looking at xterm.c, I think you also want a test against
> window-minibuffer-p.
...
> My gut is to assume that the X and GTK behavior is most likely to be 
> better tested and more correct, but I defer to Eli here.
>> I tend to agree.  But, just to be sure, can you or Olaf describe the
>> exact issue and how it could happen, and perhaps show a recipe to try
>> reproducing it?  I'd like to take a closer look at the relevant code.

Jared alreaddy answered your question. I added the test against the
minibuffer, like xterm.c and pgtkterm.c do.

>>> I also commented out a condition, which ensures that the selection of a 
>>> window can only occur, if the mouse is in the text area of the window. 
>>> This matches the following sentence of the documentation:
>>> "In either case, the mouse pointer must enter the text area of a window 
>>> in order to trigger its selection."
>>> But I found no situation, where it did matter and msdos.c didn't have 
>>> that test, either. WDYT?
>> I think the documentation is incorrect and this commented out case
>> should be removed.  Local testing on PGTK and Mac shows that the mouse
>> pointer can be over the window dividers, widget scroll bars, or
>> fringes and still have autoselect behavior activate.
> Is this at all relevant for TTY frames?  Everything is "text area" on
> TTY frames, right?  If not, what are the use cases where the mouse
> would be "not in the text area" on a TTY frame, in the context of
> auto-selecting a window?

I interpreted the phrase "text area" as those parts of the frame, which
show the contents of buffers, i.e. without modeline, window separators,
tab-bar, menu-bar. In other words, anything where posn-area returns nil.

Nevertheless, since no other backend checks for the text area, I removed
the out-commented test.

>> I can't find the documentation of the format of the select-window
>> event. Maybe its a good idea to add it.
> Agreed.  I think it should be added to Focus Events in commands.texi.

But probaly by someone who knows the texi format and has a better
command of the english language than I do. Sorry.

Olaf

PS: sorry for the horrible formatting of the previous messages: I
usually do not use my gmail account ... Hope, this one comes out better.

>From 8de818075ff5e583e25d4f408b9333fac2c37a3c Mon Sep 17 00:00:00 2001
From: Olaf Rogalsky <[email-masked]>
Date: Sat, 30 Mar 2024 17:00:51 +0100
Subject: [PATCH] Fix user option mouse-autoselect-window for tty emacs

Generate select-window events, so that mouse-autoselect-window takes
effect in tty emacs, when xterm-mouse-mode is enabled (Bug#69915).
* lisp/xt-mouse.el (xterm-mouse-translate-1):
If mouse-autoselect-window is non-nil, add select-window events to
unread-command-events.
---
 lisp/xt-mouse.el | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
index 081b8f32456..783718b4ba4 100644
--- a/lisp/xt-mouse.el
+++ b/lisp/xt-mouse.el
@@ -60,7 +60,9 @@ xterm-mouse-translate-1
     (let* ((event (xterm-mouse-event extension))
 	   (ev-command (nth 0 event))
 	   (ev-data    (nth 1 event))
+	   (ev-window  (nth 0 ev-data))
 	   (ev-where   (nth 1 ev-data))
+	   (last-window (terminal-parameter nil 'xterm-mouse-last-window))
 	   (vec (vector event))
 	   (is-move (eq 'mouse-movement ev-command))
 	   (is-down (string-match "down-" (symbol-name ev-command))))
@@ -73,6 +75,9 @@ xterm-mouse-translate-1
                                 'mouse-movement
                               'mouse-click)))
 
+      ;; remember window of current mouse position
+      (set-terminal-parameter nil 'xterm-mouse-last-window ev-window)
+
       (cond
        ((null event) nil)		;Unknown/bogus byte sequence!
        (is-down
@@ -84,10 +89,22 @@ xterm-mouse-translate-1
 	vec)
        (is-move
         (xterm-mouse--handle-mouse-movement)
-        (if track-mouse vec
-          ;; Mouse movement events are currently supposed to be
-          ;; suppressed.  Return no event.
-          []))
+        ;; after mouse movement autoselect the mouse window, but ...
+	(cond ((and mouse-autoselect-window
+                    ;; ignore modeline, tab-bar, menu-bar and so forth ...
+		    (windowp ev-window)
+                    ;; and don't deselect the minibuffer ...
+                    (not (window-minibuffer-p (selected-window)))
+                    ;; and select only, if mouse is over a new window ...
+                    (not (eq ev-window last-window))
+                    ;; which is different from the selected window
+		    (not (eq ev-window (selected-window))))
+	       (put 'select-window 'event-kind 'switch-frame)
+	       (push `(select-window (,ev-window)) unread-command-events)
+               [])
+	       ;;(vector `(select-window (,ev-window))))
+              (track-mouse vec)
+              (t [])))
        (t
 	(let* ((down (terminal-parameter nil 'xterm-mouse-last-down))
 	       (down-data (nth 1 down))