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

From: Eli Zaretskii <[email-masked]>
Date: Sat, 03 Apr 2021 16:56:35 +0300

> From: Ioannis Kappas <[email-masked]>
> Date: Sat, 3 Apr 2021 12:26:53 +0100
> 
> The issue appears to be due to the wrong calculation performed by the
> src/xdisp.c:remember_mouse_glyph fn to identify the RECTangle location
> of the glyph under the mouse cursor, when the mouse is over a tab.
> 
> The fn calls src/windows.c:window_from_coordinates to retrieve the
> window where the mouse is over, but this returns nil, resulting to a
> `virtual_glyph' position calculation, which appears to dictate that
> glyphs are fixed width having their width and height equal to the
> smallest char width and font height of the frame respectively.
> 
> But the tab bar glyphs are of variable size, and thus the glyph
> position rectangle returned by the above function will not necessarily
> correspond to the actual position of the glyph under the mouse cursor.
> 
> Consider the following example of glyph position in a tab-bar with a
> single *scratch* tab on MS-Windows. The src/xdisp.c:x_y_to_hpos_vpos
> fn used elsewhere in the tab logic correctly calculates the column
> HPOS as per below (e.g. the ?t glyph corresponds to column no. 7, it
> is 6px wide and occupies pixels 61 to 67 in the tab row):
> 
> | column no.   |   1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 |  10 |
> | glyph        | ?\s | ?* | ?s | ?c | ?r | ?a | ?t | ?c | ?h |  ?* |
> | width (px)   |   6 | 10 | 12 | 12 |  8 | 13 |  6 | 12 | 12 |   9 |
> | end pos (px) |   6 | 16 | 28 | 40 | 48 | 61 | 67 | 79 | 91 | 100 |
> 
> and the corresponding glyph positions returned by the
> src/xdisp.c:remember_mouse_glyph fn RECT on windows 10 (the fixed
> width of a glyph is 9px wide):
> 
> | column no.   |   1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 |  10 |
> | glyph        | ?\s | ?* | ?s | ?c | ?r | ?a | ?t | ?c | ?h |  ?* |
> | width (px)   |   9 |  9 |  9 |  9 |  9 |  9 |  9 |  9 |  9 |   9 |
> | end pos (px) |   9 | 18 | 27 | 36 | 45 | 54 | 63 | 82 | 91 | 100 |
> 
> The above miscalculation is used by
> src/w32term.c:w32_note_mouse_movement, to check if the mouse has moved
> over the last glyph and thus update the last glyph position
> accordingly. However, because the last glyph position check is based
> on the glyph coordinates performed by src/xdisp.c:remember_mouse_glyph
> `virtual_glyph' method, the glyph position does not correspond to the
> actual tab glyph, and updates can be missed.

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?)

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.

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.

Juri, why is that code present in handle_tab_bar_click?  Is that just
a copy/paste from handle_tool_bar_click, or is there some reason for
that?  I'm talking about this logic, and the comments which describe
it, in handle_tab_bar_click:

  /* If not on the highlighted tab-bar item, and mouse-highlight is
     non-nil, return.  This is so we generate the tab-bar button
     click only when the mouse button is released on the same item as
     where it was pressed.  However, when mouse-highlight is disabled,
     generate the click when the button is released regardless of the
     highlight, since tab-bar items are not highlighted in that
     case.  */
  frame_to_window_pixel_xy (w, &x, &y);
  ts = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p);
  if (ts == -1
      || (ts != 0 && !NILP (Vmouse_highlight)))
    return;

  /* When mouse-highlight is off, generate the click for the item
     where the button was pressed, disregarding where it was
     released.  */
  if (NILP (Vmouse_highlight) && !down_p)
    prop_idx = f->last_tab_bar_item;