Subject: bug#42406: Mouse-wheel scrolling can be flickering

From: Stefan Monnier <[email-masked]>
Date: Thu, 17 Dec 2020 15:35:27 -0500

> I just tried to test my proposed patch to see if it breaks this feature,
> and it turns out that it's very definitely unusual: I don't know if it's
> supposed to be supported, but at least I can say that it doesn't work ;-)
>
> At least:
>
>     emacs -Q --eval '(setq frame-title-format "(%l,%c)")'
>
> shows me "(,)" as the frame title with the code in `master` as well as
> with Emacs-25 and Emacs-27.

Hmm... so I cooked up the patch below which should solve the original
performance problem, hopefully without introducing any regression, but
while testing it I saw that %p *does* work in frame's titles, so
scrolling can indeed affect the frame-title.

This also means that the patch below should fail sometimes to update the
%p in the frame title, yet I couldn't make it fail :-(

I must be missing something.

I tried

    emacs -Q --eval '(setq frame-title-format "(%l,%c,%p,%I)")' lisp/subr.el

and then scrolling the buffer with `C-v`: frame-title properly updated.
Then I tried to `C-x 5 2` and then `C-M-v` to scroll the window in the
other frame than the selected one: frame-title properly properly updated
as well!

So, now I'm wondering where is the code that causes the frame title to
be (properly) refreshed in my tests!

        Stefan

diff --git a/src/window.c b/src/window.c
index bcc989b5a7..d73289764d 100644
--- a/src/window.c
+++ b/src/window.c
@@ -215,16 +215,25 @@ wset_combination (struct window *w, bool horflag, Lisp_Object val)
     w->horizontal = horflag;
 }
 
+/* Notify that the window's mode line may need to be updated.
+   If AND_FRAME is false, it means that contrary to the window's mode-line,
+   the frame's title can't be affected.  This can be the case because
+   %l and %c don't work in frame titles (i.e. only the window's point
+   has changed).  */
 static void
-wset_update_mode_line (struct window *w)
+wset_update_mode_line (struct window *w, bool and_frame)
 {
   /* If this window is the selected window on its frame, set the
      global variable update_mode_lines, so that gui_consider_frame_title
      will consider this frame's title for redisplay.  */
   Lisp_Object fselected_window = XFRAME (WINDOW_FRAME (w))->selected_window;
 
-  if (WINDOWP (fselected_window) && XWINDOW (fselected_window) == w)
-    update_mode_lines = 42;
+  if (and_frame
+        && WINDOWP (fselected_window) && XWINDOW (fselected_window) == w)
+    {
+      update_mode_lines = 2;
+      fset_redisplay (XFRAME (WINDOW_FRAME (w)));
+    }
   else
     w->update_mode_line = true;
 }
@@ -1847,7 +1856,7 @@ DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
   w->start_at_line_beg = false;
   if (NILP (noforce))
     w->force_start = true;
-  wset_update_mode_line (w);
+  wset_update_mode_line (w, false);
   /* Bug#15957.  */
   w->window_end_valid = false;
   wset_redisplay (w);
@@ -4008,7 +4017,7 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
     }
 
   wset_redisplay (w);
-  wset_update_mode_line (w);
+  wset_update_mode_line (w, true);
 
   /* We must select BUFFER to run the window-scroll-functions and to look up
      the buffer-local value of Vwindow_point_insertion_type.  */
@@ -5627,7 +5636,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
 		  set_marker_restricted (w->start, make_fixnum (spos),
 					 w->contents);
 		  w->start_at_line_beg = true;
-		  wset_update_mode_line (w);
+		  wset_update_mode_line (w, false);
 		  /* Set force_start so that redisplay_window will run the
 		     window-scroll-functions.  */
 		  w->force_start = true;
@@ -5812,7 +5821,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
 				  IT_BYTEPOS (it));
       bytepos = marker_byte_position (w->start);
       w->start_at_line_beg = (pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n');
-      wset_update_mode_line (w);
+      wset_update_mode_line (w, false);
       /* Set force_start so that redisplay_window will run the
 	 window-scroll-functions.  */
       w->force_start = true;
@@ -6072,7 +6081,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror)
 
       set_marker_restricted_both (w->start, w->contents, pos, pos_byte);
       w->start_at_line_beg = !NILP (bolp);
-      wset_update_mode_line (w);
+      wset_update_mode_line (w, false);
       /* Set force_start so that redisplay_window will run
 	 the window-scroll-functions.  */
       w->force_start = true;