Subject: Re: bug#38828: 26.3; Customized mode line breaks height of vertical scroll bar

From: Eli Zaretskii <[email-masked]>
Date: Thu, 02 Jan 2020 16:15:13 +0200

> Cc: [email-masked]
> From: martin rudalics <[email-masked]>
> Date: Wed, 1 Jan 2020 18:49:30 +0100
> 
>  > and the fallback is the same
>  > estimate_mode_line_height which doesn't support non-character display
>  > elements.  It is generally okay to use WINDOW_BOX_TEXT_HEIGHT in
>  > window.c,
> 
> window.c doesn't use it.  It's used in xdisp.c only.  And I'm sure it
> can return negative values, sometimes.  So I presume we can do away
> with it then?

I think we could.  But I'd rather not do that on the emacs-27 branch,
not unless we find situations where it actually causes bugs.

>  > Eventually, a simpler solution is just to fall back
>  > to the window's mode_line_height field, before falling back to
>  > estimate_mode_line_height, because when the mode-line height changes,
>  > we schedule an immediate thorough redisplay of the window, and
>  > invalidate that window's mode_line_height field, to be recomputed by
>  > the rescheduled redisplay.  See the proposed patch below.
> 
> This fails here when loading the attached test-popup-2.el and typing,
> for example, F2 <up> F3 <up> F2 <up>.

There's more than one problem here (didn't you wonder why pressing F3
doesn't immediately redraw the mode line?).  A more thorough patch is
below.  The dispnew.c part is semi-cleanup: it isn't strictly needed
after the changes in window_box_height, although originally that flag
not being reset upon window resizing was exactly the root cause for
the problem after "F2 up".  But I don't like the idea of this flag
remaining set, even if no one should be looking at it.  Hmm... maybe I
should reset the flag even if we did reallocate current_matrix...

diff --git a/lisp/frame.el b/lisp/frame.el
index c533e5a23f..16ee7580f8 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -2725,6 +2725,9 @@ 'automatic-hscrolling
         line-prefix
         wrap-prefix
         truncate-lines
+        mode-line-format
+        header-line-format
+        tab-line-format
         display-line-numbers
         display-line-numbers-width
         display-line-numbers-current-absolute
diff --git a/src/dispnew.c b/src/dispnew.c
index b2a257090c..8fe72df7ed 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -534,6 +534,13 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
       eassert (left >= 0 && right >= 0);
       matrix->left_margin_glyphs = left;
       matrix->right_margin_glyphs = right;
+
+      /* If we are resizing a window without allocating new rows, make
+	 sure the previous mode-line row of the window's current
+	 matrix is no longer marked as such.  */
+      if (w && matrix == w->current_matrix
+	  && dim.height != matrix->nrows && !new_rows)
+	MATRIX_MODE_LINE_ROW (matrix)->mode_line_p = false;
     }
 
   /* Number of rows to be used by MATRIX.  */
diff --git a/src/xdisp.c b/src/xdisp.c
index 6b677b63ae..4856a7b13b 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -1093,44 +1093,59 @@ window_box_height (struct window *w)
 
   /* Note: the code below that determines the mode-line/header-line/tab-line
      height is essentially the same as that contained in the macro
-     CURRENT_{MODE,HEADER}_LINE_HEIGHT, except that it checks whether
-     the appropriate glyph row has its `mode_line_p' flag set,
-     and if it doesn't, uses estimate_mode_line_height instead.  */
+     CURRENT_{MODE,HEADER,TAB}_LINE_HEIGHT, except that it checks whether
+     the appropriate glyph row has its `mode_line_p' flag set, and if
+     it doesn't, uses estimate_mode_line_height instead.  */
 
   if (window_wants_mode_line (w))
     {
-      struct glyph_row *ml_row
-	= (w->current_matrix && w->current_matrix->rows
-	   ? MATRIX_MODE_LINE_ROW (w->current_matrix)
-	   : 0);
-      if (ml_row && ml_row->mode_line_p)
-	height -= ml_row->height;
+      if (w->mode_line_height >= 0)
+	height -= w->mode_line_height;
       else
-	height -= estimate_mode_line_height (f, CURRENT_MODE_LINE_FACE_ID (w));
+	{
+	  struct glyph_row *ml_row
+	    = (w->current_matrix && w->current_matrix->rows
+	       ? MATRIX_MODE_LINE_ROW (w->current_matrix)
+	       : 0);
+	  if (ml_row && ml_row->mode_line_p)
+	    height -= ml_row->height;
+	  else
+	    height -= estimate_mode_line_height (f,
+						 CURRENT_MODE_LINE_FACE_ID (w));
+	}
     }
 
   if (window_wants_tab_line (w))
     {
-      struct glyph_row *tl_row
-	= (w->current_matrix && w->current_matrix->rows
-	   ? MATRIX_TAB_LINE_ROW (w->current_matrix)
-	   : 0);
-      if (tl_row && tl_row->mode_line_p)
-	height -= tl_row->height;
+      if (w->tab_line_height >= 0)
+	height -= w->tab_line_height;
       else
-	height -= estimate_mode_line_height (f, TAB_LINE_FACE_ID);
+	{
+	  struct glyph_row *tl_row
+	    = (w->current_matrix && w->current_matrix->rows
+	       ? MATRIX_TAB_LINE_ROW (w->current_matrix)
+	       : 0);
+	  if (tl_row && tl_row->mode_line_p)
+	    height -= tl_row->height;
+	  else
+	    height -= estimate_mode_line_height (f, TAB_LINE_FACE_ID);
+	}
     }
 
   if (window_wants_header_line (w))
     {
-      struct glyph_row *hl_row
-	= (w->current_matrix && w->current_matrix->rows
-	   ? MATRIX_HEADER_LINE_ROW (w->current_matrix)
-	   : 0);
-      if (hl_row && hl_row->mode_line_p)
-	height -= hl_row->height;
-      else
-	height -= estimate_mode_line_height (f, HEADER_LINE_FACE_ID);
+      if (w->header_line_height >= 0)
+	height -= w->header_line_height;
+      {
+	struct glyph_row *hl_row
+	  = (w->current_matrix && w->current_matrix->rows
+	     ? MATRIX_HEADER_LINE_ROW (w->current_matrix)
+	     : 0);
+	if (hl_row && hl_row->mode_line_p)
+	  height -= hl_row->height;
+	else
+	  height -= estimate_mode_line_height (f, HEADER_LINE_FACE_ID);
+      }
     }
 
   /* With a very small font and a mode-line that's taller than