Subject: bug#71866: 30.0.50; [macOS] Cursor hiding char behind it with certain theme customization

From: Eli Zaretskii <[email-masked]>
Date: Thu, 25 Jul 2024 08:01:31 +0300

> Date: Wed, 24 Jul 2024 22:22:33 +0300
> Cc: [email-masked], [email-masked]
> From: Dmitry Gutov <[email-masked]>
> 
> > Curiouser and curiouser.  And when you say that 's' is a character
> > that is blanked, does it mean that if you have several such
> > characters, then moving the cursor to any of them will show the
> > problem?
> 
> Yes: with buffer contents 'asdasdasdasd' (or any small variations of 
> that), only the 's' chars exhibit the problem with the repro script.
> 
> With my custom init, all of the chars exhibit the problem.
> 
> > I don't understand even in principle how a display problem could be
> > specific to some characters, unless it's something related very
> > strongly to the font that is being used.  So what happens in a session
> > in which 's' is a problematic character if you put a face property on
> > 's' that forces Emacs to use a different font?
> 
> I tried something different: enabled variable-pitch-mode.
> 
> * With the small repro script in the first message, the problem is gone.
> 
> * With my custom init, the problem remains for all chars. *shrug*

OK, so it isn't the font.

The only other explanation is some kind of display-related caching,
somewhere.  One of those is in Emacs: when we decide to redraw some
part of a window, we compute the minimum set of changes that need to
be done on the glass, trying to avoid redrawing what is already there.
Look at dispnew.c:update_text_area -- can you modify its code so that
it always draws the entire screen line?  That is, make the first if
clause:

  /* If rows are at different X or Y, or rows have different height,
     or the current row is marked invalid, write the entire line.  */
  if (!current_row->enabled_p
      || desired_row->y != current_row->y
      || desired_row->ascent != current_row->ascent
      || desired_row->phys_ascent != current_row->phys_ascent
      || desired_row->phys_height != current_row->phys_height
      || desired_row->visible_height != current_row->visible_height
      || current_row->overlapped_p
      /* This next line is necessary for correctly redrawing
	 mouse-face areas after scrolling and other operations.
	 However, it causes excessive flickering when mouse is moved
	 across the mode line.  Luckily, turning it off for the mode
	 line doesn't seem to hurt anything. -- cyd.
         But it is still needed for the header line. -- kfs.
         The header line vpos is 1 if a tab line is enabled.  (18th
         Apr 2022) */
      || (current_row->mouse_face_p
	  && !(current_row->mode_line_p
	       && (vpos > (w->current_matrix->tab_line_p
			   && w->current_matrix->header_line_p))))
      || current_row->x != desired_row->x)

always yield true.  Then see if the problem goes away.

Another redisplay optimization of the same kind is in function
scrolling_window, also in dispnew.c.  I don't think it is being used
in this scenario, but to be sure, change the code in its caller
update_window, so that the condition for its call, viz.:

      /* Try reusing part of the display by copying.  */
      if (row < end && !desired_matrix->no_scrolling_p)

is always false.

I don't think these optimizations are relevant to the situations you
describe, but just in case I'm missing something, please try disabling
them both and see if anything changes.

If disabling those optimizations doesn't help, the only other
hypothesis I can come with is some display wizardry done by your video
driver, whereby it attempts to "optimize" redisplay by redrawing only
parts of the screen.  If your video driver has some customization
features you can control, and if some of those customizations are
named "SOME optimization" or "fast SOMETHING" or anything else to that
effect, try disabling those "optimizations".