bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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


From: Jared Finder
Subject: bug#69915: 30.0.50; mouse-autoselect-window has no effect in terminal
Date: Wed, 27 Mar 2024 14:47:27 -0700

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
has no effect and select-window events are always generated.

Fyi, the can-return-switch-frame parameter is handled at +10838 keyboard.c
in the monstrous over 1000 lines long function read_key_sequence:

          if (EVENT_HAS_PARAMETERS (key)
              /* Either a `switch-frame' or a `select-window' event.  */
              && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)), Qswitch_frame))
            {
              /* If we're at the beginning of a key sequence, and the caller
                 says it's okay, go ahead and return this event.  If we're
                 in the midst of a key sequence, delay it until the end.  */
              if (t > 0 || !can_return_switch_frame)
                {
                  delayed_switch_frame = key;
                  goto replay_key;
                }
            }
But apparently these lines are never executed in the case of the terminal input.

Sadly, read_key_sequence in C code is quite a beast.

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?

> autoselect the mouse window, but ...
> +                (windowp ev-window) ; ignore modeline, tab-bar,
> menu-bar and so forth ...
> +                ;;(not (posn-area (event-start event))) ; also
> ignore, if not inside of text area of window ...
> +                (not (eq ev-window last-window)) ; but only, if mouse
> is over new window ...
> +                (not (eq ev-window (selected-window)))) ; which is
> different from the selected window
> Looking at xterm.c, I think you also want a test against window-minibuffer-p.

On the other hand, looking at msdos.c, there is no test against the minibuffer. I believed, that the selection of the minibuffer is taken care of at +10638 of window.el. In my tests the patch behaves exactly like the documentation, quote: "Mouse auto-selection selects the minibuffer window only if it is active, and never deselects the active minibuffer window."
I added the test, but commented it out.

I'm not sure what the right way to proceed here is then. Eli, can you give advice?

Looking at different OS files that handle mouse_autoselect_window, I see the following state for checks if the selected window is a minibuffer with MINI_WINDOW_P:

pgtkterm.c: checks
w32term.c: does NOT check
w32inevt.c: does NOT check
nsterm.m: checks
xterm.c: checks
msdos.c: does NOT check
haikuterm.c: checks
androidterm.c: checks
term.c: no support for mouse-autoselect-window. :(

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 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.

> +           (progn
> +             (put 'select-window 'event-kind 'switch-frame)
> +             (setf (car event) 'select-window)
> +             vec)
> I think this should be an event that's just select-window and the window, to 
line up with what the select-window event looks like on other platforms (I tested 
PGTK and Windows terminal).  You can verify this by running M-x trace-function RET 
handle-select-window RET.
> That would instead be something like:
> (progn
  (put 'select-window 'event-kind 'switch-frame)
  (vector `(select-window (,ev-window)))

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.

Please find below the next iteration of the patch.

Assuming above comments are addressed, this looks good to me. I imagine there will be minor comment reformatting to avoid going beyond 80 columns.

diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
index 081b8f32456..88c6c28b293 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,16 @@ 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.
-          []))
+ (cond ((and mouse-autoselect-window ; after mouse movement autoselect the mouse window, but ... + (windowp ev-window) ; ignore modeline, tab-bar, menu-bar and so forth ... + ;;(not (posn-area (event-start event))) ; also ignore, if not inside of text area of window ... + ;;(not (window-minibuffer-p (selected-window))) ; and don't deselect the minibuffer + (not (eq ev-window last-window)) ; and select only, if mouse is over a new window ... + (not (eq ev-window (selected-window)))) ; which is different from the selected window
+              (put 'select-window 'event-kind 'switch-frame)
+              (vector `(select-window (,ev-window))))
+              (track-mouse vec)
+              (t [])))
        (t
        (let* ((down (terminal-parameter nil 'xterm-mouse-last-down))
               (down-data (nth 1 down))





reply via email to

[Prev in Thread] Current Thread [Next in Thread]