Subject: Re: bug#38181: Actual height of mode-line not taken into account

From: Carlos Pita <[email-masked]>
Date: Sat, 16 Oct 2021 08:23:15 -0300

Hi Martin,

>>> Does  2. redisplay fit redisplay fit ... fail?

>> As far as I can see this works,

> What is "this" here?

Well, it is "that" there :). "redisplay fit redisplay fit ..." works just fine.
Details below.

> I'm currently not even sure what we are comparing here.

Let's see. I run emacs -q. Then:

(window-mode-line-height) -> 14
(fit-window-to-buffer)
(window-mode-line-height) -> 14

(set-face-attribute 'mode-line nil :height 250)
(set-face-attribute 'mode-line-inactive nil :height 250)
(window-mode-line-height) -> 29
(fit-window-to-buffer)
(window-mode-line-height) -> 29

(setq-default mode-line-format ...) ; full version in Jonas' post
(window-mode-line-height) -> 60
(fit-window-to-buffer)
(window-mode-line-height) -> 60
(redisplay t)
(window-mode-line-height) -> 60
(fit-window-to-buffer)
(window-mode-line-height) -> 60
(redisplay t)
(window-mode-line-height) -> 60
etc

This is not actually very interesting nor informative. The numbers are
fine, but it's always the same window and I guess I'm never in that
instant when fit-window-to-buffer runs before some calculations it
requires have taken place.

Now, let's define test-popup-no-redisplay as the version of test-popup
with the call to redisplay removed, and test-popup-redisplay as the
version that calls redisplay before fitting the window to its buffer:

(test-popup-no-redisplay) -> cropped content
close popup
(test-popup-no-redisplay) -> cropped content
close popup
(test-popup-redisplay) -> ok
close popup
(test-popup-redisplay) -> ok
close popup
(test-popup-no-redisplay) -> cropped content
close popup

As you can see, the redisplay only "fixes" the next fit, after that the
problem reappears.

This may be of interest:

(test-popup-no-redisplay) -> cropped content
(test-popup-no-redisplay) -> ok
(test-popup-no-redisplay) -> ok
(test-popup-no-redisplay) -> ok

(N.B. I'm not closing the popup) It seems like the window was reused
and the second time it got things right.

My interpretation is that the early redisplay "prepares" the current
window for the fit. Now, the workaround that I linked above does a
redisplay once per buffer, not once per window. The issue I observe,
which I believe is the same one that motivated this report in the
first place, is an org-set-tags-command menu clipped at the bottom
(it's not the only case, though). Since the popup windows that
org-mode opens for this and other menus are transient but their
buffers likely remain hidden, that may be the reason why the
workaround is not, well, working around. What I'm failing to grasp is
how could it ever work... maybe there was some change in the
implementation of org-mode popups.

I would be happy with a sound statement like "if you change the
modeline height so it is different to the default char size, you need
to call redisplay for each window that sports the modified modeline
before executing any operation that requires knowledge of the geometry
of that modeline, including fit-window-to-buffer". If that's true then the
current trick could be reasonably modified to cope with every possible
case instead of hooking to particular functions (fit-window-to-buffer) in
maybe the wrong scope (buffer), by just triggering an early redisplay
each time a new window is created.

Rereading (some of) the above thread, I noticed you said:

> If we don't want 'fit-window-to-buffer' to do that always we'd need
> some variable, either buffer local or even a window parameter, that
> 'fit-window-to-buffer' would inspect once and reset immediately in
> order to perform only the redisplay call that's really needed.

I believe this is similar to what I've just suggested. Then a long
discussion full of technicalities that I won't be able to follow in
depth anytime soon took place. I understand that maybe forcing an
early display is not ideal because, in principle, we only want to
update the size of the modeline, not prematurely redisplay the window.
Moreover, modelines could change after creating a window,
but this is not an interesting use case in real life.
But since creating a window is not a frequent operation, and
changing a modeline on the fly is not a likely event, would it be
so bad to trigger that early redisplay on window creation?
I'm not saying that emacs should do it, I'm confident that your
decision in this regard will be far better than anything I could
come up with, I'm just looking for a workaround that gets the job
done or, alternatively, the certainty that it's a bad idea and that we
should refrain from pretiffing modelines.

Best regards,
Carlos