Subject: Fwd: bug#47581: 27.1; tab-bar missed mouse clicks on MS-Windows

From: Ioannis Kappas <[email-masked]>
Date: Sun, 4 Apr 2021 20:49:24 +0100

Hi Eli,

On Sat, Apr 3, 2021 at 2:56 PM Eli Zaretskii <[email-masked]> wrote:

>
>
> Thanks, but this doesn't match my observations.
>
> First, I get a much smaller value for "virtual glyph" width: 5, not 9.
> (Did you look at the values in "emacs -Q" or in a session where fonts
> were customized?)
>

Indeed, the "Scale and Layout" on my monitor is set to 175% and thus
the difference. Setting it back to 100% gives a a virtual-glyph width
of 5px as per your correct observation with the following variable
glyph width sizes:

| column no.   |   1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 |
| glyph        | ?\s | ?* | ?s | ?c | ?r | ?a | ?t | ?c | ?h | ?* |
| width (px)   |   4 |  6 |  7 |  7 |  4 |  7 |  4 |  7 |  7 |  5 |
| end pos (px) |   4 | 10 | 17 | 24 | 28 | 35 | 39 | 46 | 53 | 58 |

>
> More importantly, remember_mouse_glyph is not called at all when I
> click on the tab-bar buttons, it is only called when I _move_ the
> mouse.  The decision whether we click on the same glyph or not is
> irrelevant to tab-bar buttons, it only cares if we click on the same
> _button_ as before, and that decision is made in get_tab_bar_item,
> which calls x_y_to_hpos_vpos, and the latter doesn't use any
> approximations of the glyph dimensions, it uses the actual pixel width
> of each glyph on display.
>

Agreed. Though, unless I am mistaken, it appears to me that the
virtual-glyph calculations performed during mouse moves over the
tab-bar, do indirectly affect the calculations during a mouse click.

I copied below a little sketch of how the situation appeared to me
while I was debugging the issue. During a mouse move, the A.1.1
predicate is referencing the virtual-glyph, fixed glyph size, calculation
from FRAME_DISPLAY_INFO's `last_mouse_glyph' done in A.1.1.2.1
and as thus it might not trigger A.1.1.1.1.1 to update MOUSE_HL_INFO when
the mouse moves to a different variable-sized glyph. The MOUSE_HL_INFO
value is later used during a mouse click in B.1.1.1 which, as a
consequence, might miss the tab activation (i.e. B.1.1.1.1 compares
the column returned from src/xdisp.c:x_y_to_hpos_vpos against a
potentially stale MOUSE_HL_INFO's mouse face beg/end col range):

A. src/w32term.c:w32_read_socket / (`WM_MOUSEMOVE' event)
   1. src/w32term.c:w32_note_mouse_movement
      1. Determine whether "Has the mouse moved off the glyph it was
         on at the last sighting?" by checking if the MOUSE_X and
         MOUSE_Y position fall outside the `RECT' of
         src/frame.h:FRAME_DISPLAY_INFO's `last_mouse_glyph'. If so
         1. src/xdisp.c:note_mouse_highlight
            1. src/xdisp.c:note_tab_bar_highlight
               1. sets src/frame.h:MOUSE_HL_INFO's
                  1. `mouse_face_beg_col' to the glyph column under the
mouse
                  2. `mouse_face_end_col' to the next glyph column under
the mouse
         2. Set src/w32term.h:FRAME_DISPLAY_INFO's `last_mouse_glyph'
            to the `RECT' that the glyph under the cursor occupies, by
            calling src/xdisp.c:remember_mouse_glyph:
            1. When it is over the tab-bar, it currently uses the
               `virtual_glyph' method to set RECT, which assumes all
               glyphs on the tab-bar row have a fixed width (sourced
               from src/frame.h:FRAME_SMALLEST_CHAR_WIDTH).
B. src/w32term.c:w32_read_socket / WM_*BUTTON* event
   1. src/w32term.c:w32_handle_tab_bar_click
      1. src/xdispl.c:handle_tab_bar_click
         1. src/xdispl.c:get_tab_bar_item
            1. Returns whether the mouse's X/Y is on the same item that
               was highlighted before. It does that by comparing, among
               other things, whether the column position HPOS returned by
               src/xdisp.c:x_y_to_hpos_vpos falls in the
               src/frame.h:MOUSE_HL_INFO's mouse face beg and end col range.
         2. if the above function indicates that the mouse cursor is
            on the same item that was highlighted before, then it
            activates the tab.

>
> I think the actual problem is elsewhere: in handle_tab_bar_click.  It
> includes code that was copied from handle_tool_bar_click, and which
> pays attention to the value of mouse-highlight.  But tab-bar buttons
> don't behave like tool-bar buttons in this regard: they don't respond
> to moving the mouse pointer to them by "activating" the button.  So I
> think that code should be removed from handle_tab_bar_click.  To wit:
> turn mouse-highlight off (M-x set-variable RET mouse-highlight RET nil
> RET), and clicks on tab-bar buttons miraculously start working with
> 100% reliability.
>

This will indeed also solve the problem by removing the comparison in
B.1.1 which is using the potentially stale
src/frame.h:MOUSE_HL_INFO, which to me seems to be the source of the
problem. And it is an even better solution, since that part of the
code might have been included there only by mistake. Nice catch!

Regardless of this though, assuming the above sketch is correct,
shouldn't we also consider fixing the code in
src/xdisp.c:remember_mouse_glyph so as to set the
src/w32term.h:FRAME_DISPLAY_INFO's `last_mouse_glyph' using
`text-glyph' coordinates, so as for A.1.1 to fire up based on the actual
tab-bar
glyph coordinates during a mouse move (so that MOUSE_HL_INFO does not
contain stale information)? I can't think of a reason why we might want
this to
be set using virtual-glyph coords when over the tab-bar (but then, I can
only see some of
the pieces and not the whole picture as you do).

Thanks!