* bug#38181: Actual height of mode-line not taken into account @ 2019-11-12 16:52 Jonas Bernoulli 2019-11-13 8:03 ` martin rudalics ` (2 more replies) 0 siblings, 3 replies; 97+ messages in thread From: Jonas Bernoulli @ 2019-11-12 16:52 UTC (permalink / raw) To: 38181 If the height of the mode-line is increased by inserting an image into it, then that height is not taken into account in a buffer/window until `redisplay' has been called at least once since the buffer was created. This function can be used for testing: (defun test-popup () (interactive) (with-current-buffer (generate-new-buffer "*test*") (save-excursion (insert "one\ntwo\nthree\nfour\nfive")) (let ((win (display-buffer (current-buffer) '(display-buffer-in-side-window (side . bottom))))) ;; (redisplay) (fit-window-to-buffer win)))) First we can see that if we increase the height by modifying the `mode-line' and `mode-line-inactive' faces, then that IS taken into account. (set-face-attribute 'mode-line nil :height 250) (set-face-attribute 'mode-line-inactive nil :height 250) Now decrease the height again and try this instead: (setq-default mode-line-format (cons (propertize " " 'display (create-image "/* XPM */ static char * image[] = { \"3 60 1 1\", \"0 c #00aaff\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\" };" 'xpm t :ascent 'center)) mode-line-format)) When you call the command now, then the lower parts of the buffer are not visible because the window is not high enough. A work-around is to call `redisplay' before calling `fit-window-to-buffer', which could be done by advising that function. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-12 16:52 bug#38181: Actual height of mode-line not taken into account Jonas Bernoulli @ 2019-11-13 8:03 ` martin rudalics 2019-11-15 13:50 ` Eli Zaretskii 2019-11-15 13:48 ` Eli Zaretskii 2021-10-15 5:13 ` Carlos Pita 2 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2019-11-13 8:03 UTC (permalink / raw) To: Jonas Bernoulli, 38181 > (setq-default > mode-line-format > (cons (propertize " " 'display > (create-image "/* XPM */ static char * image[] = { > \"3 60 1 1\", > \"0 c #00aaff\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", > \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\" > };" 'xpm t :ascent 'center)) > mode-line-format)) When I evaluate that specification, the scroll bars are screwed up for all windows and remain so for all unselected windows. So this problem is not pertinent to 'fit-window-to-buffer' only. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-13 8:03 ` martin rudalics @ 2019-11-15 13:50 ` Eli Zaretskii 0 siblings, 0 replies; 97+ messages in thread From: Eli Zaretskii @ 2019-11-15 13:50 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > From: martin rudalics <rudalics@gmx.at> > Date: Wed, 13 Nov 2019 09:03:56 +0100 > > When I evaluate that specification, the scroll bars are screwed up for > all windows and remain so for all unselected windows. Doesn't happen here, FWIW. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-12 16:52 bug#38181: Actual height of mode-line not taken into account Jonas Bernoulli 2019-11-13 8:03 ` martin rudalics @ 2019-11-15 13:48 ` Eli Zaretskii 2019-11-15 14:24 ` Jonas Bernoulli 2019-11-15 19:38 ` Eli Zaretskii 2021-10-15 5:13 ` Carlos Pita 2 siblings, 2 replies; 97+ messages in thread From: Eli Zaretskii @ 2019-11-15 13:48 UTC (permalink / raw) To: Jonas Bernoulli; +Cc: 38181 > From: Jonas Bernoulli <jonas@bernoul.li> > Date: Tue, 12 Nov 2019 17:52:59 +0100 > > If the height of the mode-line is increased by inserting an image into > it, then that height is not taken into account in a buffer/window until > `redisplay' has been called at least once since the buffer was created. AFAIR, the mode line display is done lazily, because otherwise the mode line would flicker. When you change the face, that triggers a thorough redisplay, because any change in faces does that (it could mean many faces now have a different appearance). Adding an image to the mode line doesn't have that effect, which is why you need to force redisplay manually. So much for theory. Now for the practical aspects: how bad is it to have to invoke redisplay by hand in these cases? After all, they don't sound like something a Lisp program would do frequently. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-15 13:48 ` Eli Zaretskii @ 2019-11-15 14:24 ` Jonas Bernoulli 2019-11-15 15:11 ` Eli Zaretskii 2019-11-15 19:38 ` Eli Zaretskii 1 sibling, 1 reply; 97+ messages in thread From: Jonas Bernoulli @ 2019-11-15 14:24 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 Eli Zaretskii <eliz@gnu.org> writes: > So much for theory. Now for the practical aspects: how bad is it to > have to invoke redisplay by hand in these cases? After all, they > don't sound like something a Lisp program would do frequently. Currently I do the manual redisplay by advising fit-window-to-buffer, which I don't think can be avoided. This results in some flickering, so I make sure it is only done once per buffer. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-15 14:24 ` Jonas Bernoulli @ 2019-11-15 15:11 ` Eli Zaretskii 2019-11-15 23:51 ` Jonas Bernoulli 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-15 15:11 UTC (permalink / raw) To: Jonas Bernoulli; +Cc: 38181 > From: Jonas Bernoulli <jonas@bernoul.li> > Cc: 38181@debbugs.gnu.org > Date: Fri, 15 Nov 2019 15:24:11 +0100 > > > Eli Zaretskii <eliz@gnu.org> writes: > > > So much for theory. Now for the practical aspects: how bad is it to > > have to invoke redisplay by hand in these cases? After all, they > > don't sound like something a Lisp program would do frequently. > > Currently I do the manual redisplay by advising fit-window-to-buffer, > which I don't think can be avoided. This results in some flickering, > so I make sure it is only done once per buffer. Why the need to use advising? Your recipe shows that calling redisplay before fit-window-to-buffer also solves the problem. Can't you do something like that only when you add such tall images to the mode line? An alternative would be to scale the image so that it doesn't enlarge the mode line, btw. Is that possible in your use cases? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-15 15:11 ` Eli Zaretskii @ 2019-11-15 23:51 ` Jonas Bernoulli 2019-11-16 8:38 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: Jonas Bernoulli @ 2019-11-15 23:51 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 Eli Zaretskii <eliz@gnu.org> writes: > Why the need to use advising? Your recipe shows that calling > redisplay before fit-window-to-buffer also solves the problem. Can't > you do something like that only when you add such tall images to the > mode line? This is about packages like powerline, spaceline, doom-modeline and my moody. These packages add images to the global mode-line-format to make them prettier. These packages do not create any buffers of their own and they never call fit-window-to-buffer themselves, but whenever that function is called for a new buffer redisplay has to be run first, so the advice is needed. > An alternative would be to scale the image so that it doesn't enlarge > the mode line, btw. Is that possible in your use cases? No because enlarging the mode-line is one of the things I did in order to make it prettier (imo). It's a goal not a means or side-effect. You can see a screenshot on https://github.com/tarsius/moody. Many other "mode-line prettifiers" also increase its height. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-15 23:51 ` Jonas Bernoulli @ 2019-11-16 8:38 ` Eli Zaretskii 2019-11-16 14:54 ` Jonas Bernoulli 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-16 8:38 UTC (permalink / raw) To: Jonas Bernoulli; +Cc: 38181 > From: Jonas Bernoulli <jonas@bernoul.li> > Cc: 38181@debbugs.gnu.org > Date: Sat, 16 Nov 2019 00:51:19 +0100 > > > An alternative would be to scale the image so that it doesn't enlarge > > the mode line, btw. Is that possible in your use cases? > > No because enlarging the mode-line is one of the things I did in order > to make it prettier (imo). It's a goal not a means or side-effect. If this is to make the mode line prettier, then it should be done once, at the beginning of a session, right? In that case, why calling redisplay after loading the package or enabling a feature is not a solution? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 8:38 ` Eli Zaretskii @ 2019-11-16 14:54 ` Jonas Bernoulli 2019-11-16 15:59 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: Jonas Bernoulli @ 2019-11-16 14:54 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 Eli Zaretskii <eliz@gnu.org> writes: >> From: Jonas Bernoulli <jonas@bernoul.li> >> Cc: 38181@debbugs.gnu.org >> Date: Sat, 16 Nov 2019 00:51:19 +0100 >> >> > An alternative would be to scale the image so that it doesn't enlarge >> > the mode line, btw. Is that possible in your use cases? >> >> No because enlarging the mode-line is one of the things I did in order >> to make it prettier (imo). It's a goal not a means or side-effect. > > If this is to make the mode line prettier, then it should be done > once, at the beginning of a session, right? In that case, why calling > redisplay after loading the package or enabling a feature is not a > solution? No that won't work. Each buffer has its own mode-line so when a new buffer is created, then its height has to be calculated. In practice all mode-lines have the same height, so if Emacs could use the height "that all the other buffers/windows are using" when it does not know the actual height, then that would help. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 14:54 ` Jonas Bernoulli @ 2019-11-16 15:59 ` Eli Zaretskii 2019-11-17 16:17 ` Jonas Bernoulli 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-16 15:59 UTC (permalink / raw) To: Jonas Bernoulli; +Cc: 38181 > From: Jonas Bernoulli <jonas@bernoul.li> > Cc: 38181@debbugs.gnu.org > Date: Sat, 16 Nov 2019 15:54:53 +0100 > > > If this is to make the mode line prettier, then it should be done > > once, at the beginning of a session, right? In that case, why calling > > redisplay after loading the package or enabling a feature is not a > > solution? > > No that won't work. Each buffer has its own mode-line so when > a new buffer is created, then its height has to be calculated. Ouch! > In practice all mode-lines have the same height, so if Emacs could > use the height "that all the other buffers/windows are using" when > it does not know the actual height, then that would help. fit-window-to-buffer doesn't use (or know, really) the height of the mode line in the scenario you presented. Instead, it gets the height of the window's text area (which excludes the mode line and the header line) from the data stored in the window object. The problem is that this data is recalculated only when the window is redisplayed, so without the call to 'redisplay' we use stale data until the next redisplay cycle. However, if all the mode lines have the same height, then the problem shouldn't have happened, and so now I wonder what am I missing. If you simulate the situation where the mode line changes, while keeping its height (even if that height is unusually large), does the problem with fit-window-to-buffer still happen? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 15:59 ` Eli Zaretskii @ 2019-11-17 16:17 ` Jonas Bernoulli 0 siblings, 0 replies; 97+ messages in thread From: Jonas Bernoulli @ 2019-11-17 16:17 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 Eli Zaretskii <eliz@gnu.org> writes: > The problem is that > this data is recalculated only when the window is redisplayed, so > without the call to 'redisplay' we use stale data until the next > redisplay cycle. > > However, if all the mode lines have the same height, then the problem > shouldn't have happened, and so now I wonder what am I missing. I think the culprit is that we are not reusing some existing window to display a new buffer but actually split an existing window in two and then display the new buffer in the new window which never had its mode- line height calculated. > If > you simulate the situation where the mode line changes, while keeping > its height (even if that height is unusually large), does the problem > with fit-window-to-buffer still happen? No, if the mode-line (height) can be "reused", then there is no problem. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-15 13:48 ` Eli Zaretskii 2019-11-15 14:24 ` Jonas Bernoulli @ 2019-11-15 19:38 ` Eli Zaretskii 2019-11-16 8:20 ` martin rudalics 1 sibling, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-15 19:38 UTC (permalink / raw) To: jonas; +Cc: 38181 > Date: Fri, 15 Nov 2019 15:48:53 +0200 > From: Eli Zaretskii <eliz@gnu.org> > Cc: 38181@debbugs.gnu.org > > > From: Jonas Bernoulli <jonas@bernoul.li> > > Date: Tue, 12 Nov 2019 17:52:59 +0100 > > > > If the height of the mode-line is increased by inserting an image into > > it, then that height is not taken into account in a buffer/window until > > `redisplay' has been called at least once since the buffer was created. > > AFAIR, the mode line display is done lazily, because otherwise the > mode line would flicker. When you change the face, that triggers a > thorough redisplay, because any change in faces does that (it could > mean many faces now have a different appearance). Adding an image to > the mode line doesn't have that effect, which is why you need to force > redisplay manually. Btw, I was wrong above: enlarging the mode-line faces also causes a similar problem. Try this slightly modified recipe: (defun test-popup () (interactive) (set-face-attribute 'mode-line nil :height 350) (set-face-attribute 'mode-line-inactive nil :height 350) (with-current-buffer (generate-new-buffer "*test*") (save-excursion (insert "one\ntwo\nthree\nfour\nfive")) (let ((win (display-buffer (current-buffer) '(display-buffer-in-side-window (side . bottom))))) (fit-window-to-buffer win)))) and you will see that the buffer *test* isn't shown in its entirety, either. I think fit-window-to-buffer relies on window's metrics (like the number of lines in the text area) to be up to date, and that is only true after a window was redisplayed once since changing the mode-line height. Martin, is this correct? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-15 19:38 ` Eli Zaretskii @ 2019-11-16 8:20 ` martin rudalics 2019-11-16 8:35 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2019-11-16 8:20 UTC (permalink / raw) To: Eli Zaretskii, jonas; +Cc: 38181 [-- Attachment #1: Type: text/plain, Size: 556 bytes --] > I think fit-window-to-buffer relies on window's metrics (like the > number of lines in the text area) to be up to date, and that is only > true after a window was redisplayed once since changing the mode-line > height. Martin, is this correct? Yes. But, as I mentioned earlier, the problem shows up with the scroll bar immediately when Jonas' form is evaluated, see the attached screenshot. Code like 'fit-window-to-buffer' works on the text area only, it doesn't care whether a scroll bar or mode line changed size since last redisplay. martin [-- Attachment #2: mode-line-vs-scroll-bar.png --] [-- Type: image/png, Size: 18762 bytes --] ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 8:20 ` martin rudalics @ 2019-11-16 8:35 ` Eli Zaretskii 2019-11-16 8:57 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-16 8:35 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sat, 16 Nov 2019 09:20:27 +0100 > > > I think fit-window-to-buffer relies on window's metrics (like the > > number of lines in the text area) to be up to date, and that is only > > true after a window was redisplayed once since changing the mode-line > > height. Martin, is this correct? > > Yes. Then I'm not sure we can fix such use cases at all, without causing display flickering in much more popular use cases. Do you have any ideas for a possible fix? Could fit-window-to-buffer invoke 'redisplay' internally, perhaps? > But, as I mentioned earlier, the problem shows up with the > scroll bar immediately when Jonas' form is evaluated, see the attached > screenshot. That just means we (or a Lisp program which makes these mode-line modifications) need to recreate and redisplay the scroll bars anew in these cases, right? It's a separate problem, right? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 8:35 ` Eli Zaretskii @ 2019-11-16 8:57 ` martin rudalics 2019-11-16 10:57 ` Eli Zaretskii 2019-11-16 15:27 ` Jonas Bernoulli 0 siblings, 2 replies; 97+ messages in thread From: martin rudalics @ 2019-11-16 8:57 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 >> > I think fit-window-to-buffer relies on window's metrics (like the >> > number of lines in the text area) to be up to date, and that is only >> > true after a window was redisplayed once since changing the mode-line >> > height. Martin, is this correct? >> >> Yes. > > Then I'm not sure we can fix such use cases at all, without causing > display flickering in much more popular use cases. Do you have any > ideas for a possible fix? Could fit-window-to-buffer invoke > 'redisplay' internally, perhaps? It could but it's called way too often to warrant such behavior by default. But we could give it a separate optional argument so users can avoid the advice. I think Jonas could easily write and a test a patch along this idea. >> But, as I mentioned earlier, the problem shows up with the >> scroll bar immediately when Jonas' form is evaluated, see the attached >> screenshot. > > That just means we (or a Lisp program which makes these mode-line > modifications) need to recreate and redisplay the scroll bars anew in > these cases, right? Right. But that same program could also redisplay all windows in these cases, right? > It's a separate problem, right? For some value of right ... martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 8:57 ` martin rudalics @ 2019-11-16 10:57 ` Eli Zaretskii 2019-11-16 19:28 ` martin rudalics 2019-11-16 15:27 ` Jonas Bernoulli 1 sibling, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-16 10:57 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sat, 16 Nov 2019 09:57:40 +0100 > > > Then I'm not sure we can fix such use cases at all, without causing > > display flickering in much more popular use cases. Do you have any > > ideas for a possible fix? Could fit-window-to-buffer invoke > > 'redisplay' internally, perhaps? > > It could but it's called way too often to warrant such behavior by > default. What are the frequent calls? Help and completions windows come to mind, but those are interactive, and so I'm not sure I see why calling redisplay would be a bad idea there. Are there other callers which I'm missing? > But we could give it a separate optional argument so users can avoid > the advice. That's possible, of course. > >> But, as I mentioned earlier, the problem shows up with the > >> scroll bar immediately when Jonas' form is evaluated, see the attached > >> screenshot. > > > > That just means we (or a Lisp program which makes these mode-line > > modifications) need to recreate and redisplay the scroll bars anew in > > these cases, right? > > Right. But that same program could also redisplay all windows in > these cases, right? I meant that calling redisplay should do this automatically. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 10:57 ` Eli Zaretskii @ 2019-11-16 19:28 ` martin rudalics 2019-11-16 19:44 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2019-11-16 19:28 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > What are the frequent calls? Help and completions windows come to > mind, but those are interactive, and so I'm not sure I see why calling > redisplay would be a bad idea there. Are there other callers which > I'm missing? The functions for displaying temporary buffers when 'temp-buffer-resize-mode' is on. I do not think that the overhead for calculating the mode line height is excessive. It's just that IIUC even Jonas changes the mode line height only once per window/buffer assignment so even for him this overhead is practically always lost. >> Right. But that same program could also redisplay all windows in >> these cases, right? > > I meant that calling redisplay should do this automatically. By calculating the mode line before drawing the scroll bars? martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 19:28 ` martin rudalics @ 2019-11-16 19:44 ` Eli Zaretskii 2019-11-17 8:55 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-16 19:44 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sat, 16 Nov 2019 20:28:10 +0100 > > > What are the frequent calls? Help and completions windows come to > > mind, but those are interactive, and so I'm not sure I see why calling > > redisplay would be a bad idea there. Are there other callers which > > I'm missing? > > The functions for displaying temporary buffers when > 'temp-buffer-resize-mode' is on. I do not think that the overhead for > calculating the mode line height is excessive. It's just that IIUC > even Jonas changes the mode line height only once per window/buffer > assignment so even for him this overhead is practically always lost. But I thought we'd established that mode-line height calculation is not the culprit, the culprit is the fact that a window's height is not recomputed when the mode-line height changes. Did I misunderstand? > >> Right. But that same program could also redisplay all windows in > >> these cases, right? > > > > I meant that calling redisplay should do this automatically. > > By calculating the mode line before drawing the scroll bars? No, by triggering redrawing of scroll bars when we detect that the mode line changed its height. In this place of redisplay_window: display_mode_lines (w); /* If mode line height has changed, arrange for a thorough immediate redisplay using the correct mode line height. */ if (window_wants_mode_line (w) && CURRENT_MODE_LINE_HEIGHT (w) != DESIRED_MODE_LINE_HEIGHT (w)) { f->fonts_changed = true; w->mode_line_height = -1; MATRIX_MODE_LINE_ROW (w->current_matrix)->height = DESIRED_MODE_LINE_HEIGHT (w); } Or maybe in redisplay_internal, when we see that f->fonts_changed is set. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 19:44 ` Eli Zaretskii @ 2019-11-17 8:55 ` martin rudalics 2019-11-17 17:26 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2019-11-17 8:55 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > But I thought we'd established that mode-line height calculation is > not the culprit, the culprit is the fact that a window's height is not > recomputed when the mode-line height changes. Did I misunderstand? I don't think we contradicted each other's sayings here. To recapitulate what we found out so far: (1) To operate correctly in the user's sense, 'fit-window-to-buffer' has to know the height of the mode line of the window it operates on as it will be shown by the next redisplay. (2) When users or applications (maybe implicitly) change the mode line appearance, they have no generally established way to tell Emacs that this happened. The display engine has to find out by herself but then it's already too late for telling 'fit-window-to-buffer'. The question we yet have to resolve is now "only" _whether_ we can safely recompute a window's height after redisplay detects that the mode line height has changed. This may easily trigger window change functions which might easily change the mode line height again ... martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-17 8:55 ` martin rudalics @ 2019-11-17 17:26 ` Eli Zaretskii 2019-11-17 18:15 ` martin rudalics 2020-05-02 18:06 ` martin rudalics 0 siblings, 2 replies; 97+ messages in thread From: Eli Zaretskii @ 2019-11-17 17:26 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sun, 17 Nov 2019 09:55:47 +0100 > > > But I thought we'd established that mode-line height calculation is > > not the culprit, the culprit is the fact that a window's height is not > > recomputed when the mode-line height changes. Did I misunderstand? > > I don't think we contradicted each other's sayings here. To > recapitulate what we found out so far: > > (1) To operate correctly in the user's sense, 'fit-window-to-buffer' > has to know the height of the mode line of the window it operates > on as it will be shown by the next redisplay. I didn't see where fit-window-to-buffer looks at the height of the mode line. What did I miss? > (2) When users or applications (maybe implicitly) change the mode line > appearance, they have no generally established way to tell Emacs > that this happened. The display engine has to find out by herself > but then it's already too late for telling 'fit-window-to-buffer'. Suppose we had a Lisp-callable function which would return the height of the mode line of a window as per the current mode-line-format for that window -- would that make the solution possible/easier? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-17 17:26 ` Eli Zaretskii @ 2019-11-17 18:15 ` martin rudalics 2019-11-17 18:35 ` Eli Zaretskii 2020-05-02 18:06 ` martin rudalics 1 sibling, 1 reply; 97+ messages in thread From: martin rudalics @ 2019-11-17 18:15 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > I didn't see where fit-window-to-buffer looks at the height of the > mode line. What did I miss? 'window-text-pixel-size' does it (triggered by the sixth argument MODE-AND-HEADER-LINE non-nil). > Suppose we had a Lisp-callable function which would return the height > of the mode line of a window as per the current mode-line-format for > that window -- would that make the solution possible/easier? Possible, I think. If we pass it on to 'window-text-pixel-size', it wouldn't even have to be Lisp-callable. Still, it will penalize every ‘fit-window-to-buffer’ call (without a redisplay, though). martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-17 18:15 ` martin rudalics @ 2019-11-17 18:35 ` Eli Zaretskii 2019-11-18 9:44 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-17 18:35 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sun, 17 Nov 2019 19:15:44 +0100 > > > I didn't see where fit-window-to-buffer looks at the height of the > > mode line. What did I miss? > > 'window-text-pixel-size' does it (triggered by the sixth argument > MODE-AND-HEADER-LINE non-nil). Thanks. So the only thing that's missing is that it should call display_mode_lines, and then look at DESIRED_MODE_LINE_HEIGHT instead of WINDOW_MODE_LINE_HEIGHT? > > Suppose we had a Lisp-callable function which would return the height > > of the mode line of a window as per the current mode-line-format for > > that window -- would that make the solution possible/easier? > > Possible, I think. If we pass it on to 'window-text-pixel-size', it > wouldn't even have to be Lisp-callable. Still, it will penalize every > ‘fit-window-to-buffer’ call (without a redisplay, though). Why "penalize"? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-17 18:35 ` Eli Zaretskii @ 2019-11-18 9:44 ` martin rudalics 2019-11-18 15:42 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2019-11-18 9:44 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > Thanks. So the only thing that's missing is that it should call > display_mode_lines, and then look at DESIRED_MODE_LINE_HEIGHT instead > of WINDOW_MODE_LINE_HEIGHT? I suppose so. But please always keep in mind that the window code does not handle problems caused by specifications in the mode and header lines immediately. For example, it will not auto-resize a one-line window when its mode line height is increased to more than its text height. Try with a one-line window and Jonas' (set-face-attribute 'mode-line nil :height 250) >> Still, it will penalize every >> ‘fit-window-to-buffer’ call (without a redisplay, though). > > Why "penalize"? Because 'fit-window-to-buffer' now has to calculate the mode line height which it didn't before and which for the majority of users never changes. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-18 9:44 ` martin rudalics @ 2019-11-18 15:42 ` Eli Zaretskii 2019-11-18 18:45 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-18 15:42 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Mon, 18 Nov 2019 10:44:56 +0100 > > > Thanks. So the only thing that's missing is that it should call > > display_mode_lines, and then look at DESIRED_MODE_LINE_HEIGHT instead > > of WINDOW_MODE_LINE_HEIGHT? > > I suppose so. But please always keep in mind that the window code > does not handle problems caused by specifications in the mode and > header lines immediately. What kind of problems are we talking about? > For example, it will not auto-resize a one-line window when its mode > line height is increased to more than its text height. That's a separate issue, isn't it? > >> Still, it will penalize every > >> ‘fit-window-to-buffer’ call (without a redisplay, though). > > > > Why "penalize"? > > Because 'fit-window-to-buffer' now has to calculate the mode line > height which it didn't before and which for the majority of users > never changes. Is that a significant problem? It's not like fit-window-to-buffer is expected to be called in a tight loop, right? Displaying a mode line is no more expensive (actually, even usually expensive) than calling vertical-motion to move one line, and we would never think twice before adding a call to the latter, right? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-18 15:42 ` Eli Zaretskii @ 2019-11-18 18:45 ` martin rudalics 0 siblings, 0 replies; 97+ messages in thread From: martin rudalics @ 2019-11-18 18:45 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 >> I suppose so. But please always keep in mind that the window code >> does not handle problems caused by specifications in the mode and >> header lines immediately. > > What kind of problems are we talking about? Any problems with the minimum size of windows as the one described in the next sentence. >> For example, it will not auto-resize a one-line window when its mode >> line height is increased to more than its text height. > > That's a separate issue, isn't it? It's similar, at least. The scroll bar issue is another similar one. >> Because 'fit-window-to-buffer' now has to calculate the mode line >> height which it didn't before and which for the majority of users >> never changes. > > Is that a significant problem? I hope it isn't. > It's not like fit-window-to-buffer is > expected to be called in a tight loop, right? Displaying a mode line > is no more expensive (actually, even usually expensive) than calling > vertical-motion to move one line, and we would never think twice > before adding a call to the latter, right? Agreed (I suppose you meant to say "even usually less expensive" above). martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-17 17:26 ` Eli Zaretskii 2019-11-17 18:15 ` martin rudalics @ 2020-05-02 18:06 ` martin rudalics 2020-05-04 13:46 ` Eli Zaretskii 1 sibling, 1 reply; 97+ messages in thread From: martin rudalics @ 2020-05-02 18:06 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > Suppose we had a Lisp-callable function which would return the height > of the mode line of a window as per the current mode-line-format for > that window -- would that make the solution possible/easier? Suppose I wanted to write such a function. Then the problem is with scenarios like your earlier (defun test-popup () (interactive) (set-face-attribute 'mode-line nil :height 350) (set-face-attribute 'mode-line-inactive nil :height 350) (with-current-buffer (generate-new-buffer "*test*") (save-excursion (insert "one\ntwo\nthree\nfour\nfive")) (let ((win (display-buffer (current-buffer) '(display-buffer-in-side-window (side . bottom))))) (fit-window-to-buffer win)))) If I wanted to take into account the changes of the face attributes in 'fit-window-to-buffer', I'd have to set 'inhibit-free-realized-faces' there to nil in order to apply the necessary face changes. Wouldn't that possibly harm our window matrices? Can you somehow summarize how that variable is supposed to be treated in general? I already gave up fighting with it in Bug#40639. Thanks, martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-02 18:06 ` martin rudalics @ 2020-05-04 13:46 ` Eli Zaretskii 2020-05-04 15:04 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2020-05-04 13:46 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sat, 2 May 2020 20:06:38 +0200 > > > Suppose we had a Lisp-callable function which would return the height > > of the mode line of a window as per the current mode-line-format for > > that window -- would that make the solution possible/easier? > > Suppose I wanted to write such a function. Then the problem is with > scenarios like your earlier Sorry for the belated response, there's a tsunami out there... > (defun test-popup () > (interactive) > (set-face-attribute 'mode-line nil :height 350) > (set-face-attribute 'mode-line-inactive nil :height 350) > (with-current-buffer (generate-new-buffer "*test*") > (save-excursion > (insert "one\ntwo\nthree\nfour\nfive")) > (let ((win (display-buffer (current-buffer) > '(display-buffer-in-side-window > (side . bottom))))) > (fit-window-to-buffer win)))) > > If I wanted to take into account the changes of the face attributes in > 'fit-window-to-buffer', I'd have to set 'inhibit-free-realized-faces' > there to nil in order to apply the necessary face changes. Wouldn't > that possibly harm our window matrices? Can you somehow summarize how > that variable is supposed to be treated in general? I already gave up > fighting with it in Bug#40639. I don't think I follow. Are you saying that inhibit-free-realized-faces is non-nil when you run Lisp interactively, or in general in a Lisp program that was not called, directly or indirectly, from redisplay_internal? That should never happen, as the code arranges for inhibit-free-realized-faces to be reset to its original value when redisplay_internal returns. If this doesn't work, then we have a serious bug on our hands, and should fix it ASAP. This variable is supposed to be non-nil only when we are done preparing the desired matrices and are about to call update_frame, because that function cannot cope with faces referenced in the desired matrices that were meanwhile freed. This could happen if some hook called from redisplay_internal manages to run code that decides to free the faces. But once update_frame is done, we don't need this variable set anymore, and it should revert to nil soon enough, because redisplay_internal returns soon after that. What am I missing? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-04 13:46 ` Eli Zaretskii @ 2020-05-04 15:04 ` martin rudalics 2020-05-04 17:05 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2020-05-04 15:04 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > I don't think I follow. Are you saying that > inhibit-free-realized-faces is non-nil when you run Lisp > interactively, Yes. > or in general in a Lisp program that was not called, > directly or indirectly, from redisplay_internal? That should never > happen, as the code arranges for inhibit-free-realized-faces to be > reset to its original value when redisplay_internal returns. If this > doesn't work, then we have a serious bug on our hands, and should fix > it ASAP. The problem here seems that the original value is true. So if I'm not entirely misguided it must be somehow set by PRODUCE_GLYPHS outside of redisplay_internal. > This variable is supposed to be non-nil only when we are done > preparing the desired matrices and are about to call update_frame, > because that function cannot cope with faces referenced in the desired > matrices that were meanwhile freed. This could happen if some hook > called from redisplay_internal manages to run code that decides to > free the faces. > > But once update_frame is done, we don't need this variable set > anymore, and it should revert to nil soon enough, because > redisplay_internal returns soon after that. > > What am I missing? Your explanation coincides with how I expected this variable to behave. It does not coincide with the behavior I see. Thanks, martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-04 15:04 ` martin rudalics @ 2020-05-04 17:05 ` martin rudalics 2020-05-05 8:32 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2020-05-04 17:05 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > So if I'm not > entirely misguided it must be somehow set by PRODUCE_GLYPHS outside of > redisplay_internal. Confirmed meanwhile. Something is utterly broken here. Removing the offending setting in PRODUCE_GLYPHS automagically fixes Bug#40639 and Bug#41071, for example. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-04 17:05 ` martin rudalics @ 2020-05-05 8:32 ` martin rudalics 2020-05-05 14:58 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2020-05-05 8:32 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 Below find two backtraces with emacs -Q where PRODUCE_GLYPHS here sets inhibit_free_realized_faces outside the scope of redisplay_internal (that is, while redisplaying_p is nil) such that these will not get caught by the unbind form in redisplay_internal. do_inhibit_free_realized_faces is the function I used to trap these. It's defined as void do_inhibit_free_realized_faces (void) { if (redisplaying_p) inhibit_free_realized_faces = true; else if (!inhibit_free_realized_faces) inhibit_free_realized_faces = true; } and gets called by PRODUCE_GLYPHS instead of setting inhibit_free_realized_faces directly. The first one comes initially: #0 0x000000000046f836 in do_inhibit_free_realized_faces () at ../../src/xdisp.c:2043 #1 0x000000000057098e in display_line (it=0x7fffffffab00, cursor_vpos=0) at ../../src/xdisp.c:23311 #2 0x00000000004c1a8e in try_window (window=XIL(0x12c2db5), pos=..., flags=0) at ../../src/xdisp.c:19180 #3 0x00000000004a1029 in display_echo_area_1 (a1=19672496, a2=XIL(0)) at ../../src/xdisp.c:11552 #4 0x00000000004a0270 in with_echo_area_buffer (w=0x12c2db0, which=0, fn=0x4a0f3d <display_echo_area_1>, a1=19672496, a2=XIL(0)) at ../../src/xdisp.c:11314 #5 0x00000000004a0ee8 in display_echo_area (w=0x12c2db0) at ../../src/xdisp.c:11510 #6 0x00000000004a4520 in echo_area_display (update_frame_p=true) at ../../src/xdisp.c:12023 #7 0x000000000049f59e in message3_nolog (m=XIL(0x12b6be4)) at ../../src/xdisp.c:11016 #8 0x000000000049f26b in message3 (m=XIL(0x12b6be4)) at ../../src/xdisp.c:10946 #9 0x0000000000834154 in Fmessage (nargs=2, args=0x7fffffffc210) at ../../src/editfns.c:2859 #10 0x00000000008456b1 in funcall_subr (subr=0xe0e680 <Smessage>, numargs=2, args=0x7fffffffc210) at ../../src/eval.c:2847 #11 0x0000000000845287 in Ffuncall (nargs=3, args=0x7fffffffc208) at ../../src/eval.c:2794 #12 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff4225264), vector=XIL(0x7ffff4225135), maxdepth=make_fixnum(7), args_template=make_fixnum(0), nargs=0, args=0x7fffffffc728) at ../../src/bytecode.c:633 #13 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff422510d), nargs=0, arg_vector=0x7fffffffc728) at ../../src/eval.c:2989 #14 0x00000000008452cb in Ffuncall (nargs=1, args=0x7fffffffc720) at ../../src/eval.c:2796 #15 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff42252a4), vector=XIL(0x7ffff4223e0d), maxdepth=make_fixnum(25), args_template=make_fixnum(257), nargs=1, args=0x7fffffffd0d8) at ../../src/bytecode.c:633 #16 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff4223ddd), nargs=1, arg_vector=0x7fffffffd0d0) at ../../src/eval.c:2989 #17 0x00000000008452cb in Ffuncall (nargs=2, args=0x7fffffffd0c8) at ../../src/eval.c:2796 #18 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff4229434), vector=XIL(0x7ffff42254f5), maxdepth=make_fixnum(14), args_template=make_fixnum(0), nargs=0, args=0x7fffffffdc18) at ../../src/bytecode.c:633 #19 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff42254c5), nargs=0, arg_vector=0x7fffffffdc18) at ../../src/eval.c:2989 #20 0x00000000008452cb in Ffuncall (nargs=1, args=0x7fffffffdc10) at ../../src/eval.c:2796 #21 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff422a0fc), vector=XIL(0x7ffff4229605), maxdepth=make_fixnum(12), args_template=make_fixnum(0), nargs=0, args=0x7fffffffe250) at ../../src/bytecode.c:633 #22 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff42295d5), nargs=0, arg_vector=0x7fffffffe250) at ../../src/eval.c:2989 #23 0x0000000000845b42 in apply_lambda (fun=XIL(0x7ffff42295d5), args=XIL(0), count=4) at ../../src/eval.c:2926 #24 0x0000000000843d3e in eval_sub (form=XIL(0x7ffff4385a83)) at ../../src/eval.c:2318 #25 0x00000000008430ce in Feval (form=XIL(0x7ffff4385a83), lexical=XIL(0)) at ../../src/eval.c:2102 #26 0x0000000000764b7f in top_level_2 () at ../../src/keyboard.c:1100 #27 0x000000000084126b in internal_condition_case (bfun=0x764b5c <top_level_2>, handlers=XIL(0x90), hfun=0x76455b <cmd_error>) at ../../src/eval.c:1355 #28 0x0000000000764bc7 in top_level_1 (ignore=XIL(0)) at ../../src/keyboard.c:1108 #29 0x000000000084071f in internal_catch (tag=XIL(0xd200), func=0x764b81 <top_level_1>, arg=XIL(0)) at ../../src/eval.c:1116 #30 0x0000000000764aa6 in command_loop () at ../../src/keyboard.c:1069 #31 0x0000000000764042 in recursive_edit_1 () at ../../src/keyboard.c:714 #32 0x000000000076423a in Frecursive_edit () at ../../src/keyboard.c:786 #33 0x00000000007603bd in main (argc=2, argv=0x7fffffffe7c8) at ../../src/emacs.c:2035 Lisp Backtrace: "message" (0xffffc210) "display-startup-echo-area-message" (0xffffc728) "command-line-1" (0xffffd0d0) "command-line" (0xffffdc18) "normal-top-level" (0xffffe250) (gdb) After now evaluating (setq inhibit-free-realized-faces nil) the second one comes up as: #0 0x000000000046f836 in do_inhibit_free_realized_faces () at ../../src/xdisp.c:2043 #1 0x000000000057098e in display_line (it=0x7fffffffa4c0, cursor_vpos=0) at ../../src/xdisp.c:23311 #2 0x00000000004c1a8e in try_window (window=XIL(0x12c2db5), pos=..., flags=0) at ../../src/xdisp.c:19180 #3 0x00000000004a1029 in display_echo_area_1 (a1=19672496, a2=XIL(0)) at ../../src/xdisp.c:11552 #4 0x00000000004a0270 in with_echo_area_buffer (w=0x12c2db0, which=0, fn=0x4a0f3d <display_echo_area_1>, a1=19672496, a2=XIL(0)) at ../../src/xdisp.c:11314 #5 0x00000000004a0ee8 in display_echo_area (w=0x12c2db0) at ../../src/xdisp.c:11510 #6 0x00000000004a4520 in echo_area_display (update_frame_p=true) at ../../src/xdisp.c:12023 #7 0x000000000049f59e in message3_nolog (m=XIL(0xf07bf4)) at ../../src/xdisp.c:11016 #8 0x000000000049f26b in message3 (m=XIL(0xf07bf4)) at ../../src/xdisp.c:10946 #9 0x0000000000834154 in Fmessage (nargs=2, args=0x7fffffffbd48) at ../../src/editfns.c:2859 #10 0x00000000008456b1 in funcall_subr (subr=0xe0e680 <Smessage>, numargs=2, args=0x7fffffffbd48) at ../../src/eval.c:2847 #11 0x0000000000845287 in Ffuncall (nargs=3, args=0x7fffffffbd40) at ../../src/eval.c:2794 #12 0x00000000008440f9 in Fapply (nargs=3, args=0x7fffffffbd40) at ../../src/eval.c:2381 #13 0x00000000008456b1 in funcall_subr (subr=0xe0f100 <Sapply>, numargs=3, args=0x7fffffffbd40) at ../../src/eval.c:2847 #14 0x0000000000845287 in Ffuncall (nargs=4, args=0x7fffffffbd38) at ../../src/eval.c:2794 #15 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff402e244), vector=XIL(0x7ffff402e075), maxdepth=make_fixnum(7), args_template=make_fixnum(385), nargs=2, args=0x7fffffffc238) at ../../src/bytecode.c:633 #16 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff402e045), nargs=2, arg_vector=0x7fffffffc230) at ../../src/eval.c:2989 #17 0x00000000008452cb in Ffuncall (nargs=3, args=0x7fffffffc228) at ../../src/eval.c:2796 #18 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff402e9cc), vector=XIL(0x7ffff402df45), maxdepth=make_fixnum(5), args_template=make_fixnum(256), nargs=1, args=0x7fffffffc6e8) at ../../src/bytecode.c:633 #19 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff402df15), nargs=1, arg_vector=0x7fffffffc6e0) at ../../src/eval.c:2989 #20 0x00000000008452cb in Ffuncall (nargs=2, args=0x7fffffffc6d8) at ../../src/eval.c:2796 #21 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff4031b2c), vector=XIL(0x7ffff40318ed), maxdepth=make_fixnum(4), args_template=make_fixnum(0), nargs=0, args=0x7fffffffcbb0) at ../../src/bytecode.c:633 #22 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff40318bd), nargs=0, arg_vector=0x7fffffffcbb0) at ../../src/eval.c:2989 #23 0x00000000008452cb in Ffuncall (nargs=1, args=0x7fffffffcba8) at ../../src/eval.c:2796 #24 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff4031b6c), vector=XIL(0x7ffff4031865), maxdepth=make_fixnum(1), args_template=make_fixnum(0), nargs=0, args=0x7fffffffd1e0) at ../../src/bytecode.c:633 #25 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff403183d), nargs=0, arg_vector=0x7fffffffd1e0) at ../../src/eval.c:2989 #26 0x00000000008452cb in Ffuncall (nargs=1, args=0x7fffffffd1d8) at ../../src/eval.c:2796 #27 0x0000000000844088 in Fapply (nargs=2, args=0x7fffffffd1d8) at ../../src/eval.c:2377 #28 0x00000000008456b1 in funcall_subr (subr=0xe0f100 <Sapply>, numargs=2, args=0x7fffffffd1d8) at ../../src/eval.c:2847 #29 0x0000000000845287 in Ffuncall (nargs=3, args=0x7fffffffd1d0) at ../../src/eval.c:2794 #30 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff438e57c), vector=XIL(0x7ffff438e445), maxdepth=make_fixnum(10), args_template=make_fixnum(257), nargs=1, args=0x7fffffffd730) at ../../src/bytecode.c:633 #31 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff438e415), nargs=1, arg_vector=0x7fffffffd728) at ../../src/eval.c:2989 #32 0x00000000008452cb in Ffuncall (nargs=2, args=0x7fffffffd720) at ../../src/eval.c:2796 #33 0x0000000000844bb7 in call1 (fn=XIL(0xcf30), arg1=XIL(0x172d2f5)) at ../../src/eval.c:2654 #34 0x000000000076e3ae in timer_check_2 (timers=XIL(0), idle_timers=XIL(0x170e5b3)) at ../../src/keyboard.c:4340 #35 0x000000000076e4e3 in timer_check () at ../../src/keyboard.c:4402 #36 0x000000000076c242 in readable_events (flags=1) at ../../src/keyboard.c:3401 #37 0x0000000000778a4e in get_input_pending (flags=1) at ../../src/keyboard.c:6800 #38 0x0000000000781f2b in detect_input_pending_run_timers (do_display=true) at ../../src/keyboard.c:10361 #39 0x00000000008aeb95 in wait_reading_process_output (time_limit=30, nsecs=0, read_kbd=-1, do_display=true, wait_for_cell=XIL(0), wait_proc=0x0, just_wait_proc=0) at ../../src/process.c:5701 #40 0x000000000042a466 in sit_for (timeout=make_fixnum(30), reading=true, display_option=1) at ../../src/dispnew.c:6077 #41 0x0000000000769957 in read_char (commandflag=1, map=XIL(0x1709e33), prev_event=XIL(0), used_mouse_menu=0x7fffffffe13f, end_time=0x0) at ../../src/keyboard.c:2738 #42 0x0000000000780011 in read_key_sequence (keybuf=0x7fffffffe2d0, prompt=XIL(0), dont_downcase_last=false, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=false) at ../../src/keyboard.c:9547 #43 0x00000000007653c8 in command_loop_1 () at ../../src/keyboard.c:1350 #44 0x000000000084126b in internal_condition_case (bfun=0x764f4c <command_loop_1>, handlers=XIL(0x90), hfun=0x76455b <cmd_error>) at ../../src/eval.c:1355 #45 0x0000000000764b31 in command_loop_2 (ignore=XIL(0)) at ../../src/keyboard.c:1091 #46 0x000000000084071f in internal_catch (tag=XIL(0xd200), func=0x764b04 <command_loop_2>, arg=XIL(0)) at ../../src/eval.c:1116 #47 0x0000000000764acf in command_loop () at ../../src/keyboard.c:1070 #48 0x0000000000764042 in recursive_edit_1 () at ../../src/keyboard.c:714 #49 0x000000000076423a in Frecursive_edit () at ../../src/keyboard.c:786 #50 0x00000000007603bd in main (argc=2, argv=0x7fffffffe7c8) at ../../src/emacs.c:2035 Lisp Backtrace: "message" (0xffffbd48) "apply" (0xffffbd40) "eldoc-minibuffer-message" (0xffffc230) "eldoc-message" (0xffffc6e0) "eldoc-print-current-symbol-info" (0xffffcbb0) 0xf4031838 PVEC_COMPILED "apply" (0xffffd1d8) "timer-event-handler" (0xffffd728) (gdb) And below is one where I load my usual customizations #0 0x000000000046f836 in do_inhibit_free_realized_faces () at ../../src/xdisp.c:2043 #1 0x000000000057098e in display_line (it=0x7fffffff8a30, cursor_vpos=0) at ../../src/xdisp.c:23311 #2 0x00000000004c1a8e in try_window (window=XIL(0x12c5db5), pos=..., flags=0) at ../../src/xdisp.c:19180 #3 0x00000000004a1029 in display_echo_area_1 (a1=19684784, a2=XIL(0)) at ../../src/xdisp.c:11552 #4 0x00000000004a0270 in with_echo_area_buffer (w=0x12c5db0, which=0, fn=0x4a0f3d <display_echo_area_1>, a1=19684784, a2=XIL(0)) at ../../src/xdisp.c:11314 #5 0x00000000004a0ee8 in display_echo_area (w=0x12c5db0) at ../../src/xdisp.c:11510 #6 0x00000000004a4520 in echo_area_display (update_frame_p=true) at ../../src/xdisp.c:12023 #7 0x000000000049f59e in message3_nolog (m=XIL(0xeef4b4)) at ../../src/xdisp.c:11016 #8 0x000000000049f26b in message3 (m=XIL(0xeef4b4)) at ../../src/xdisp.c:10946 #9 0x000000000049f891 in message_with_string (m=0x9a619d "Loading %s...", string=XIL(0x7ffff3d31104), log=true) at ../../src/xdisp.c:11089 #10 0x0000000000881110 in Fload (file=XIL(0x7ffff3d31104), noerror=XIL(0), nomessage=XIL(0), nosuffix=XIL(0), must_suffix=XIL(0)) at ../../src/lread.c:1440 #11 0x0000000000845883 in funcall_subr (subr=0xe11c40 <Sload>, numargs=1, args=0x7fffffffa3c8) at ../../src/eval.c:2879 #12 0x0000000000845287 in Ffuncall (nargs=2, args=0x7fffffffa3c0) at ../../src/eval.c:2794 #13 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff3d4ef0c), vector=XIL(0x7ffff3d4ec45), maxdepth=make_fixnum(14), args_template=make_fixnum(257), nargs=1, args=0x7fffffffa960) at ../../src/bytecode.c:633 #14 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff3d4ec15), nargs=1, arg_vector=0x7fffffffa958) at ../../src/eval.c:2989 #15 0x00000000008452cb in Ffuncall (nargs=2, args=0x7fffffffa950) at ../../src/eval.c:2796 #16 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff3d4f8f4), vector=XIL(0x7ffff3d4e9ad), maxdepth=make_fixnum(15), args_template=make_fixnum(385), nargs=142, args=0x7fffffffaf00) at ../../src/bytecode.c:633 #17 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff3d4e97d), nargs=142, arg_vector=0x7fffffffaef8) at ../../src/eval.c:2989 #18 0x00000000008452cb in Ffuncall (nargs=143, args=0x7fffffffaef0) at ../../src/eval.c:2796 #19 0x00000000008444c3 in Fapply (nargs=3, args=0x7fffffffb518) at ../../src/eval.c:2424 #20 0x00000000008456b1 in funcall_subr (subr=0xe0f100 <Sapply>, numargs=3, args=0x7fffffffb518) at ../../src/eval.c:2847 #21 0x0000000000845287 in Ffuncall (nargs=4, args=0x7fffffffb510) at ../../src/eval.c:2794 #22 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff3d213dc), vector=XIL(0x7ffff41be795), maxdepth=make_fixnum(5), args_template=make_fixnum(128), nargs=141, args=0x7fffffffb930) at ../../src/bytecode.c:633 #23 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff41be765), nargs=141, arg_vector=0x7fffffffb930) at ../../src/eval.c:2989 #24 0x0000000000845b42 in apply_lambda (fun=XIL(0x7ffff41be765), args=XIL(0x1631ab3), count=36) at ../../src/eval.c:2926 #25 0x0000000000843d3e in eval_sub (form=XIL(0x1631b23)) at ../../src/eval.c:2318 #26 0x0000000000882b74 in readevalloop_eager_expand_eval (val=XIL(0x1631b23), macroexpand=XIL(0x7ffff31f4a98)) at ../../src/lread.c:1912 #27 0x00000000008833a7 in readevalloop (readcharfun=XIL(0x168c415), infile0=0x0, sourcename=XIL(0x13b67b4), printflag=false, unibyte=XIL(0), readfun=XIL(0), start=XIL(0), end=XIL(0)) at ../../src/lread.c:2094 #28 0x00000000008836d2 in Feval_buffer (buffer=XIL(0x168c415), printflag=XIL(0), filename=XIL(0x13b67b4), unibyte=XIL(0), do_allow_print=XIL(0x30)) at ../../src/lread.c:2167 #29 0x0000000000845883 in funcall_subr (subr=0xe11cc0 <Seval_buffer>, numargs=5, args=0x7fffffffc1d0) at ../../src/eval.c:2879 #30 0x0000000000845287 in Ffuncall (nargs=6, args=0x7fffffffc1c8) at ../../src/eval.c:2794 #31 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff3d5d664), vector=XIL(0x7ffff3d5cfe5), maxdepth=make_fixnum(6), args_template=XIL(0), nargs=0, args=0x0) at ../../src/bytecode.c:633 #32 0x00000000008464a0 in funcall_lambda (fun=XIL(0x7ffff3d5cfb5), nargs=4, arg_vector=0x7ffff3d5cfe5) at ../../src/eval.c:3067 #33 0x00000000008452cb in Ffuncall (nargs=5, args=0x7fffffffc740) at ../../src/eval.c:2796 #34 0x0000000000844c98 in call4 (fn=XIL(0x7ffff2eda6a0), arg1=XIL(0x13b67b4), arg2=XIL(0x13b67b4), arg3=XIL(0x30), arg4=XIL(0x30)) at ../../src/eval.c:2676 #35 0x0000000000880f40 in Fload (file=XIL(0x13354d4), noerror=XIL(0x7ffff2edac10), nomessage=XIL(0x7ffff2edaa68), nosuffix=XIL(0), must_suffix=XIL(0)) at ../../src/lread.c:1376 #36 0x0000000000845883 in funcall_subr (subr=0xe11c40 <Sload>, numargs=3, args=0x7fffffffcaf8) at ../../src/eval.c:2879 #37 0x0000000000845287 in Ffuncall (nargs=4, args=0x7fffffffcaf0) at ../../src/eval.c:2794 #38 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff422855c), vector=XIL(0x7ffff42282c5), maxdepth=make_fixnum(18), args_template=make_fixnum(769), nargs=3, args=0x7fffffffd0d8) at ../../src/bytecode.c:633 #39 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff4228295), nargs=3, arg_vector=0x7fffffffd0c0) at ../../src/eval.c:2989 #40 0x00000000008452cb in Ffuncall (nargs=4, args=0x7fffffffd0b8) at ../../src/eval.c:2796 #41 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff4229434), vector=XIL(0x7ffff42254f5), maxdepth=make_fixnum(14), args_template=make_fixnum(0), nargs=0, args=0x7fffffffdbf8) at ../../src/bytecode.c:633 #42 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff42254c5), nargs=0, arg_vector=0x7fffffffdbf8) at ../../src/eval.c:2989 #43 0x00000000008452cb in Ffuncall (nargs=1, args=0x7fffffffdbf0) at ../../src/eval.c:2796 #44 0x000000000089cd03 in exec_byte_code (bytestr=XIL(0x7ffff422a0fc), vector=XIL(0x7ffff4229605), maxdepth=make_fixnum(12), args_template=make_fixnum(0), nargs=0, args=0x7fffffffe230) at ../../src/bytecode.c:633 #45 0x0000000000845f0b in funcall_lambda (fun=XIL(0x7ffff42295d5), nargs=0, arg_vector=0x7fffffffe230) at ../../src/eval.c:2989 #46 0x0000000000845b42 in apply_lambda (fun=XIL(0x7ffff42295d5), args=XIL(0), count=4) at ../../src/eval.c:2926 #47 0x0000000000843d3e in eval_sub (form=XIL(0x7ffff4385a83)) at ../../src/eval.c:2318 #48 0x00000000008430ce in Feval (form=XIL(0x7ffff4385a83), lexical=XIL(0)) at ../../src/eval.c:2102 #49 0x0000000000764b7f in top_level_2 () at ../../src/keyboard.c:1100 #50 0x000000000084126b in internal_condition_case (bfun=0x764b5c <top_level_2>, handlers=XIL(0x90), hfun=0x76455b <cmd_error>) at ../../src/eval.c:1355 #51 0x0000000000764bc7 in top_level_1 (ignore=XIL(0)) at ../../src/keyboard.c:1108 #52 0x000000000084071f in internal_catch (tag=XIL(0xd200), func=0x764b81 <top_level_1>, arg=XIL(0)) at ../../src/eval.c:1116 #53 0x0000000000764aa6 in command_loop () at ../../src/keyboard.c:1069 #54 0x0000000000764042 in recursive_edit_1 () at ../../src/keyboard.c:714 #55 0x000000000076423a in Frecursive_edit () at ../../src/keyboard.c:786 #56 0x00000000007603bd in main (argc=2, argv=0x7fffffffe7a8) at ../../src/emacs.c:2035 Lisp Backtrace: "load" (0xffffa3c8) "custom-load-symbol" (0xffffa958) "custom-theme-set-variables" (0xffffaef8) "apply" (0xffffb518) "custom-set-variables" (0xffffb930) "eval-buffer" (0xffffc1d0) "load-with-code-conversion" (0xffffc748) "load" (0xffffcaf8) "startup--load-user-init-file" (0xffffd0c0) "command-line" (0xffffdbf8) "normal-top-level" (0xffffe230) (gdb) martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-05 8:32 ` martin rudalics @ 2020-05-05 14:58 ` Eli Zaretskii 2020-05-05 16:57 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2020-05-05 14:58 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > From: martin rudalics <rudalics@gmx.at> > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > Date: Tue, 5 May 2020 10:32:31 +0200 > > Below find two backtraces with emacs -Q where PRODUCE_GLYPHS here sets > inhibit_free_realized_faces outside the scope of redisplay_internal > (that is, while redisplaying_p is nil) such that these will not get > caught by the unbind form in redisplay_internal. Thanks. All of these enter redisplay via echo_area_display. That calls redisplay_internal, but only after it displays the mini-window. However, I had my doubts regarding the accuracy of my mental model. Namely, the part where I said that inhibit_free_realized_faces should never be non-zero outside of redisplay. So I looked at the code and its history, and it turns out I was wrong: the line that sets the flag in PRODUCE_GLYPHS was there since Emacs 21, and I see the flag set to non-zero all the way back to Emacs 22.1 (and probably earlier). So it sounds like we always were running like that. Therefore, I must turn the table and ask you to please describe in more detail, preferably with Lisp snippets to try, how the fact that this flag is non-zero gets in the way of something we need to do with faces, both in this bug and the other one you mentioned. I'd like to understand better how this flag interferes in these use cases. Thanks (and sorry for spreading misinformation: I was somehow confident that it was myself who added the setting of inhibit_free_realized_faces in PRODUCE_GLYPHS, but the truth is that it was Gerd, long ago). ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-05 14:58 ` Eli Zaretskii @ 2020-05-05 16:57 ` martin rudalics 2020-05-05 17:11 ` Eli Zaretskii 2020-05-06 14:44 ` Eli Zaretskii 0 siblings, 2 replies; 97+ messages in thread From: martin rudalics @ 2020-05-05 16:57 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 >> Below find two backtraces with emacs -Q where PRODUCE_GLYPHS here sets >> inhibit_free_realized_faces outside the scope of redisplay_internal >> (that is, while redisplaying_p is nil) such that these will not get >> caught by the unbind form in redisplay_internal. > > Thanks. All of these enter redisplay via echo_area_display. That > calls redisplay_internal, but only after it displays the mini-window. > > However, I had my doubts regarding the accuracy of my mental model. > Namely, the part where I said that inhibit_free_realized_faces should > never be non-zero outside of redisplay. So I looked at the code and > its history, and it turns out I was wrong: the line that sets the flag > in PRODUCE_GLYPHS was there since Emacs 21, and I see the flag set to > non-zero all the way back to Emacs 22.1 (and probably earlier). C-x v l told me it was commit 18155a1d5a93cec23255becab15f26e77cace9e7 Author: Richard M. Stallman <rms@gnu.org> Date: Thu Aug 29 14:41:28 2002 +0000 (PRODUCE_GLYPHS): Set inhibit_free_realized_faces when iterator is adding glyphs to a glyph matrix. but I didn't dig any further. > So it sounds like we always were running like that. Therefore, I must > turn the table and ask you to please describe in more detail, > preferably with Lisp snippets to try, how the fact that this flag is > non-zero gets in the way of something we need to do with faces, both > in this bug and the other one you mentioned. I'd like to understand > better how this flag interferes in these use cases. With Bug#40639 and Bug#41071 the situation is simple: The internal border changed face but when we enter init_iterator inhibit_free_realized_faces is true and we don't handle it. Redisplay takes care of the face change for normal frames only when it evaluates their titles and that strange incident is what I used to fix these bugs on master. The situation with the present bug is that I rewrote 'window-text-pixel-size' as DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_size, 0, 6, 0, doc: /* Return the size of the text of WINDOW's buffer in pixels. WINDOW must be a live window and defaults to the selected one. The return value is a cons of the maximum pixel-width of any text line and the maximum pixel-height of all text lines. The optional argument FROM, if non-nil, specifies the first text position and defaults to the minimum accessible position of the buffer. If FROM is t, use the minimum accessible position that starts a non-empty line. TO, if non-nil, specifies the last text position and defaults to the maximum accessible position of the buffer. If TO is t, use the maximum accessible position that ends a non-empty line. The optional argument X-LIMIT, if non-nil, specifies the maximum text width that can be returned. X-LIMIT nil or omitted, means to use the pixel-width of WINDOW's body; use this if you want to know how high WINDOW should be become in order to fit all of its buffer's text with the width of WINDOW unaltered. Use the maximum width WINDOW may assume if you intend to change WINDOW's width. In any case, text whose x-coordinate is beyond X-LIMIT is ignored. Since calculating the width of long lines can take some time, it's always a good idea to make this argument as small as possible; in particular, if the buffer contains long lines that shall be truncated anyway. The optional argument Y-LIMIT, if non-nil, specifies the maximum text height (excluding the height of the mode- or header-line, if any) that can be returned. Text lines whose y-coordinate is beyond Y-LIMIT are ignored. Since calculating the text height of a large buffer can take some time, it makes sense to specify this argument if the size of the buffer is large or unknown. Optional argument MODE-AND-HEADER-LINE nil or omitted means do not include the height of the mode- or header-line of WINDOW in the return value. If it is either the symbol `mode-line' or `header-line', include only the height of that line, if present, in the return value. If t, include the height of both, if present, in the return value. */) (Lisp_Object window, Lisp_Object from, Lisp_Object to, Lisp_Object x_limit, Lisp_Object y_limit, Lisp_Object mode_and_header_line) { struct window *w = decode_live_window (window); Lisp_Object buffer = w->contents; struct buffer *b; struct it it; struct buffer *old_b = NULL; ptrdiff_t start, end, pos; struct text_pos startp; void *itdata = NULL; int c, max_x = 0, max_y = 0, x = 0, y = 0; CHECK_BUFFER (buffer); b = XBUFFER (buffer); if (b != current_buffer) { old_b = current_buffer; set_buffer_internal (b); } if (NILP (from)) start = BEGV; else if (EQ (from, Qt)) { start = pos = BEGV; while ((pos++ < ZV) && (c = FETCH_CHAR (pos)) && (c == ' ' || c == '\t' || c == '\n' || c == '\r')) start = pos; while ((pos-- > BEGV) && (c = FETCH_CHAR (pos)) && (c == ' ' || c == '\t')) start = pos; } else start = clip_to_bounds (BEGV, fix_position (from), ZV); if (NILP (to)) end = ZV; else if (EQ (to, Qt)) { end = pos = ZV; while ((pos-- > BEGV) && (c = FETCH_CHAR (pos)) && (c == ' ' || c == '\t' || c == '\n' || c == '\r')) end = pos; while ((pos++ < ZV) && (c = FETCH_CHAR (pos)) && (c == ' ' || c == '\t')) end = pos; } else end = clip_to_bounds (start, fix_position (to), ZV); if (!NILP (x_limit) && RANGED_FIXNUMP (0, x_limit, INT_MAX)) max_x = XFIXNUM (x_limit); if (NILP (y_limit)) max_y = INT_MAX; else if (RANGED_FIXNUMP (0, y_limit, INT_MAX)) max_y = XFIXNUM (y_limit); /* Recompute faces if needed. */ if (face_change || XFRAME (w->frame)->face_change) { Lisp_Object window_header_line_format = window_parameter (w, Qheader_line_format); Lisp_Object window_tab_line_format = window_parameter (w, Qtab_line_format); Lisp_Object window_mode_line_format = window_parameter (w, Qmode_line_format); if (((EQ (mode_and_header_line, Qheader_line) || EQ (mode_and_header_line, Qt)) && !EQ (window_header_line_format, Qnone) && (!NILP (window_header_line_format) || !NILP (BVAR (current_buffer, header_line_format)))) || ((EQ (mode_and_header_line, Qtab_line) || EQ (mode_and_header_line, Qt)) && !EQ (window_tab_line_format, Qnone) && (!NILP (window_tab_line_format) || !NILP (BVAR (current_buffer, tab_line_format)))) || ((EQ (mode_and_header_line, Qmode_line) || EQ (mode_and_header_line, Qt)) && !EQ (window_mode_line_format, Qnone) && (!NILP (window_mode_line_format) || !NILP (BVAR (current_buffer, mode_line_format))))) { if (face_change) { face_change = false; XFRAME (w->frame)->face_change = 0; free_all_realized_faces (Qnil); } else { XFRAME (w->frame)->face_change = 0; free_all_realized_faces (w->frame); } } } itdata = bidi_shelve_cache (); SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start)); start_display (&it, w, startp); /* It makes no sense to measure dimensions of region of text that crosses the point where bidi reordering changes scan direction. By using unidirectional movement here we at least support the use case of measuring regions of text that have a uniformly R2L directionality, and regions that begin and end in text of the same directionality. */ it.bidi_p = false; int move_op = MOVE_TO_POS | MOVE_TO_Y; int to_x = -1; if (!NILP (x_limit)) { it.last_visible_x = max_x; /* Actually, we never want move_it_to stop at to_x. But to make sure that move_it_in_display_line_to always moves far enough, we set to_x to INT_MAX and specify MOVE_TO_X. */ move_op |= MOVE_TO_X; to_x = INT_MAX; } void *it2data = NULL; struct it it2; SAVE_IT (it2, it, it2data); x = move_it_to (&it, end, to_x, max_y, -1, move_op); /* We could have a display property at END, in which case asking move_it_to to stop at END will overshoot and stop at position after END. So we try again, stopping before END, and account for the width of the last buffer position manually. */ if (IT_CHARPOS (it) > end) { end--; RESTORE_IT (&it, &it2, it2data); x = move_it_to (&it, end, to_x, max_y, -1, move_op); /* Add the width of the thing at TO, but only if we didn't overshoot it; if we did, it is already accounted for. Also, account for the height of the thing at TO. */ if (IT_CHARPOS (it) == end) { x += it.pixel_width; it.max_ascent = max (it.max_ascent, it.ascent); it.max_descent = max (it.max_descent, it.descent); } } if (!NILP (x_limit)) { /* Don't return more than X-LIMIT. */ if (x > max_x) x = max_x; } /* Subtract height of header-line which was counted automatically by start_display. */ y = it.current_y + it.max_ascent + it.max_descent - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); /* Don't return more than Y-LIMIT. */ if (y > max_y) y = max_y; if (EQ (mode_and_header_line, Qtab_line) || EQ (mode_and_header_line, Qt)) { Lisp_Object window_tab_line_format = window_parameter (w, Qtab_line_format); if (!EQ (window_tab_line_format, Qnone) && (!NILP (window_tab_line_format) || !NILP (BVAR (current_buffer, tab_line_format)))) /* Re-add height of tab-line as requested. */ y = y + display_mode_line (w, TAB_LINE_FACE_ID, NILP (window_tab_line_format) ? BVAR (current_buffer, tab_line_format) : window_tab_line_format); } if (EQ (mode_and_header_line, Qheader_line) || EQ (mode_and_header_line, Qt)) { Lisp_Object window_header_line_format = window_parameter (w, Qheader_line_format); if (!EQ (window_header_line_format, Qnone) && (!NILP (window_header_line_format) || !NILP (BVAR (current_buffer, header_line_format)))) /* Re-add height of header-line as requested. */ y = y + display_mode_line (w, HEADER_LINE_FACE_ID, NILP (window_header_line_format) ? BVAR (current_buffer, header_line_format) : window_header_line_format); } if (EQ (mode_and_header_line, Qmode_line) || EQ (mode_and_header_line, Qt)) { Lisp_Object window_mode_line_format = window_parameter (w, Qmode_line_format); if (!EQ (window_mode_line_format, Qnone) && (!NILP (window_mode_line_format) || !NILP (BVAR (current_buffer, mode_line_format)))) /* Add height of mode-line as requested. */ y = y + display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w), NILP (window_mode_line_format) ? BVAR (current_buffer, mode_line_format) : window_mode_line_format); } bidi_unshelve_cache (itdata, false); if (old_b) set_buffer_internal (old_b); return Fcons (make_fixnum (x), make_fixnum (y)); } This takes any face change into consideration and works. But it obviously disregards inhibit_free_realized_faces and so I'm not sure whether it's TRT (rather, I'm quite confident that it is not TRT). At the very least I probably should set windows_or_buffers_changed. There is this comment in redisplay_internal /* If face_change, init_iterator will free all realized faces, which includes the faces referenced from current matrices. So, we can't reuse current matrices in this case. */ if (face_change) windows_or_buffers_changed = 47; which hints at that (without considering that f->face_change is not handled there). > Thanks (and sorry for spreading misinformation: I was somehow > confident that it was myself who added the setting of > inhibit_free_realized_faces in PRODUCE_GLYPHS, but the truth is that > it was Gerd, long ago). Nevertheless, the fact that inhibit_free_realized_faces is true when entering the iterator after a face change is IMO a bug. We apparently always run the iterator with the old faces first. Only after we have (incidentally?) detected some change that forces us to "retry", we have redisplay set inhibit_free_realized_faces to false itself and the face change will get applied in the next iteration. If so, the outcome of the previous iterations gets lost if a face changed there. Does such a strategy give us any gains? Again, the question I tried to ask earlier was: Does a current matrix in between two redisplays rely on the old realized faces? If so, the answer is that inhibit_free_realized_faces should be always true but for the small window within retrying in redisplay_internal. And maybe somewhere at the beginning of redisplay when a face change occurred for the window's frame and we clear all matrices therefore and avoid any redisplay optimizations. In either case, it strikes me as a strange idea that redisplay_internal saves and restores the value of a variable which is apparently always true when it is entered (I suppose redisplay_internal is not re-entrant given /* I don't think this happens but let's be paranoid. */ if (redisplaying_p) return; ) but maybe there are exceptions I don't know. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-05 16:57 ` martin rudalics @ 2020-05-05 17:11 ` Eli Zaretskii 2020-05-06 6:50 ` martin rudalics 2020-05-06 14:44 ` Eli Zaretskii 1 sibling, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2020-05-05 17:11 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Tue, 5 May 2020 18:57:06 +0200 > > With Bug#40639 and Bug#41071 the situation is simple: The internal > border changed face but when we enter init_iterator > inhibit_free_realized_faces is true and we don't handle it. Why do we need to enter init_iterator when the border face changes? And why do we need init_iterator to handle the face change? Thanks for the rest, I will look at that soon. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-05 17:11 ` Eli Zaretskii @ 2020-05-06 6:50 ` martin rudalics 2020-05-06 9:27 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2020-05-06 6:50 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > Why do we need to enter init_iterator when the border face changes? > And why do we need init_iterator to handle the face change? If our only tool is a hammer ... Or should we call 'clear-face-cache' or 'redraw-display' whenever changing the border face? martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-06 6:50 ` martin rudalics @ 2020-05-06 9:27 ` Eli Zaretskii 2020-05-06 9:44 ` martin rudalics 2020-05-06 14:16 ` Eli Zaretskii 0 siblings, 2 replies; 97+ messages in thread From: Eli Zaretskii @ 2020-05-06 9:27 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 On May 6, 2020 9:50:06 AM GMT+03:00, martin rudalics <rudalics@gmx.at> wrote: > > Why do we need to enter init_iterator when the border face changes? > > And why do we need init_iterator to handle the face change? > > If our only tool is a hammer ... Or should we call 'clear-face-cache' > or > 'redraw-display' whenever changing the border face? > > martin I simply don't yet understand why updating the frame decorations that have nothing to do with text layout needs init_iterator to run. What am I missing? Redisplay doesn't in general redraw the whole frame, it only redraws windows. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-06 9:27 ` Eli Zaretskii @ 2020-05-06 9:44 ` martin rudalics 2020-05-06 14:16 ` Eli Zaretskii 1 sibling, 0 replies; 97+ messages in thread From: martin rudalics @ 2020-05-06 9:44 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > I simply don't yet understand why updating the frame decorations that > have nothing to do with text layout needs init_iterator to run. What > am I missing? Redisplay doesn't in general redraw the whole frame, it > only redraws windows. I don't understand either. Fact is, that init_iterator is the only agent within redisplay that frees realized faces and causes the new border face to be realized. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-06 9:27 ` Eli Zaretskii 2020-05-06 9:44 ` martin rudalics @ 2020-05-06 14:16 ` Eli Zaretskii 2020-05-07 8:34 ` martin rudalics 1 sibling, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2020-05-06 14:16 UTC (permalink / raw) To: rudalics; +Cc: jonas, 38181 > Date: Wed, 06 May 2020 12:27:52 +0300 > From: Eli Zaretskii <eliz@gnu.org> > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > > I simply don't yet understand why updating the frame decorations that have nothing to do with text layout needs init_iterator to run. What am I missing? Redisplay doesn't in general redraw the whole frame, it only redraws windows. Answering my own question: because the clear_under_internal_border method, which redraws the internal border, is called from redisplay_internal. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-06 14:16 ` Eli Zaretskii @ 2020-05-07 8:34 ` martin rudalics 2020-05-07 12:41 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2020-05-07 8:34 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 >> I simply don't yet understand why updating the frame decorations that have nothing to do with text layout needs init_iterator to run. What am I missing? Redisplay doesn't in general redraw the whole frame, it only redraws windows. > > Answering my own question: because the clear_under_internal_border > method, which redraws the internal border, is called from > redisplay_internal. That's only a secondary issue, I think. clear_under_internal_border is called from so many places. The real reason is, as I tried to explain before, to update the basic faces, however that is accomplished. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-07 8:34 ` martin rudalics @ 2020-05-07 12:41 ` Eli Zaretskii 0 siblings, 0 replies; 97+ messages in thread From: Eli Zaretskii @ 2020-05-07 12:41 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Thu, 7 May 2020 10:34:40 +0200 > > >> I simply don't yet understand why updating the frame decorations that have nothing to do with text layout needs init_iterator to run. What am I missing? Redisplay doesn't in general redraw the whole frame, it only redraws windows. > > > > Answering my own question: because the clear_under_internal_border > > method, which redraws the internal border, is called from > > redisplay_internal. > > That's only a secondary issue, I think. clear_under_internal_border is > called from so many places. The real reason is, as I tried to explain > before, to update the basic faces, however that is accomplished. What puzzled me was how init_iterator was involved: without its being called at least once, the call to clear_under_internal_border will not use the updated faces. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-05 16:57 ` martin rudalics 2020-05-05 17:11 ` Eli Zaretskii @ 2020-05-06 14:44 ` Eli Zaretskii 2020-05-07 8:34 ` martin rudalics 1 sibling, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2020-05-06 14:44 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Tue, 5 May 2020 18:57:06 +0200 > > > So it sounds like we always were running like that. Therefore, I must > > turn the table and ask you to please describe in more detail, > > preferably with Lisp snippets to try, how the fact that this flag is > > non-zero gets in the way of something we need to do with faces, both > > in this bug and the other one you mentioned. I'd like to understand > > better how this flag interferes in these use cases. > > With Bug#40639 and Bug#41071 the situation is simple: The internal > border changed face but when we enter init_iterator > inhibit_free_realized_faces is true and we don't handle it. Can you show the backtrace from this call to init_iterator? If it is called directly or indirectly from redisplay_internal, the inhibit_free_realized_faces flag should be reset to zero. So I'm guessing it is called in some other way. That other way is not necessarily the situation which should solve the delayed face refreshing, since the corresponding parts of the frame will not be redrawn until we enter redisplay_internal anyway, right? Or am I missing something. > if (face_change) > { > face_change = false; > XFRAME (w->frame)->face_change = 0; > free_all_realized_faces (Qnil); > } > else > { > XFRAME (w->frame)->face_change = 0; > free_all_realized_faces (w->frame); > } You don't really need to free the faces everywhere here, only for the window W's frame, right? I think we shouldn't throw away face caches of other frames in this situation, it's too radical. > This takes any face change into consideration and works. But it > obviously disregards inhibit_free_realized_faces and so I'm not sure > whether it's TRT (rather, I'm quite confident that it is not TRT). I think the only situation where it can hurt is when this code is called while redisplay_internal runs. IOW, we need to test the value of redisplaying_p. > At the very least I probably should set windows_or_buffers_changed. > There is this comment in redisplay_internal > > /* If face_change, init_iterator will free all realized faces, which > includes the faces referenced from current matrices. So, we > can't reuse current matrices in this case. */ > if (face_change) > windows_or_buffers_changed = 47; > > which hints at that (without considering that f->face_change is not > handled there). The call to free_all_realized_faces invalidates the current matrices of all the windows on the frame, so the stale face IDs will not be used after that on that frame, and therefore nothing else needs to be done in that case. If _all_ the face caches are discarded on all frames, we need windows_or_buffers_changed to force redisplay_internal consider more than just the selected frame. So if you modify your code to free faces only on the frame of the window for which you compute the mode-line height, the problem with windows_or_buffers_changed will disappear. > Nevertheless, the fact that inhibit_free_realized_faces is true when > entering the iterator after a face change is IMO a bug. We apparently > always run the iterator with the old faces first. Only after we have > (incidentally?) detected some change that forces us to "retry", we have > redisplay set inhibit_free_realized_faces to false itself and the face > change will get applied in the next iteration. If so, the outcome of > the previous iterations gets lost if a face changed there. Does such a > strategy give us any gains? I don't think I follow. redisplay_internal resets the inhibit_free_realized_faces flag to zero near its beginning. It is true that we also reset it when we retry, but the first try doesn't bypass this resetting. Am I missing something? > Again, the question I tried to ask earlier was: Does a current matrix in > between two redisplays rely on the old realized faces? Of course it does. The glyph matrices don't hold any face information, they only hold the ID of each face, and the ID is just the index of the face's cache slot. If the face cache is thrown away, we will not be able to use the current matrix. The current matrix is used for the following purposes: . outside of the redisplay cycle, for redisplaying portions of windows when we get expose events -- in this case we simply write to the glass the relevant portions of the matrix, without reproducing it . during a redisplay cycle, for decisions about redisplay optimizations . at the end of a redisplay cycle, for comparison with the desired matrix, which is needed for figuring out what to write to the glass For the first purpose, we have the following defenses: . expose_frame: if (FRAME_FACE_CACHE (f) == NULL || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL) { redisplay_trace ("expose_frame no faces\n"); return; } . expose_window (called by expose_frame): if (w->current_matrix == NULL) return false; So this case is covered, i.e. you can call free_all_realized_faces, and the next expose event will be handled correctly. The other two are the reason why we set the inhibit_free_realized_faces in PRODUCE_GLYPHS: the flag must be set during redisplay, until update_frame finished its job. Otherwise we will sooner or later crash. So I think each function that might need to notice face changes as soon as they happened, should be able to reset inhibit_free_realized_faces, provided that (a) it makes sure redisplaying_p is zero, and (b) it only does that if necessary and for a single frame. The latter part is because clearing the face cache will cause all the move_it_* functions to work harder, because they will have to recompute all the faces. > If so, the answer is that inhibit_free_realized_faces should be > always true but for the small window within retrying in > redisplay_internal. I don't think I agree, but maybe I'm missing something. > In either case, it strikes me as a strange idea that redisplay_internal > saves and restores the value of a variable which is apparently always > true when it is entered (I suppose redisplay_internal is not re-entrant > given > > /* I don't think this happens but let's be paranoid. */ > if (redisplaying_p) > return; redisplay_internal is non-reentrant, but I see no harm in restoring the value on exit. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-06 14:44 ` Eli Zaretskii @ 2020-05-07 8:34 ` martin rudalics 2020-05-10 14:33 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2020-05-07 8:34 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 >> With Bug#40639 and Bug#41071 the situation is simple: The internal >> border changed face but when we enter init_iterator >> inhibit_free_realized_faces is true and we don't handle it. > > Can you show the backtrace from this call to init_iterator? I run emacs -Q and evaluate there the following form (progn (set-face-background 'internal-border "red") (select-window (display-buffer-in-child-frame (get-buffer-create "*scratch*") '((child-frame-parameters . ((left . 100) (top . 100) (height . 10) (width . 20) (minibuffer . nil) (internal-border-width . 50))))))) Now _if I remove the following two lines_ if ((IT)->glyph_row != NULL) \ inhibit_free_realized_faces = true; \ from PRODUCE_GLYPHS, evaluating the form above does pick up the face triggered by XFRAME (w->frame)->face_change true as #0 0x0000000000463cbf in init_iterator (it=0x7fffffff8c60, w=0x193e060, charpos=1, bytepos=1, row=0x1947f90, base_face_id=DEFAULT_FACE_ID) at ../../src/xdisp.c:2975 #1 0x00000000004652e8 in start_display (it=0x7fffffff8c60, w=0x193e060, pos=...) at ../../src/xdisp.c:3298 #2 0x0000000000497468 in try_window (window=XIL(0x193e065), pos=..., flags=1) at ../../src/xdisp.c:19120 #3 0x00000000004941e9 in redisplay_window (window=XIL(0x193e065), just_this_one_p=false) at ../../src/xdisp.c:18544 #4 0x000000000048be75 in redisplay_window_0 (window=XIL(0x193e065)) at ../../src/xdisp.c:16258 #5 0x00000000007af751 in internal_condition_case_1 (bfun=0x48be33 <redisplay_window_0>, arg=XIL(0x193e065), handlers=XIL(0x7ffff3e98ee3), hfun=0x48bdfb <redisplay_window_error>) at ../../src/eval.c:1379 #6 0x000000000048bdcd in redisplay_windows (window=XIL(0x193e065)) at ../../src/xdisp.c:16238 #7 0x000000000048a7fb in redisplay_internal () at ../../src/xdisp.c:15706 #8 0x00000000004883f9 in redisplay () at ../../src/xdisp.c:14933 #9 0x000000000064edbd in read_char (commandflag=1, map=XIL(0x17e4f93), prev_event=XIL(0), used_mouse_menu=0x7fffffffe0ff, end_time=0x0) at ../../src/keyboard.c:2493 #10 0x0000000000661ce5 in read_key_sequence (keybuf=0x7fffffffe290, prompt=XIL(0), dont_downcase_last=false, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=false) at ../../src/keyboard.c:9553 #11 0x000000000064b283 in command_loop_1 () at ../../src/keyboard.c:1350 #12 0x00000000007af676 in internal_condition_case (bfun=0x64ae07 <command_loop_1>, handlers=XIL(0x90), hfun=0x64a416 <cmd_error>) at ../../src/eval.c:1355 #13 0x000000000064a9ec in command_loop_2 (ignore=XIL(0)) at ../../src/keyboard.c:1091 #14 0x00000000007aeb2a in internal_catch (tag=XIL(0xd110), func=0x64a9bf <command_loop_2>, arg=XIL(0)) at ../../src/eval.c:1116 #15 0x000000000064a98a in command_loop () at ../../src/keyboard.c:1070 #16 0x0000000000649efd in recursive_edit_1 () at ../../src/keyboard.c:714 #17 0x000000000064a0f5 in Frecursive_edit () at ../../src/keyboard.c:786 #18 0x00000000006404fe in main (argc=4, argv=0x7fffffffe788) at ../../src/emacs.c:2054 Lisp Backtrace: "redisplay_internal (C function)" (0x0) (gdb) c With PRODUCE_GLYPHS unaltered, that breakpoint does _not_ trigger. Only if I set frame titles for child frames (as I do on master now) I can get a backtrace like the below #0 0x00000000004821dc in init_iterator (it=0x7fffffffb4a0, w=0x1a4b800, charpos=-1, bytepos=-1, row=0x0, base_face_id=DEFAULT_FACE_ID) at ../../src/xdisp.c:2988 #1 0x00000000004a575b in gui_consider_frame_title (frame=XIL(0x1a5e8f5)) at ../../src/xdisp.c:12447 #2 0x00000000004a5c07 in prepare_menu_bars () at ../../src/xdisp.c:12544 #3 0x00000000004aaeaf in redisplay_internal () at ../../src/xdisp.c:15392 #4 0x00000000004a9aeb in redisplay () at ../../src/xdisp.c:14977 #5 0x0000000000768eb6 in read_char (commandflag=1, map=XIL(0x1c5c3d3), prev_event=XIL(0), used_mouse_menu=0x7fffffffe10f, end_time=0x0) at ../../src/keyboard.c:2493 #6 0x00000000007800e3 in read_key_sequence (keybuf=0x7fffffffe2a0, prompt=XIL(0), dont_downcase_last=false, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=false) at ../../src/keyboard.c:9547 #7 0x000000000076549a in command_loop_1 () at ../../src/keyboard.c:1350 #8 0x000000000084133d in internal_condition_case (bfun=0x76501e <command_loop_1>, handlers=XIL(0x90), hfun=0x76462d <cmd_error>) at ../../src/eval.c:1355 #9 0x0000000000764c03 in command_loop_2 (ignore=XIL(0)) at ../../src/keyboard.c:1091 #10 0x00000000008407f1 in internal_catch (tag=XIL(0xd200), func=0x764bd6 <command_loop_2>, arg=XIL(0)) at ../../src/eval.c:1116 #11 0x0000000000764ba1 in command_loop () at ../../src/keyboard.c:1070 #12 0x0000000000764114 in recursive_edit_1 () at ../../src/keyboard.c:714 #13 0x000000000076430c in Frecursive_edit () at ../../src/keyboard.c:786 #14 0x000000000076048f in main (argc=3, argv=0x7fffffffe798) at ../../src/emacs.c:2035 which also picks up the change of the internal border's background. With an unaltered release I can't get init_iterator to notice the face change without, in some clumsy way, switching to that child frame with the mouse or something the like. Disclaimer: In all those runs I do not know whether the (set-face-background 'internal-border "red") set the face_change flag or something else did. >> if (face_change) >> { >> face_change = false; >> XFRAME (w->frame)->face_change = 0; >> free_all_realized_faces (Qnil); >> } >> else >> { >> XFRAME (w->frame)->face_change = 0; >> free_all_realized_faces (w->frame); >> } > > You don't really need to free the faces everywhere here, only for the > window W's frame, right? Right. > I think we shouldn't throw away face caches > of other frames in this situation, it's too radical. Agreed. > I think the only situation where it can hurt is when this code is > called while redisplay_internal runs. IOW, we need to test the value > of redisplaying_p. OK. >> At the very least I probably should set windows_or_buffers_changed. >> There is this comment in redisplay_internal >> >> /* If face_change, init_iterator will free all realized faces, which >> includes the faces referenced from current matrices. So, we >> can't reuse current matrices in this case. */ >> if (face_change) >> windows_or_buffers_changed = 47; >> >> which hints at that (without considering that f->face_change is not >> handled there). > > The call to free_all_realized_faces invalidates the current matrices > of all the windows on the frame, so the stale face IDs will not be > used after that on that frame, and therefore nothing else needs to be > done in that case. If _all_ the face caches are discarded on all > frames, we need windows_or_buffers_changed to force redisplay_internal > consider more than just the selected frame. So if you modify your > code to free faces only on the frame of the window for which you > compute the mode-line height, the problem with > windows_or_buffers_changed will disappear. OK. >> Nevertheless, the fact that inhibit_free_realized_faces is true when >> entering the iterator after a face change is IMO a bug. We apparently >> always run the iterator with the old faces first. Only after we have >> (incidentally?) detected some change that forces us to "retry", we have >> redisplay set inhibit_free_realized_faces to false itself and the face >> change will get applied in the next iteration. If so, the outcome of >> the previous iterations gets lost if a face changed there. Does such a >> strategy give us any gains? > > I don't think I follow. redisplay_internal resets the > inhibit_free_realized_faces flag to zero near its beginning. It is > true that we also reset it when we retry, but the first try doesn't > bypass this resetting. Am I missing something? It might have been a wrong conclusion on my side. Maybe the problem is caused by the fact that face_change is not set by 'set-face-background' and the face change that triggered the backtraces above came from somewhere else. >> Again, the question I tried to ask earlier was: Does a current matrix in >> between two redisplays rely on the old realized faces? > > Of course it does. The glyph matrices don't hold any face > information, they only hold the ID of each face, and the ID is just > the index of the face's cache slot. If the face cache is thrown away, > we will not be able to use the current matrix. So if I set `inhibit-free-realized-faces' to nil at some arbitrary time things may go wrong. > The current matrix is used for the following purposes: > > . outside of the redisplay cycle, for redisplaying portions of > windows when we get expose events -- in this case we simply write > to the glass the relevant portions of the matrix, without > reproducing it > > . during a redisplay cycle, for decisions about redisplay > optimizations > > . at the end of a redisplay cycle, for comparison with the desired > matrix, which is needed for figuring out what to write to the > glass > > For the first purpose, we have the following defenses: > > . expose_frame: > > if (FRAME_FACE_CACHE (f) == NULL > || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL) > { > redisplay_trace ("expose_frame no faces\n"); > return; > } > > . expose_window (called by expose_frame): > > if (w->current_matrix == NULL) > return false; > > So this case is covered, i.e. you can call ... from Elisp, at any time, I presume ... > free_all_realized_faces, > and the next expose event will be handled correctly. > The other two are the reason why we set the > inhibit_free_realized_faces in PRODUCE_GLYPHS: the flag must be set > during redisplay, until update_frame finished its job. Otherwise we > will sooner or later crash. I'm running without this for a couple of days now and it did not crash so far. Sheer luck, I presume. Couldn't PRODUCE_GLYPHS set inhibit_free_realized_faces iff redisplaying_p is true? > So I think each function that might need to notice face changes as > soon as they happened, should be able to reset > inhibit_free_realized_faces, provided that (a) it makes sure > redisplaying_p is zero, and (b) it only does that if necessary and for > a single frame. The latter part is because clearing the face cache > will cause all the move_it_* functions to work harder, because they > will have to recompute all the faces. So it's not so entirely trivial to do that in Elisp. >> If so, the answer is that inhibit_free_realized_faces should be >> always true but for the small window within retrying in >> redisplay_internal. > > I don't think I agree, but maybe I'm missing something. OK. But IIUC so far we do not allow inhibit_free_realized_faces nil outside of redisplay_internal. Unless someone sets 'inhibit-free-realized-faces' which is, in general, to recommended. Right? >> In either case, it strikes me as a strange idea that redisplay_internal >> saves and restores the value of a variable which is apparently always >> true when it is entered (I suppose redisplay_internal is not re-entrant >> given >> >> /* I don't think this happens but let's be paranoid. */ >> if (redisplaying_p) >> return; > > redisplay_internal is non-reentrant, but I see no harm in restoring > the value on exit. If someone sets it to nil now, observing the precautions you gave above, things change radically. We may restore the value to nil, which was hardly the case before. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-07 8:34 ` martin rudalics @ 2020-05-10 14:33 ` Eli Zaretskii 2020-05-11 8:30 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2020-05-10 14:33 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Thu, 7 May 2020 10:34:53 +0200 > > >> With Bug#40639 and Bug#41071 the situation is simple: The internal > >> border changed face but when we enter init_iterator > >> inhibit_free_realized_faces is true and we don't handle it. > > > > Can you show the backtrace from this call to init_iterator? > > I run emacs -Q and evaluate there the following form > > (progn > (set-face-background 'internal-border "red") > (select-window > (display-buffer-in-child-frame > (get-buffer-create "*scratch*") > '((child-frame-parameters > . > ((left . 100) > (top . 100) > (height . 10) > (width . 20) > (minibuffer . nil) > (internal-border-width . 50))))))) > > Now _if I remove the following two lines_ > > if ((IT)->glyph_row != NULL) \ > inhibit_free_realized_faces = true; \ > > from PRODUCE_GLYPHS, evaluating the form above does pick up the face > triggered by > > XFRAME (w->frame)->face_change > > true as > > #0 0x0000000000463cbf in init_iterator (it=0x7fffffff8c60, w=0x193e060, charpos=1, bytepos=1, row=0x1947f90, base_face_id=DEFAULT_FACE_ID) at ../../src/xdisp.c:2975 > #1 0x00000000004652e8 in start_display (it=0x7fffffff8c60, w=0x193e060, pos=...) at ../../src/xdisp.c:3298 > #2 0x0000000000497468 in try_window (window=XIL(0x193e065), pos=..., flags=1) at ../../src/xdisp.c:19120 > #3 0x00000000004941e9 in redisplay_window (window=XIL(0x193e065), just_this_one_p=false) at ../../src/xdisp.c:18544 > #4 0x000000000048be75 in redisplay_window_0 (window=XIL(0x193e065)) at ../../src/xdisp.c:16258 > #5 0x00000000007af751 in internal_condition_case_1 (bfun=0x48be33 <redisplay_window_0>, arg=XIL(0x193e065), handlers=XIL(0x7ffff3e98ee3), hfun=0x48bdfb <redisplay_window_error>) at ../../src/eval.c:1379 > #6 0x000000000048bdcd in redisplay_windows (window=XIL(0x193e065)) at ../../src/xdisp.c:16238 > #7 0x000000000048a7fb in redisplay_internal () at ../../src/xdisp.c:15706 > [...] > With PRODUCE_GLYPHS unaltered, that breakpoint does _not_ trigger. Only > if I set frame titles for child frames (as I do on master now) I can get > a backtrace like the below > > #0 0x00000000004821dc in init_iterator (it=0x7fffffffb4a0, w=0x1a4b800, charpos=-1, bytepos=-1, row=0x0, base_face_id=DEFAULT_FACE_ID) at ../../src/xdisp.c:2988 > #1 0x00000000004a575b in gui_consider_frame_title (frame=XIL(0x1a5e8f5)) at ../../src/xdisp.c:12447 > #2 0x00000000004a5c07 in prepare_menu_bars () at ../../src/xdisp.c:12544 > #3 0x00000000004aaeaf in redisplay_internal () at ../../src/xdisp.c:15392 The second call happens before the first one, so it looks more correct to me. Why did you think you didn't need to set the frame title for child frames? > Disclaimer: In all those runs I do not know whether the > > (set-face-background 'internal-border "red") > > set the face_change flag or something else did. It doesn't. It sets the face_change flag of each frame instead. See internal-set-lisp-face-attribute. > >> Nevertheless, the fact that inhibit_free_realized_faces is true when > >> entering the iterator after a face change is IMO a bug. We apparently > >> always run the iterator with the old faces first. Only after we have > >> (incidentally?) detected some change that forces us to "retry", we have > >> redisplay set inhibit_free_realized_faces to false itself and the face > >> change will get applied in the next iteration. If so, the outcome of > >> the previous iterations gets lost if a face changed there. Does such a > >> strategy give us any gains? > > > > I don't think I follow. redisplay_internal resets the > > inhibit_free_realized_faces flag to zero near its beginning. It is > > true that we also reset it when we retry, but the first try doesn't > > bypass this resetting. Am I missing something? > > It might have been a wrong conclusion on my side. Maybe the problem is > caused by the fact that face_change is not set by 'set-face-background' > and the face change that triggered the backtraces above came from > somewhere else. See above. It could be that we somehow fail to redisplay the child frame thoroughly enough, though. > >> Again, the question I tried to ask earlier was: Does a current matrix in > >> between two redisplays rely on the old realized faces? > > > > Of course it does. The glyph matrices don't hold any face > > information, they only hold the ID of each face, and the ID is just > > the index of the face's cache slot. If the face cache is thrown away, > > we will not be able to use the current matrix. > > So if I set `inhibit-free-realized-faces' to nil at some arbitrary time > things may go wrong. Only if you do that in code that can run while redisplay_internal is doing its job. > > . expose_frame: > > > > if (FRAME_FACE_CACHE (f) == NULL > > || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL) > > { > > redisplay_trace ("expose_frame no faces\n"); > > return; > > } > > > > . expose_window (called by expose_frame): > > > > if (w->current_matrix == NULL) > > return false; > > > > So this case is covered, i.e. you can call > > ... from Elisp, at any time, I presume ... Yes, but not limited to that. > > The other two are the reason why we set the > > inhibit_free_realized_faces in PRODUCE_GLYPHS: the flag must be set > > during redisplay, until update_frame finished its job. Otherwise we > > will sooner or later crash. > > I'm running without this for a couple of days now and it did not crash > so far. Try setting things up such that faces are modified by some Lisp that runs during redisplay, like some :eval form of the mode line or one of the hooks called by the display code. That's how crashes with face = NULL invariably start. > Sheer luck, I presume. Couldn't PRODUCE_GLYPHS set > inhibit_free_realized_faces iff redisplaying_p is true? No, because some functions we call from Lisp actually write into the current matrix. For example, tool-bar-height and tab-bar-height. > > So I think each function that might need to notice face changes as > > soon as they happened, should be able to reset > > inhibit_free_realized_faces, provided that (a) it makes sure > > redisplaying_p is zero, and (b) it only does that if necessary and for > > a single frame. The latter part is because clearing the face cache > > will cause all the move_it_* functions to work harder, because they > > will have to recompute all the faces. > > So it's not so entirely trivial to do that in Elisp. Why do we need to do this in Lisp? > >> If so, the answer is that inhibit_free_realized_faces should be > >> always true but for the small window within retrying in > >> redisplay_internal. > > > > I don't think I agree, but maybe I'm missing something. > > OK. But IIUC so far we do not allow inhibit_free_realized_faces nil > outside of redisplay_internal. Unless someone sets > 'inhibit-free-realized-faces' which is, in general, to recommended. > Right? Yes, but I see no reason not to reset it in other places, provided that we do it carefully and only when absolutely needed. > >> In either case, it strikes me as a strange idea that redisplay_internal > >> saves and restores the value of a variable which is apparently always > >> true when it is entered (I suppose redisplay_internal is not re-entrant > >> given > >> > >> /* I don't think this happens but let's be paranoid. */ > >> if (redisplaying_p) > >> return; > > > > redisplay_internal is non-reentrant, but I see no harm in restoring > > the value on exit. > > If someone sets it to nil now, observing the precautions you gave above, > things change radically. We may restore the value to nil, which was > hardly the case before. That'd be shooting ourselves in the foot during the next redisplay, but it isn't a catastrophe, AFAIU. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-10 14:33 ` Eli Zaretskii @ 2020-05-11 8:30 ` martin rudalics 2020-05-15 15:00 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2020-05-11 8:30 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > The second call happens before the first one, so it looks more correct > to me. Why did you think you didn't need to set the frame title for > child frames? Because on all systems excluding Windows child frames do not show their titles. Calculating something that cannot be displayed doesn't strike me as a good idea. And obviously native tooltip frames which suffer the same problem using (progn (setq x-gtk-use-system-tooltips nil) (set-face-background 'internal-border "red")) would still not display borders correctly. Or should we set their titles too? >> Disclaimer: In all those runs I do not know whether the >> >> (set-face-background 'internal-border "red") >> >> set the face_change flag or something else did. > > It doesn't. It sets the face_change flag of each frame instead. See > internal-set-lisp-face-attribute. This way of setting things confuses me. What is then that global face_change bool needed for? >> It might have been a wrong conclusion on my side. Maybe the problem is >> caused by the fact that face_change is not set by 'set-face-background' >> and the face change that triggered the backtraces above came from >> somewhere else. > > See above. It could be that we somehow fail to redisplay the child > frame thoroughly enough, though. I have not tried yet but I'm convinced that we would fail for a normal frame as well if we didn't set its frame title. This reliance of one (internal border color) upon the conceptually unrelated other (setting the frame title) looks fishy to me and IIRC causes redisplay_internal to initially run with old character sizes until the actual ones get realized when setting the frame title. >> So if I set `inhibit-free-realized-faces' to nil at some arbitrary time >> things may go wrong. > > Only if you do that in code that can run while redisplay_internal is > doing its job. That's what I meant, yes. >> > The other two are the reason why we set the >> > inhibit_free_realized_faces in PRODUCE_GLYPHS: the flag must be set >> > during redisplay, until update_frame finished its job. Otherwise we >> > will sooner or later crash. >> >> I'm running without this for a couple of days now and it did not crash >> so far. > > Try setting things up such that faces are modified by some Lisp that > runs during redisplay, like some :eval form of the mode line or one of > the hooks called by the display code. That's how crashes with face = > NULL invariably start. Not really needed. You convinced me here. >> Sheer luck, I presume. Couldn't PRODUCE_GLYPHS set >> inhibit_free_realized_faces iff redisplaying_p is true? > > No, because some functions we call from Lisp actually write into the > current matrix. For example, tool-bar-height and tab-bar-height. Then there's more to it than the above "the flag must be set during redisplay, until update_frame finished its job"? I'm still confused but that's probably my poor mind. Maybe re-reading your text after a day or so will help. >> So it's not so entirely trivial to do that in Elisp. > > Why do we need to do this in Lisp? Didn't you propose to calculate the mode-line height from 'fit-window-to-buffer'? >> OK. But IIUC so far we do not allow inhibit_free_realized_faces nil >> outside of redisplay_internal. Unless someone sets >> 'inhibit-free-realized-faces' which is, in general, to recommended. >> Right? > > Yes, but I see no reason not to reset it in other places, provided > that we do it carefully and only when absolutely needed. We should say that in the doc-string of 'inhibit-free-realized-faces', maybe. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-11 8:30 ` martin rudalics @ 2020-05-15 15:00 ` Eli Zaretskii 2020-05-16 8:44 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2020-05-15 15:00 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Mon, 11 May 2020 10:30:45 +0200 > > > The second call happens before the first one, so it looks more correct > > to me. Why did you think you didn't need to set the frame title for > > child frames? > > Because on all systems excluding Windows child frames do not show their > titles. Calculating something that cannot be displayed doesn't strike > me as a good idea. And obviously native tooltip frames which suffer the > same problem using > > (progn > (setq x-gtk-use-system-tooltips nil) > (set-face-background 'internal-border "red")) > > would still not display borders correctly. Or should we set their > titles too? Is that a serious question? Anyway, if we want to be able create frames without titles, I guess we should simply arrange for the face cache to be cleared and the basic faces recomputed somewhere near the beginning of redisplay_internal. > >> Disclaimer: In all those runs I do not know whether the > >> > >> (set-face-background 'internal-border "red") > >> > >> set the face_change flag or something else did. > > > > It doesn't. It sets the face_change flag of each frame instead. See > > internal-set-lisp-face-attribute. > > This way of setting things confuses me. What is then that global > face_change bool needed for? For when we don't want to loop over all the frames setting their individual flags, I guess. > I have not tried yet but I'm convinced that we would fail for a normal > frame as well if we didn't set its frame title. This reliance of one > (internal border color) upon the conceptually unrelated other (setting > the frame title) looks fishy to me and IIRC causes redisplay_internal to > initially run with old character sizes until the actual ones get > realized when setting the frame title. "Initially run with old character sizes" doing what? AFAIR, we do the frame title thingy quite early during the redisplay cycle. What is done before that that needs to know about the faces change? > >> Sheer luck, I presume. Couldn't PRODUCE_GLYPHS set > >> inhibit_free_realized_faces iff redisplaying_p is true? > > > > No, because some functions we call from Lisp actually write into the > > current matrix. For example, tool-bar-height and tab-bar-height. > > Then there's more to it than the above "the flag must be set during > redisplay, until update_frame finished its job"? More in what way? This just means we sometimes set it elsewhere as well. > >> So it's not so entirely trivial to do that in Elisp. > > > > Why do we need to do this in Lisp? > > Didn't you propose to calculate the mode-line height from > 'fit-window-to-buffer'? I don't remember, but if so, it doesn't yet mean everything must be done in Lisp. > >> OK. But IIUC so far we do not allow inhibit_free_realized_faces nil > >> outside of redisplay_internal. Unless someone sets > >> 'inhibit-free-realized-faces' which is, in general, to recommended. > >> Right? > > > > Yes, but I see no reason not to reset it in other places, provided > > that we do it carefully and only when absolutely needed. > > We should say that in the doc-string of 'inhibit-free-realized-faces', > maybe. We should? why? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-15 15:00 ` Eli Zaretskii @ 2020-05-16 8:44 ` martin rudalics 2020-05-16 10:46 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2020-05-16 8:44 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 >> And obviously native tooltip frames which suffer the >> same problem using >> >> (progn >> (setq x-gtk-use-system-tooltips nil) >> (set-face-background 'internal-border "red")) >> >> would still not display borders correctly. Or should we set their >> titles too? > > Is that a serious question? Given my current knowledge of the matter, yes. Note that ATK apparently even mandates that tooltip windows have some sort of title set. > Anyway, if we want to be able create frames without titles, Our tooltips are frames and don't have titles so we do that already. >> This way of setting things confuses me. What is then that global >> face_change bool needed for? > > For when we don't want to loop over all the frames setting their > individual flags, I guess. Agreed. But does our code adhere to that idea? gui_set_font_backend sets face_change to true and so does IT_set_frame_parameters (not that it matters here - I'm just talking about the idea) while working on a specific frame. And in x_create_tip_frame and w32_create_tip_frame we even have to save the value of it via face_change_before even though these two functions really should only affect the tip frame about to be created. All other settings of face_change happen in xfaces.c and that one really should know better. > "Initially run with old character sizes" doing what? AFAIR, we do the > frame title thingy quite early during the redisplay cycle. What is > done before that that needs to know about the faces change? Earlier, when debugging this issue, I spent some time stepping through the iterator with the old faces in place and just wondered why the new faces would not get applied. Whenever I'm back there I might be able to tell more. But before that I'd rather wait whether your > I guess we > should simply arrange for the face cache to be cleared and the basic > faces recomputed somewhere near the beginning of redisplay_internal. could be implemented and solve all these problems in one rush. >> >> Sheer luck, I presume. Couldn't PRODUCE_GLYPHS set >> >> inhibit_free_realized_faces iff redisplaying_p is true? >> > >> > No, because some functions we call from Lisp actually write into the >> > current matrix. For example, tool-bar-height and tab-bar-height. >> >> Then there's more to it than the above "the flag must be set during >> redisplay, until update_frame finished its job"? > > More in what way? This just means we sometimes set it elsewhere as > well. With the inevitable consequence that redisplay_internal restores it to true when it exits. Is that the idea behind "we sometimes set it elsewhere as well" or just some sort of collateral damage? >> We should say that in the doc-string of 'inhibit-free-realized-faces', >> maybe. > > We should? why? Because it might help people like me understand this issue. Do you think that my questions are provocative? Maybe they are, but then that's a consequence of the fact that I don't get the picture of our implementation of faces. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2020-05-16 8:44 ` martin rudalics @ 2020-05-16 10:46 ` Eli Zaretskii 0 siblings, 0 replies; 97+ messages in thread From: Eli Zaretskii @ 2020-05-16 10:46 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sat, 16 May 2020 10:44:38 +0200 > > > Anyway, if we want to be able create frames without titles, > > Our tooltips are frames and don't have titles so we do that already. Yes, of course. I hope you don't assume I didn't know that. > >> This way of setting things confuses me. What is then that global > >> face_change bool needed for? > > > > For when we don't want to loop over all the frames setting their > > individual flags, I guess. > > Agreed. But does our code adhere to that idea? gui_set_font_backend > sets face_change to true and so does IT_set_frame_parameters (not that > it matters here - I'm just talking about the idea) while working on a > specific frame. And in x_create_tip_frame and w32_create_tip_frame we > even have to save the value of it via face_change_before even though > these two functions really should only affect the tip frame about to be > created. All other settings of face_change happen in xfaces.c and that > one really should know better. Could you please tell where is this discussion going? Because I no longer understand that. We seem to be talking around the issue, but to what end? Why are these details important for whatever job you have in mind? I'd like to help you do that job, but I'm lost in "twisty little passages, all alike". > > I guess we > > should simply arrange for the face cache to be cleared and the basic > > faces recomputed somewhere near the beginning of redisplay_internal. > > could be implemented and solve all these problems in one rush. All it takes is to call free_all_realized_faces for the frame in question, and then do what init_iterator does: if (FRAME_FACE_CACHE (it->f) == NULL) init_frame_faces (it->f); if (FRAME_FACE_CACHE (it->f)->used == 0) recompute_basic_faces (it->f); > With the inevitable consequence that redisplay_internal restores it to > true when it exits. Is that the idea behind "we sometimes set it > elsewhere as well" or just some sort of collateral damage? I don't think it matters that this flag is set when we are outside redisplay. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 8:57 ` martin rudalics 2019-11-16 10:57 ` Eli Zaretskii @ 2019-11-16 15:27 ` Jonas Bernoulli 2019-11-16 16:19 ` Eli Zaretskii 2019-11-16 19:30 ` martin rudalics 1 sibling, 2 replies; 97+ messages in thread From: Jonas Bernoulli @ 2019-11-16 15:27 UTC (permalink / raw) To: martin rudalics; +Cc: 38181 >> Could fit-window-to-buffer invoke >> 'redisplay' internally, perhaps? > > It could but it's called way too often to warrant such behavior by > default. But we could give it a separate optional argument so users > can avoid the advice. I think Jonas could easily write and a test a > patch along this idea. Again, the mode-line-prettifiers are not the ones who create new buffers and then call fit-buffer-to-window. It's arbitrary other packages that do that. An optional argument therefore would not help because when one of the prettifier modes is active, then each and every third-party caller of fit-buffer-to-window would have to pass that optional argument. This is the advice I currently use: (defvar-local moody--size-hacked-p nil) (defun moody-redisplay (&optional _force &rest _ignored) (unless moody--size-hacked-p (setq moody--size-hacked-p t) (redisplay t))) (advice-add 'fit-window-to-buffer :before #'moody-redisplay) Of course fit-buffer-to-window itself could be changed to do that and it could also be taught to only do so iff the user opted in to doing it. ---- Creating and displaying a new buffer and creating and resizing a new window surely *already* causes a "redisplay" without the programmer having to explicitly call `redisplay'. So if we explicitly tell fit-window-to-buffer to redisplay, then that means that we are redisplaying twice, right? I am under the impression (but this is just wild speculation) that redisplay only performs some of the necessary size calculations before doing the actual redisplaying. But some other calculations (including those concerning the mode-lien) are done only after the actual redisplaying has already happened. That is too late for this redisplay round but causes the values to be in place for all subsequent redisplays. So the fix could be to do the mode-line based calculations earlier? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 15:27 ` Jonas Bernoulli @ 2019-11-16 16:19 ` Eli Zaretskii 2019-11-16 19:30 ` martin rudalics 2019-11-17 16:21 ` Jonas Bernoulli 2019-11-16 19:30 ` martin rudalics 1 sibling, 2 replies; 97+ messages in thread From: Eli Zaretskii @ 2019-11-16 16:19 UTC (permalink / raw) To: Jonas Bernoulli; +Cc: 38181 > From: Jonas Bernoulli <jonas@bernoul.li> > Cc: Eli Zaretskii <eliz@gnu.org>, 38181@debbugs.gnu.org > Date: Sat, 16 Nov 2019 16:27:12 +0100 > > >> Could fit-window-to-buffer invoke > >> 'redisplay' internally, perhaps? > > > > It could but it's called way too often to warrant such behavior by > > default. But we could give it a separate optional argument so users > > can avoid the advice. I think Jonas could easily write and a test a > > patch along this idea. > > Again, the mode-line-prettifiers are not the ones who create new buffers > and then call fit-buffer-to-window. It's arbitrary other packages that > do that. So how are mode-line-prettifiers triggered by those packages creating and showing new buffers? > Of course fit-buffer-to-window itself could be changed to do that and it > could also be taught to only do so iff the user opted in to doing it. Can you suggest a way of knowing that this situation happened? > Creating and displaying a new buffer and creating and resizing a new > window surely *already* causes a "redisplay" without the programmer > having to explicitly call `redisplay'. So if we explicitly tell > fit-window-to-buffer to redisplay, then that means that we are > redisplaying twice, right? Yes. But if you don't call 'redisplay' _before_ fit-window-to-buffer, that function will use stale data about the window's text area height, computed before the mode line was updated. You are right saying that displaying a window causes a redisplay, but keep in mind that redisplay triggered by that happens _after_ the command which enlarged the mode-line height finishes, and by that time fit-window-to-buffer will have already run (using stale window dimensions). > I am under the impression (but this is just wild speculation) that > redisplay only performs some of the necessary size calculations before > doing the actual redisplaying. But some other calculations (including > those concerning the mode-lien) are done only after the actual > redisplaying has already happened. That is too late for this redisplay > round but causes the values to be in place for all subsequent > redisplays. So the fix could be to do the mode-line based calculations > earlier? If you look at the code of redisplay_window, which is the function that handles redisplay of each window, you will see that it indeed calls display_mode_lines near its end (because the mode line includes constructs that depend on position of point and other state, and that could change as result of redisplaying a window). However, if after calling display_mode_lines we detect that the height of the mode line changed, we schedule an immediate thorough redisplay. So your theory doesn't sound correct, at least not when taken at face value. And once again, please keep in mind that by the time redisplay runs (without an explicit call to 'redisplay' inside the recipe you posted), 'fit-window-to-buffer' was already called, and it already used stale value of height stored in the window object. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 16:19 ` Eli Zaretskii @ 2019-11-16 19:30 ` martin rudalics 2019-11-16 19:45 ` Eli Zaretskii 2019-11-17 16:21 ` Jonas Bernoulli 1 sibling, 1 reply; 97+ messages in thread From: martin rudalics @ 2019-11-16 19:30 UTC (permalink / raw) To: Eli Zaretskii, Jonas Bernoulli; +Cc: 38181 > However, if after > calling display_mode_lines we detect that the height of the mode line > changed, we schedule an immediate thorough redisplay. ... which, unfortunately, will not re-run ‘fit-window-to-buffer’ but just use its earlier computed values. Theoretically, 'redisplay' could check the 'preserve-size' parameter of each window and try to preserve the text height when resizing the mode line. But I wouldn't want to think of all the tricky details of such an approach. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 19:30 ` martin rudalics @ 2019-11-16 19:45 ` Eli Zaretskii 2019-11-17 9:01 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-16 19:45 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sat, 16 Nov 2019 20:30:55 +0100 > > > However, if after > > calling display_mode_lines we detect that the height of the mode line > > changed, we schedule an immediate thorough redisplay. > > ... which, unfortunately, will not re-run ‘fit-window-to-buffer’ but > just use its earlier computed values. Maybe fit-window-to-buffer should set some hook, which redisplay should call if it finds out that the mode-line height changed? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 19:45 ` Eli Zaretskii @ 2019-11-17 9:01 ` martin rudalics 2019-11-17 17:22 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2019-11-17 9:01 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > Maybe fit-window-to-buffer should set some hook, which redisplay > should call if it finds out that the mode-line height changed? Maybe a two-bits sticky bit-field in the window structure called refit_window_to_buffer. The Lisp interface to it is a function called 'refit-window-to-buffer' setting refit_window_to_buffer to 1 if it is zero. 'fit-window-to-buffer' always calls 'refit-window-to-buffer'. display_mode_lines sets refit_window_to_buffer to 2 provided it is 1 and the mode line height of this window has changed. The display engine eventually calls 'fit-window-to-buffer' for all windows that have refit_window_to_buffer equal 2 and sets it to 3. When the display engine is done with redisplay it resets refit_window_to_buffer for all windows to 0. This might be tricky for windows stored in configurations and states. And always remember the fact that in one and the same display cycle 'fit-window-to-buffer' may have been called for two windows above each other. So this is definitely not for Emacs 27. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-17 9:01 ` martin rudalics @ 2019-11-17 17:22 ` Eli Zaretskii 2019-11-17 18:16 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-17 17:22 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sun, 17 Nov 2019 10:01:44 +0100 > > > Maybe fit-window-to-buffer should set some hook, which redisplay > > should call if it finds out that the mode-line height changed? > > Maybe a two-bits sticky bit-field in the window structure called > refit_window_to_buffer. The Lisp interface to it is a function called > 'refit-window-to-buffer' setting refit_window_to_buffer to 1 if it is > zero. 'fit-window-to-buffer' always calls 'refit-window-to-buffer'. I'd prefer a hook, because the problem probably isn't limited to fit-window-to-buffer. Wait, don't we already call window-size-change-functions in this case? If not, would it help if we did? > display_mode_lines sets refit_window_to_buffer to 2 provided it is 1 > and the mode line height of this window has changed. The detection of the change in mode-line height is outside display_mode_lines, see the snippet I posted up-thread. > The display engine eventually calls 'fit-window-to-buffer' for all > windows that have refit_window_to_buffer equal 2 and sets it to 3. We need to figure out the "eventually" part. It should happen after the windows have their dimensions updated due to the mode-line changes. Do you know where this happens? > This might be tricky for windows stored in configurations and states. Why tricky? A stored configuration shouldn't be affected by any changes after it's tored, no? > And always remember the fact that in one and the same display cycle > 'fit-window-to-buffer' may have been called for two windows above each > other. Mmm... actually, it could be that we cannot resize windows during redisplay at all. See, for example, how resize_mini_window does its tricky job. We may need to call this outside of redisplay. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-17 17:22 ` Eli Zaretskii @ 2019-11-17 18:16 ` martin rudalics 2019-11-17 18:39 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2019-11-17 18:16 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 > I'd prefer a hook, because the problem probably isn't limited to > fit-window-to-buffer. The display engine has to be able to ultimately control the behavior to avoid ending up in an infinite loop. Hooks are dangerous (though evaluating the mode line can be dangerous too IIRC). > Wait, don't we already call window-size-change-functions in this case? > If not, would it help if we did? That's precisely what I would like to avoid. Note that we do not re-run window change functions when they, for example, change the size of a window. Such changes are, in a sense, lost to the next redisplay cycle. >> display_mode_lines sets refit_window_to_buffer to 2 provided it is 1 >> and the mode line height of this window has changed. > > The detection of the change in mode-line height is outside > display_mode_lines, see the snippet I posted up-thread. Right. It should be done there. >> The display engine eventually calls 'fit-window-to-buffer' for all >> windows that have refit_window_to_buffer equal 2 and sets it to 3. > > We need to figure out the "eventually" part. It should happen after > the windows have their dimensions updated due to the mode-line > changes. Do you know where this happens? Nowhere, hopefully. Managing the mode-line happens in the display engine only. Note that a function like 'window-text-height', for example, detracts the mode line, header line and now even the tab line heights on-the-fly from the stored pixel_height and might even use estimate_mode_line_height. The stored text_height _does_ include mode and header line. >> This might be tricky for windows stored in configurations and states. > > Why tricky? A stored configuration shouldn't be affected by any > changes after it's tored, no? When we restore a configuration we probably should nullify the bit-field to avoid unwanted re-runs. Or not nullify to ensure re-runs? > Mmm... actually, it could be that we cannot resize windows during > redisplay at all. See, for example, how resize_mini_window does its > tricky job. We may need to call this outside of redisplay. Inherently, resize_mini_window does what 'fit-window-to-buffer' does and it gets called from redisplay_internal. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-17 18:16 ` martin rudalics @ 2019-11-17 18:39 ` Eli Zaretskii 2019-11-18 9:45 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-17 18:39 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sun, 17 Nov 2019 19:16:32 +0100 > > > Mmm... actually, it could be that we cannot resize windows during > > redisplay at all. See, for example, how resize_mini_window does its > > tricky job. We may need to call this outside of redisplay. > > Inherently, resize_mini_window does what 'fit-window-to-buffer' does > and it gets called from redisplay_internal. And it immediately returns if that happens while redisplaying a window. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-17 18:39 ` Eli Zaretskii @ 2019-11-18 9:45 ` martin rudalics 2019-11-18 15:46 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2019-11-18 9:45 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 >> > Mmm... actually, it could be that we cannot resize windows during >> > redisplay at all. See, for example, how resize_mini_window does its >> > tricky job. We may need to call this outside of redisplay. >> >> Inherently, resize_mini_window does what 'fit-window-to-buffer' does >> and it gets called from redisplay_internal. > > And it immediately returns if that happens while redisplaying a > window. But IIUC in neither of our proposals we would have done that. I'd even say that we should resize windows when redisplay finds out that the mode line height has been increased and would obscure the window above, not leave at least one line of its window's text visible (see the example in my other mail), ... martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-18 9:45 ` martin rudalics @ 2019-11-18 15:46 ` Eli Zaretskii 2019-11-18 18:46 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2019-11-18 15:46 UTC (permalink / raw) To: martin rudalics; +Cc: jonas, 38181 > Cc: jonas@bernoul.li, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Mon, 18 Nov 2019 10:45:13 +0100 > > >> > Mmm... actually, it could be that we cannot resize windows during > >> > redisplay at all. See, for example, how resize_mini_window does its > >> > tricky job. We may need to call this outside of redisplay. > >> > >> Inherently, resize_mini_window does what 'fit-window-to-buffer' does > >> and it gets called from redisplay_internal. > > > > And it immediately returns if that happens while redisplaying a > > window. > > But IIUC in neither of our proposals we would have done that. I wouldn't be so sure: the code fragment I've shown that detects mode-line height changes is inside redisplay_window. > I'd even say that we should resize windows when redisplay finds out > that the mode line height has been increased and would obscure the > window above, not leave at least one line of its window's text > visible Some might dislike such side effects, I think, for the same reason some dislike the resizing which happens due to mini-window growth. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-18 15:46 ` Eli Zaretskii @ 2019-11-18 18:46 ` martin rudalics 0 siblings, 0 replies; 97+ messages in thread From: martin rudalics @ 2019-11-18 18:46 UTC (permalink / raw) To: Eli Zaretskii; +Cc: jonas, 38181 >> But IIUC in neither of our proposals we would have done that. > > I wouldn't be so sure: the code fragment I've shown that detects > mode-line height changes is inside redisplay_window. But we should collect evidence from all windows first before redisplaying again. >> I'd even say that we should resize windows when redisplay finds out >> that the mode line height has been increased and would obscure the >> window above, not leave at least one line of its window's text >> visible > > Some might dislike such side effects, I think, for the same reason > some dislike the resizing which happens due to mini-window growth. You probably misunderstood. I meant the example from my other mail where enlarging the mode line covers the entire text area of its window. In that case we sooner or later will resize anyway, that is when the window resizing code becomes aware of the fact. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 16:19 ` Eli Zaretskii 2019-11-16 19:30 ` martin rudalics @ 2019-11-17 16:21 ` Jonas Bernoulli 1 sibling, 0 replies; 97+ messages in thread From: Jonas Bernoulli @ 2019-11-17 16:21 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 Eli Zaretskii <eliz@gnu.org> writes: > You are right saying that displaying a window causes a redisplay, but > keep in mind that redisplay triggered by that happens _after_ the > command which enlarged the mode-line height finishes, and by that time > fit-window-to-buffer will have already run (using stale window > dimensions). Thanks for that reminder. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-16 15:27 ` Jonas Bernoulli 2019-11-16 16:19 ` Eli Zaretskii @ 2019-11-16 19:30 ` martin rudalics 1 sibling, 0 replies; 97+ messages in thread From: martin rudalics @ 2019-11-16 19:30 UTC (permalink / raw) To: Jonas Bernoulli; +Cc: 38181 > Again, the mode-line-prettifiers are not the ones who create new buffers > and then call fit-buffer-to-window. It's arbitrary other packages that > do that. An optional argument therefore would not help because when one > of the prettifier modes is active, then each and every third-party > caller of fit-buffer-to-window would have to pass that optional > argument. I see. Maybe a function 'set-default-mode-line-format' would be useful here. Anyway: At the time you prettify a mode line or show a new buffer in a window with a to be prettified mode line, would doing an immediate redisplay work around future problems? > This is the advice I currently use: > > (defvar-local moody--size-hacked-p nil) > > (defun moody-redisplay (&optional _force &rest _ignored) > (unless moody--size-hacked-p > (setq moody--size-hacked-p t) > (redisplay t))) > > (advice-add 'fit-window-to-buffer :before #'moody-redisplay) > > Of course fit-buffer-to-window itself could be changed to do that and it > could also be taught to only do so iff the user opted in to doing it. 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. > Creating and displaying a new buffer and creating and resizing a new > window surely *already* causes a "redisplay" without the programmer > having to explicitly call `redisplay'. So if we explicitly tell > fit-window-to-buffer to redisplay, then that means that we are > redisplaying twice, right? I think so. Maybe 'fit-window-to-buffer' could use the string returned by 'format-mode-line' instead and calculate its height without redisplaying anything. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2019-11-12 16:52 bug#38181: Actual height of mode-line not taken into account Jonas Bernoulli 2019-11-13 8:03 ` martin rudalics 2019-11-15 13:48 ` Eli Zaretskii @ 2021-10-15 5:13 ` Carlos Pita 2021-10-15 7:05 ` martin rudalics 2021-10-15 7:51 ` Eli Zaretskii 2 siblings, 2 replies; 97+ messages in thread From: Carlos Pita @ 2021-10-15 5:13 UTC (permalink / raw) To: 38181 Hi, I'm seeing what I believe is an instance of this issue in a vanilla build from emacs-28 branch, ns/cocoa backed. Here are some instructions for reproduction: https://github.com/seagle0128/doom-modeline/issues/480#issue-1027051204 Best regards, Carlos ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 5:13 ` Carlos Pita @ 2021-10-15 7:05 ` martin rudalics 2021-10-15 7:26 ` Carlos Pita 2021-10-15 7:51 ` Eli Zaretskii 1 sibling, 1 reply; 97+ messages in thread From: martin rudalics @ 2021-10-15 7:05 UTC (permalink / raw) To: Carlos Pita, 38181 > I'm seeing what I believe is an instance of this issue in a vanilla > build from emacs-28 branch, ns/cocoa backed. > > Here are some instructions for reproduction: > https://github.com/seagle0128/doom-modeline/issues/480#issue-1027051204 If the underlying scenario is that you first fit a window to its buffer and then enlarge the height of that window's mode-line, there's not much we can do here currently. It's like fitting a window to its buffer and then adding a header line or a horizontal scroll bar to that window. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 7:05 ` martin rudalics @ 2021-10-15 7:26 ` Carlos Pita 2021-10-15 7:54 ` Eli Zaretskii 2021-10-15 8:35 ` martin rudalics 0 siblings, 2 replies; 97+ messages in thread From: Carlos Pita @ 2021-10-15 7:26 UTC (permalink / raw) To: martin rudalics; +Cc: 38181 Hi Martin, > If the underlying scenario is that you first fit a window to its buffer > and then enlarge the height of that window's mode-line, there's not much > we can do here currently. It's like fitting a window to its buffer and > then adding a header line or a horizontal scroll bar to that window. I can't say I understand the details discussed here but I'm not quite sure your description fits the situation. The workaround since this bug was first reported has been: immediately before fit-window-to-buffer execute an advice that forces a redisplay, then deactivate the advice. But the problem I'm seeing now is that the first time org-set-tags-command is executed its popup is correctly sized (with said workaround in place, of course), but further executions show a popup with the wrong geometry that trims part of the text off. If I remove the "just once" clause in the workaround, so that the redisplay is forced after each fit-window-to-buffer execution, then the layout is correct every time. It goes without saying that org-set-tags-command is ultimately triggering the execution of fit-window-to-buffer, but that stuff you probably know much better than me. Thing is, there was no enlargement of the modeline in-between, as far as I can understand and see nothing changed in this regard between the first and the second execution of org-set-tags-command. Best regards, Carlos ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 7:26 ` Carlos Pita @ 2021-10-15 7:54 ` Eli Zaretskii 2021-10-15 8:18 ` Carlos Pita 2021-10-15 8:35 ` martin rudalics 1 sibling, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2021-10-15 7:54 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 > From: Carlos Pita <carlosjosepita2@gmail.com> > Date: Fri, 15 Oct 2021 04:26:51 -0300 > Cc: 38181@debbugs.gnu.org > > > If the underlying scenario is that you first fit a window to its buffer > > and then enlarge the height of that window's mode-line, there's not much > > we can do here currently. It's like fitting a window to its buffer and > > then adding a header line or a horizontal scroll bar to that window. > > I can't say I understand the details discussed here but I'm not quite > sure your description fits the situation. > > The workaround since this bug was first reported has been: immediately > before fit-window-to-buffer execute an advice that forces a redisplay, > then deactivate the advice. > > But the problem I'm seeing now is that the first time > org-set-tags-command is executed its popup is correctly sized (with > said workaround in place, of course), but further executions show a > popup with the wrong geometry that trims part of the text off. If I > remove the "just once" clause in the workaround, so that the redisplay > is forced after each fit-window-to-buffer execution, then the layout > is correct every time. It goes without saying that > org-set-tags-command is ultimately triggering the execution of > fit-window-to-buffer, but that stuff you probably know much better > than me. Thing is, there was no enlargement of the modeline > in-between, as far as I can understand and see nothing changed in this > regard between the first and the second execution of > org-set-tags-command. Can you show the recipe for the problem, starting from "emacs -Q"? It sounds from what you say that the problem is not with the mode line, but with something else. If that is true, please submit a new bug report. This bug is about redisplaying the mode line when something changes in mode-line-format that affects the height of the mode line. If there are other problems with fit-window-to-buffer, they should be discussed separately. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 7:54 ` Eli Zaretskii @ 2021-10-15 8:18 ` Carlos Pita 0 siblings, 0 replies; 97+ messages in thread From: Carlos Pita @ 2021-10-15 8:18 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 > Can you show the recipe for the problem, starting from "emacs -Q"? Yes, of course, the example Jonas provided in the opening post will do it with a small modification. 1. Execute the code. 2. Call test-popup and check that the layout is wrong. 3. Redefine test-popup with (redisplay) uncommented. 4. Call it again and check that the layout is right. 5. Redefine test-popup with (redisplay) commented again. 6. Call it again and check that the layout is wrong again. Now, consider the workaround [1] that seemingly has been doing the job for almost two years in at least moody and doom modelines. AFAICS if this workaround was working then, (6) above is showing us something new. Or perhaps it's just my setup and the workaround still works for everybody else. > It sounds from what you say that the problem is not with the mode line, but with something else. If that is true, please submit a new bug report. Please, you tell me what to do in this regard because I'm unable to tell if the problem is in the modeline or elsewhere. To my untrained eye it looks quite similar to what was reported here, although with the aforementioned difference. Best regards, Carlos --- [1] https://github.com/tarsius/moody/blob/9b679400ca885b8ff51bcfd75b87f79d66c0ee26/moody.el#L303 ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 7:26 ` Carlos Pita 2021-10-15 7:54 ` Eli Zaretskii @ 2021-10-15 8:35 ` martin rudalics 2021-10-15 8:45 ` Carlos Pita [not found] ` <CAEOO5TdaV=tdj23afEcqJGZf4JM3VVQ6TFt4F3q6k6d=f4_36w@mail.gmail.com> 1 sibling, 2 replies; 97+ messages in thread From: martin rudalics @ 2021-10-15 8:35 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 > But the problem I'm seeing now is that the first time > org-set-tags-command is executed its popup is correctly sized (with > said workaround in place, of course), but further executions show a > popup with the wrong geometry that trims part of the text off. If I > remove the "just once" clause in the workaround, so that the redisplay > is forced after each fit-window-to-buffer execution, then the layout > is correct every time. It goes without saying that > org-set-tags-command is ultimately triggering the execution of > fit-window-to-buffer, but that stuff you probably know much better > than me. Thing is, there was no enlargement of the modeline > in-between, as far as I can understand and see nothing changed in this > regard between the first and the second execution of > org-set-tags-command. I'm not sure I follow. What is the purpose of "the redisplay is forced after each fit-window-to-buffer execution"? If you want a new mode line height to be taken into account by 'fit-window-to-buffer', you probably should do any such redisplay _before_ executing 'fit-window-to-buffer'. Or what am I missing? martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 8:35 ` martin rudalics @ 2021-10-15 8:45 ` Carlos Pita [not found] ` <CAEOO5TdaV=tdj23afEcqJGZf4JM3VVQ6TFt4F3q6k6d=f4_36w@mail.gmail.com> 1 sibling, 0 replies; 97+ messages in thread From: Carlos Pita @ 2021-10-15 8:45 UTC (permalink / raw) To: 38181 On Fri, Oct 15, 2021 at 5:35 AM martin rudalics <rudalics@gmx.at> wrote: > I'm not sure I follow. What is the purpose of "the redisplay is forced > after each fit-window-to-buffer execution"? My bad, it wasn't the best way to express it. It's executed before, of course, it's a before advice. What I meant is that previously we had the sequence: 1. redisplay fit fit ... and now: 2. redisplay fit redisplay fit redisplay ... Supposedly 1 was a fix for: 0. fit fit fit ... but now I need 2. Best regards, Carlos ^ permalink raw reply [flat|nested] 97+ messages in thread
[parent not found: <CAEOO5TdaV=tdj23afEcqJGZf4JM3VVQ6TFt4F3q6k6d=f4_36w@mail.gmail.com>]
[parent not found: <776a35b7-1920-2987-88ae-6dcab958a8e4@gmx.at>]
* bug#38181: Actual height of mode-line not taken into account [not found] ` <776a35b7-1920-2987-88ae-6dcab958a8e4@gmx.at> @ 2021-10-15 9:07 ` Carlos Pita 2021-10-16 7:55 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Carlos Pita @ 2021-10-15 9:07 UTC (permalink / raw) To: martin rudalics, 38181 > > 2. redisplay fit redisplay fit redisplay ... > Sorry. I still don't understand the purpose of the last redisplay here. It's not the last, it's a repeating sequence, I left the dangling redisplay instead of ending it in a fit because I was explaining my unfortunate choice of words when I said "after", but it's formally the same, the point being that the first redisplay is not enough. > Does > > 2. redisplay fit redisplay fit ... > > fail? What are the values returned by 'window-mode-line-height' after > each redisplay? As far as I can see this works, as I said before. In the example provided by Jonas window-mode-line-height is 29 immediately after calling set-face-attribute, but after setting mode-line-format it's always 60, no matter if I call redisplay or fit or none of them or in what order. But even if the reported height is the same, the layout is not, omitting the (previous) redisplay always crops the text. Best regards, Carlos ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 9:07 ` Carlos Pita @ 2021-10-16 7:55 ` martin rudalics 2021-10-16 11:23 ` Carlos Pita 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2021-10-16 7:55 UTC (permalink / raw) To: Carlos Pita, 38181 >> > 2. redisplay fit redisplay fit redisplay ... > >> Sorry. I still don't understand the purpose of the last redisplay here. > > It's not the last, it's a repeating sequence, I left the dangling > redisplay instead of ending it in a fit because I was explaining my > unfortunate choice of words when I said "after", but it's formally the > same, the point being that the first redisplay is not enough. OK. Can we settle on something like 2. redisplay fit redisplay fit redisplay ... fit Bear with me but I'm trying to simultaneously understand what you are doing and what Emacs is doing. This is multitasking and I'm bad at that. >> Does >> >> 2. redisplay fit redisplay fit ... >> >> fail? What are the values returned by 'window-mode-line-height' after >> each redisplay? > > As far as I can see this works, What is "this" here? > as I said before. In the example > provided by Jonas window-mode-line-height is 29 immediately after > calling set-face-attribute, but after setting mode-line-format it's > always 60, no matter if I call redisplay or fit or none of them or in > what order. But even if the reported height is the same, the layout is > not, omitting the (previous) redisplay always crops the text. I'm currently not even sure what we are comparing here. Let's settle on the following idioms: (defun selected-window-mode-line-height () (pos-visible-in-window-p t nil t) (window-mode-line-height)) (let ((val (selected-window-mode-line-height))) (fit-window-to-buffer) (cons (selected-window-mode-line-height) val)) Do you see any change in the return value here? And when you run this repeatedly as in the redisplay fit redisplay fit redisplay ... fit scenario? And with 'set-face-attribute' and setting 'mode-line-format' intermingled? Maybe Emacs sometimes doesn't cache the result of an earlier call of display_mode_line although it could (or should). martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-16 7:55 ` martin rudalics @ 2021-10-16 11:23 ` Carlos Pita 2021-10-16 16:48 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Carlos Pita @ 2021-10-16 11:23 UTC (permalink / raw) To: martin rudalics; +Cc: 38181 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 ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-16 11:23 ` Carlos Pita @ 2021-10-16 16:48 ` martin rudalics 2021-10-16 18:00 ` Carlos Pita 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2021-10-16 16:48 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 > 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. Right. The "close popup" removes anything redisplay cached for the window's mode line in the last call of 'test-popup-redisplay'. > 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. Right. It always uses the cached mode line height in this case. > 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. What is the "workaround"? IIUC there is no "redisplay" one can call on a "per buffer" base. > 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. Even the 'redisplay' trick will not be sufficient: Consider Eli's scenario in this thread but with _different_ heights for active and inactive mode lines. It will break things when after doing the 'fit-window-to-buffer' call you (de-)select the window you've just fit. > 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 think you mean with every set_window_buffer? And probably with every set_window_configuration too. Did you try it? > 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. Here I have no problems with the scenarios I've seen in this thread because I update the mode line caches with every change of a window height (which includes the case where a window is created) and with any change of a buffer local variable like 'mode-line-format'. So basically no redisplay is ever needed in the first place, just a recalculation of the mode line heights of all windows whose heights have changed. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-16 16:48 ` martin rudalics @ 2021-10-16 18:00 ` Carlos Pita 2021-10-16 19:41 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Carlos Pita @ 2021-10-16 18:00 UTC (permalink / raw) To: martin rudalics; +Cc: 38181 Hi Martin, thank you for the commentary. > What is the "workaround"? IIUC there is no "redisplay" one can call on > a "per buffer" base. The one I linked above which some packages have been using for almost a couple of years now and, indeed, was mentioned early in this thread but never questioned AFAICS, namely: (defvar-local moody--size-hacked-p nil) (defun moody-redisplay (&optional _force &rest _ignored) (when (and mode-line-format (not moody--size-hacked-p)) (setq moody--size-hacked-p t) (redisplay t))) (advice-add 'fit-window-to-buffer :before #'moody-redisplay) The problem I see with it is that buffers often survive their windows and are later reused in other windows. This happens with some of the popups that fit to their buffers we are talking about. Moreover, using a window parameter instead of the buffer local won't be enough, because sometimes fit-window-to-buffer is called from another window (I mean, not the popup window) after the excursion that prepares the popup, so the redisplay ends up running in the wrong window. > Even the 'redisplay' trick will not be sufficient: Consider Eli's > scenario in this thread but with _different_ heights for active and > inactive mode lines. It will break things when after doing the > 'fit-window-to-buffer' call you (de-)select the window you've just fit. I think I follow the argument but I don't see it as having practical interest for the use cases that motivated this report. All modeline customizations I'm aware of use a single modeline height, although the modeline contents and faces may of course change with major and minor modes and activity status. > > 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 think you mean with every set_window_buffer? And probably with every > set_window_configuration too. Did you try it? I still need to refine my concept of "on window creation". When you say "with evert set_window_buffer" I'm not sure whether you mean something like: 1. There is an event (a) of window creation and later and event (b) when the buffer is set for the new window. So if I call redisplay immediately after (a) it would be too early because the modeline won't be properly set up until (b). Or, instead, something like: 2. Windows often change buffers and buffers may have modeline formats that imply different modeline heights. If 1 is the case then sure, maybe it's a different event that I need to listen to, but it's still one forced early redisplay per window. But if you mean 2, again I don't see the relevance in practice. With regard to set_window_configuration similar observations can be done. > change of a buffer local variable like 'mode-line-format'. So basically > no redisplay is ever needed in the first place, just a recalculation of > the mode line heights of all windows whose heights have changed. This is good to know. Thank you again. Best regards, Carlos ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-16 18:00 ` Carlos Pita @ 2021-10-16 19:41 ` martin rudalics 2021-10-16 19:57 ` Carlos Pita 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2021-10-16 19:41 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 > I still need to refine my concept of "on window creation". When you say > "with evert set_window_buffer" I'm not sure whether you mean something > like: > > 1. There is an event (a) of window creation and later and event (b) > when the buffer is set for the new window. So if I call redisplay > immediately after (a) it would be too early because the modeline won't > be properly set up until (b). Window creation means 'split-window' which assigns the new window a buffer that appears in the window that was split. > Or, instead, something like: > > 2. Windows often change buffers and buffers may have modeline formats > that imply different modeline heights. > > If 1 is the case then sure, maybe it's a different event that I need > to listen to, but it's still one forced early redisplay per window. > But if you mean 2, again I don't see the relevance in practice. How comes? 'display-buffer-in-side-window' may reuse an existing window or pop up a new one. Or do the mode lines of _all_ your windows have the same height? That indeed would simplify things a lot. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-16 19:41 ` martin rudalics @ 2021-10-16 19:57 ` Carlos Pita 2021-10-16 21:27 ` Carlos Pita 2021-10-17 8:33 ` martin rudalics 0 siblings, 2 replies; 97+ messages in thread From: Carlos Pita @ 2021-10-16 19:57 UTC (permalink / raw) To: martin rudalics; +Cc: 38181 I was just about to email you with some questions that you now have answered to some extent. Anyway, I'm copying my original questions with some annotations. > > I think you mean with every set_window_buffer? And probably with every > > set_window_configuration too. Did you try it? > > I still need to refine my concept of "on window creation". Well, any relevant window hook in [1] is advertised as "called during redisplay", so that surely isn't the place to trigger that same redisplay to begin with... Let's go back to advising then. Here are some questions I have: 1. Is there a primitive function that is like the mother of all windows? There is no window-create nor create-window alikes, so maybe split-window-internal? > Window creation means 'split-window' which assigns the new window a > buffer that appears in the window that was split. So this more or less settles the question, but to be more precise: do you see any difference of relevance between advicing split-window and split-window-internal? 2. Or is it better to advise set-window-buffer/configuration for whatever reasons? Any or both of them? 3. If advising set-window-buffer/configuration is the preferred method, I'm still assuming that we will keep a window parameter in order to disable the forced redisplay after its first execution for the window. Is there any reason not do so (taking into account what I said before of the target use case: a single modeline height for every modeline during the entire session). > Or do the mode lines of _all_ your windows have > the same height? That indeed would simplify things a lot. Yes, this is by far the usual case and I believe it's a fact that favours the "advise window creation" strategy over the "advise window buffer/config change events" (with or without the "just once per window" clause) strategy. Thanks again, Carlos ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-16 19:57 ` Carlos Pita @ 2021-10-16 21:27 ` Carlos Pita 2021-10-17 6:06 ` Eli Zaretskii 2021-10-17 8:34 ` martin rudalics 2021-10-17 8:33 ` martin rudalics 1 sibling, 2 replies; 97+ messages in thread From: Carlos Pita @ 2021-10-16 21:27 UTC (permalink / raw) To: martin rudalics; +Cc: 38181 In practice this seems to nicely cover the relevant cases: (defun my-redisplay-hack (&rest _) (when mode-line-format (redisplay t))) (advice-add #'split-window :after #'my-redisplay-hack) but there is some flickering because the window is displayed before the fit and then immediately replaced by the fitted version. Although I see no way around that glitch, so it might be the price to pay. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-16 21:27 ` Carlos Pita @ 2021-10-17 6:06 ` Eli Zaretskii 2021-10-17 6:45 ` Carlos Pita 2021-10-17 8:34 ` martin rudalics 2021-10-17 8:34 ` martin rudalics 1 sibling, 2 replies; 97+ messages in thread From: Eli Zaretskii @ 2021-10-17 6:06 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 > From: Carlos Pita <carlosjosepita2@gmail.com> > Date: Sat, 16 Oct 2021 18:27:10 -0300 > Cc: 38181@debbugs.gnu.org > > In practice this seems to nicely cover the relevant cases: > > (defun my-redisplay-hack (&rest _) > (when mode-line-format > (redisplay t))) > (advice-add #'split-window :after #'my-redisplay-hack) I wonder how this fixes anything, since split-window already triggers redisplay. Martin, do you understand the difference? > but there is some flickering because the window is displayed before > the fit and then immediately replaced by the fitted version. Which means there are two redisplay cycles, and the first one (which produces incorrect display) is the one from your hack. So once again, I wonder why that call to 'redisplay' is needed. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-17 6:06 ` Eli Zaretskii @ 2021-10-17 6:45 ` Carlos Pita 2021-10-17 8:34 ` martin rudalics 1 sibling, 0 replies; 97+ messages in thread From: Carlos Pita @ 2021-10-17 6:45 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 Hi Eli, > > In practice this seems to nicely cover the relevant cases: > > > > (defun my-redisplay-hack (&rest _) > > (when mode-line-format > > (redisplay t))) > > (advice-add #'split-window :after #'my-redisplay-hack) > > I wonder how this fixes anything, since split-window already triggers > redisplay. In the use cases discussed above, IIUC the problem is that the redisplay is triggered at some point, but only after fit-window-to-buffer has already taken place. Consider for example what org-attach does: 1. Create a new window 2. Enter a window excursion and insert stuff into the new window 3. After the excursion fit the new window to the buffer (this is done from another window) 4. Wait for user input Seemingly, at point 3 the redisplay has not happened yet. The redisplay-before-fit advice won't work in this case because the current window is not the popup anymore when the fit (and hence the forced redisplay) happens. Another different example is org-set-tags-command, this is what it does: 1. Create a new window 2. Enter a window excursion and insert stuff into the new window 3. Inside the excursion fit the new window to the buffer (now this is done while the popup is the current window) 4. After the excursion, wait for user input So in this case the redisplay-before-fit advice works fine since it's triggered inside the popup. But then the popup is killed while its buffer remains hidden, outliving the popup. Remember that the advice is really a redisplay-before-fit-once-per-buffer advice, so the next time you call org-set-tags-command it will fail to redisplay. This is why I believe these cases weren't properly addressed by the previous workaround but are now. > Which means there are two redisplay cycles, and the first one (which > produces incorrect display) is the one from your hack. So once again, > I wonder why that call to 'redisplay' is needed. Yes, I know that is the cause. The redisplay is not needed per se and, worse, produces undesirable visual artifacts, but apparently it's the only way we have to update the information about the mode-line height before fit-window-to-buffer runs. Now, if you are saying that step 1 in the examples above already triggered a redisplay, and if a redisplay always updates whatever information about the modeline geometry that needs to be updated, then something is not adding up. Best regards -- Carlos ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-17 6:06 ` Eli Zaretskii 2021-10-17 6:45 ` Carlos Pita @ 2021-10-17 8:34 ` martin rudalics 1 sibling, 0 replies; 97+ messages in thread From: martin rudalics @ 2021-10-17 8:34 UTC (permalink / raw) To: Eli Zaretskii, Carlos Pita; +Cc: 38181 >> In practice this seems to nicely cover the relevant cases: >> >> (defun my-redisplay-hack (&rest _) >> (when mode-line-format >> (redisplay t))) >> (advice-add #'split-window :after #'my-redisplay-hack) > > I wonder how this fixes anything, since split-window already triggers > redisplay. Martin, do you understand the difference? There is no difference in the use cases posted here. The results will change only when a window is reused and then fit to its buffer. >> but there is some flickering because the window is displayed before >> the fit and then immediately replaced by the fitted version. > > Which means there are two redisplay cycles, and the first one (which > produces incorrect display) is the one from your hack. So once again, > I wonder why that call to 'redisplay' is needed. Where "incorrect redisplay" stands for "window that has not been yet fit to its buffer". martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-16 21:27 ` Carlos Pita 2021-10-17 6:06 ` Eli Zaretskii @ 2021-10-17 8:34 ` martin rudalics 1 sibling, 0 replies; 97+ messages in thread From: martin rudalics @ 2021-10-17 8:34 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 > In practice this seems to nicely cover the relevant cases: > > (defun my-redisplay-hack (&rest _) > (when mode-line-format > (redisplay t))) > (advice-add #'split-window :after #'my-redisplay-hack) > > but there is some flickering because the window is displayed before > the fit and then immediately replaced by the fitted version. Although > I see no way around that glitch, so it might be the price to pay. Nothing new here. The sequence remains the same as before: 'split-window', 'redisplay', 'fit-window-to-buffer'. And remember: People usually tolerate when Emacs occasionally crashes. They never tolerate flickering. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-16 19:57 ` Carlos Pita 2021-10-16 21:27 ` Carlos Pita @ 2021-10-17 8:33 ` martin rudalics 2021-10-18 9:34 ` martin rudalics 1 sibling, 1 reply; 97+ messages in thread From: martin rudalics @ 2021-10-17 8:33 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 > Well, any relevant window hook in [1] is advertised as "called during > redisplay", so that surely isn't the place to trigger that same > redisplay to begin with... Roughly spoken, redisplay calculates the height of the minibuffer window and those of the mode lines and, if any of these changed since last redisplay, does another redisplay in the hope that they stick to their values now. After that, it runs the hooks you mention above so these can take the now final (wrt redisplay) window and mode line sizes into account. A function on any of these hooks that changes a mode line height or a window size does that on its own risk. It's _not_ recommended. > Let's go back to advising then. Here are some questions I have: > > 1. Is there a primitive function that is like the mother of all > windows? I always wanted to write one to make 'display-buffer' simpler but nobody was enthusiastic about it. > There is no window-create nor create-window alikes, so maybe > split-window-internal? > > > Window creation means 'split-window' which assigns the new window a > > buffer that appears in the window that was split. > > So this more or less settles the question, but to be more precise: > do you see any difference of relevance between advicing split-window > and split-window-internal? Never advise an internal function or one with an '-internal' postfix. Such function may change or be removed at any time. > 2. Or is it better to advise set-window-buffer/configuration for > whatever reasons? Any or both of them? Both. Especially because you may want to reuse a window for showing another buffer in it. > 3. If advising set-window-buffer/configuration is the preferred > method, I'm still assuming that we will keep a window parameter in > order to disable the forced redisplay after its first execution for the > window. Is there any reason not do so (taking into account what > I said before of the target use case: a single modeline height for > every modeline during the entire session). The mode line height is window specific, taking into account what the buffer, the window and the window's frame have set up for it. > > Or do the mode lines of _all_ your windows have > > the same height? That indeed would simplify things a lot. > > Yes, this is by far the usual case and I believe it's a fact that > favours the "advise window creation" strategy over the > "advise window buffer/config change events" (with or without > the "just once per window" clause) strategy. In one of my earlier postings I falsely assumed that we _could_ retrieve the prospective heights of mode lines by calling 'pos-visible-in-window-p' followed by 'window-mode-line-height', forgetting that the former restores the previous values after doing its calculations. By looking at these functions you could derive a new one that calculates mode line heights in a similar way and peruse the return values of that function in 'window-text-pixel-size' in the hope that they won't change with the next redisplay. The 'mode-lines' argument of 'window-text-pixel-size' should then accept a value like 'update' to reflect this special use case. It might be worth the experience. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-17 8:33 ` martin rudalics @ 2021-10-18 9:34 ` martin rudalics 2021-10-18 15:56 ` Carlos Pita 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2021-10-18 9:34 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 [-- Attachment #1: Type: text/plain, Size: 504 bytes --] > By looking at these functions you could derive a new one > that calculates mode line heights in a similar way and peruse the return > values of that function in 'window-text-pixel-size' in the hope that > they won't change with the next redisplay. The 'mode-lines' argument of > 'window-text-pixel-size' should then accept a value like 'update' to > reflect this special use case. It might be worth the experience. Or try the attached patch on master. It seems to fix the issue here. martin [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: xdisp.c.diff --] [-- Type: text/x-patch; name="xdisp.c.diff", Size: 2042 bytes --] diff --git a/src/xdisp.c b/src/xdisp.c index 783ef396a3..ad833d99e3 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -10847,17 +10847,45 @@ DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_siz if (y > max_y) y = max_y; - if (EQ (mode_lines, Qtab_line) || EQ (mode_lines, Qt)) - /* Re-add height of tab-line as requested. */ - y = y + WINDOW_TAB_LINE_HEIGHT (w); + if ((EQ (mode_lines, Qtab_line) + || EQ (mode_lines, Qt)) + && window_wants_tab_line (w)) + /* Add height of tab-line as requested. */ + { + Lisp_Object window_tab_line_format + = window_parameter (w, Qtab_line_format); + + y = y + display_mode_line (w, TAB_LINE_FACE_ID, + NILP (window_tab_line_format) + ? BVAR (current_buffer, tab_line_format) + : window_tab_line_format); + } - if (EQ (mode_lines, Qheader_line) || EQ (mode_lines, Qt)) - /* Re-add height of header-line as requested. */ - y = y + WINDOW_HEADER_LINE_HEIGHT (w); + if ((EQ (mode_lines, Qheader_line) + || EQ (mode_lines, Qt)) + && window_wants_header_line (w)) + { + Lisp_Object window_header_line_format + = window_parameter (w, Qheader_line_format); - if (EQ (mode_lines, Qmode_line) || EQ (mode_lines, Qt)) - /* Add height of mode-line as requested. */ - y = y + WINDOW_MODE_LINE_HEIGHT (w); + y = y + display_mode_line (w, HEADER_LINE_FACE_ID, + NILP (window_header_line_format) + ? BVAR (current_buffer, header_line_format) + : window_header_line_format); + } + + if ((EQ (mode_lines, Qmode_line) + || EQ (mode_lines, Qt)) + && window_wants_mode_line (w)) + { + Lisp_Object window_mode_line_format + = window_parameter (w, Qmode_line_format); + + y = y + display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w), + NILP (window_mode_line_format) + ? BVAR (current_buffer, mode_line_format) + : window_mode_line_format); + } bidi_unshelve_cache (itdata, false); ^ permalink raw reply related [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-18 9:34 ` martin rudalics @ 2021-10-18 15:56 ` Carlos Pita 2021-10-18 17:44 ` martin rudalics 0 siblings, 1 reply; 97+ messages in thread From: Carlos Pita @ 2021-10-18 15:56 UTC (permalink / raw) To: martin rudalics; +Cc: 38181 Hi Martin, Thank you very much. I've tested it in both master and emacs-28 branches and I've seen none of the aforementioned issues nor, at least in a cursory examination, any regression. It seems like you're displaying the modeline instead of merely using the current height? There is no perceptible flickering in any case. Best regards, Carlos ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-18 15:56 ` Carlos Pita @ 2021-10-18 17:44 ` martin rudalics 2021-10-18 18:27 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: martin rudalics @ 2021-10-18 17:44 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 > I've tested it in both master and emacs-28 branches and I've seen none > of the aforementioned issues nor, at least in a cursory examination, > any regression. > > It seems like you're displaying the modeline instead of merely using > the current height? There is no perceptible flickering in any case. There's no "displaying" involved. IIUC display_mode_line has become a misnomer ever since it's used in pos_visible_p. Basically, I do two things: Run 'format-mode-line' and compute_line_metrics on the current mode line strings. Eli, I think this could go into Emacs 28. WDYT? martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-18 17:44 ` martin rudalics @ 2021-10-18 18:27 ` Eli Zaretskii 2021-10-18 23:35 ` Carlos Pita ` (2 more replies) 0 siblings, 3 replies; 97+ messages in thread From: Eli Zaretskii @ 2021-10-18 18:27 UTC (permalink / raw) To: martin rudalics; +Cc: carlosjosepita2, 38181 > From: martin rudalics <rudalics@gmx.at> > Date: Mon, 18 Oct 2021 19:44:08 +0200 > Cc: 38181@debbugs.gnu.org > > > I've tested it in both master and emacs-28 branches and I've seen none > > of the aforementioned issues nor, at least in a cursory examination, > > any regression. > > > > It seems like you're displaying the modeline instead of merely using > > the current height? There is no perceptible flickering in any case. > > There's no "displaying" involved. There is, for some value of "display": this function actually generates a glyph row in the glyph matrix. > Eli, I think this could go into Emacs 28. WDYT? No, it's too radical, and the problem it fixes is too obscure. Let's install it on master, please. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-18 18:27 ` Eli Zaretskii @ 2021-10-18 23:35 ` Carlos Pita 2021-10-19 0:11 ` Carlos Pita 2021-10-19 9:25 ` martin rudalics [not found] ` <CAEOO5TemeSrLkudEBRbMaLrCXq7A0y5uv+SdcfZwMo77onMMoA@mail.gmail.com> 2 siblings, 1 reply; 97+ messages in thread From: Carlos Pita @ 2021-10-18 23:35 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 (Sorry if it ends up being a dup but I'm resending this because I'd previously sent it with an attached screencast and it seems that it's not being accepted by the bug tracker. In any case, it was the wrong cast :P. Please let me know if there's a policy wrt screencasts, even the right ones. I think it could be useful in this case but it's not that important.) Hi, Here is one more example that tries to capture the essence of another popup dialog in org that is giving me headaches. It's fixed by applying Martin's patch, it's not "fixed" with the redisplay-before-fit workaround (although the redisplay does make a difference as shown below) and it's "fixed" with the redisplay-after-creation workaround. 1) I run emacs -q and execute this simple code that opens a window with 30 numbers, each in its own line: (progn (switch-to-buffer-other-window "popup") (erase-buffer) (insert (mapconcat #'number-to-string (number-sequence 1 30) "\n")) (fit-window-to-buffer)) The window properly fits the numbers, which are all visible (please ensure your screen and frame is large enough). Now I close the window and make the modeline bigger as in Jonas' example: (setq-default mode-line-format (cons (propertize " " 'display (create-image "/* XPM */ static char * image[] = { \"3 60 1 1\", \"0 c #00aaff\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\", \"000\",\n\"000\",\n\"000\",\n\"000\",\n\"000\" };" 'xpm t :ascent 'center)) mode-line-format)) 2) If I run the code above one more time, that is: (progn (switch-to-buffer-other-window "popup") (erase-buffer) (insert (mapconcat #'number-to-string (number-sequence 1 30) "\n")) (fit-window-to-buffer)) The numbers are only partially visible, the window looks as if I had scrolled the buffer down to the bottom. Scrolling up it's easy to see that not all of the numbers fit the window. I guess this is expected because of the miscalculations regarding the modeline height. 3) Now I add a redisplay before the fit: (progn (switch-to-buffer-other-window "popup") (erase-buffer) (insert (mapconcat #'number-to-string (number-sequence 1 30) "\n")) (redisplay t) (fit-window-to-buffer)) Again, only about half of the numbers are visible and the window looks as if its buffer has been scrolled down. But now by scrolling up I can check that all the numbers fit the window. So the height of the window is right but there is that unnecessary scrolling down of the contents. 4) Now I repeat with the forced redisplay even earlier: (progn (switch-to-buffer-other-window "popup") (redisplay t) (erase-buffer) (insert (mapconcat #'number-to-string (number-sequence 1 30) "\n")) (fit-window-to-buffer)) This seems to work around the issue. I believe that in 3 there is some miscalculation during the insertion of text into the buffer that forces a scroll, but I'm having a hard time trying to explain that. Anyway, it's another case the redisplay-before-fit advice can't cope with. Best regards, Carlos ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-18 23:35 ` Carlos Pita @ 2021-10-19 0:11 ` Carlos Pita 0 siblings, 0 replies; 97+ messages in thread From: Carlos Pita @ 2021-10-19 0:11 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 > Please let me know if there's a policy wrt screencasts, > even the right ones. I think it could be useful in this case but it's > not that important. FWIW here is a permalink (I hope) to the cast: https://user-images.githubusercontent.com/2845433/137821853-c887649d-848d-4d55-8a1f-299da8020ff4.mov ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-18 18:27 ` Eli Zaretskii 2021-10-18 23:35 ` Carlos Pita @ 2021-10-19 9:25 ` martin rudalics 2021-10-19 12:22 ` Eli Zaretskii 2021-10-22 9:04 ` martin rudalics [not found] ` <CAEOO5TemeSrLkudEBRbMaLrCXq7A0y5uv+SdcfZwMo77onMMoA@mail.gmail.com> 2 siblings, 2 replies; 97+ messages in thread From: martin rudalics @ 2021-10-19 9:25 UTC (permalink / raw) To: Eli Zaretskii; +Cc: carlosjosepita2, 38181 > There is, for some value of "display": this function actually > generates a glyph row in the glyph matrix. The same thing happens with 'pos-visible-in-window-p', I suppose. >> Eli, I think this could go into Emacs 28. WDYT? > > No, it's too radical, and the problem it fixes is too obscure. Let's > install it on master, please. I'll wait a couple of days and do that if Carlos doesn't see any problems. Thanks, martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-19 9:25 ` martin rudalics @ 2021-10-19 12:22 ` Eli Zaretskii 2021-10-22 9:04 ` martin rudalics 1 sibling, 0 replies; 97+ messages in thread From: Eli Zaretskii @ 2021-10-19 12:22 UTC (permalink / raw) To: martin rudalics; +Cc: carlosjosepita2, 38181 > Cc: carlosjosepita2@gmail.com, 38181@debbugs.gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Tue, 19 Oct 2021 11:25:09 +0200 > > > There is, for some value of "display": this function actually > > generates a glyph row in the glyph matrix. > > The same thing happens with 'pos-visible-in-window-p', I suppose. If it calls display_mode_line, yes. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-19 9:25 ` martin rudalics 2021-10-19 12:22 ` Eli Zaretskii @ 2021-10-22 9:04 ` martin rudalics 2021-10-22 14:55 ` Carlos Pita 1 sibling, 1 reply; 97+ messages in thread From: martin rudalics @ 2021-10-22 9:04 UTC (permalink / raw) To: Eli Zaretskii; +Cc: carlosjosepita2, 38181 close 38181 29.1 quit > > No, it's too radical, and the problem it fixes is too obscure. Let's > > install it on master, please. > > I'll wait a couple of days and do that if Carlos doesn't see any > problems. Done. Bug closed. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-22 9:04 ` martin rudalics @ 2021-10-22 14:55 ` Carlos Pita 2021-11-07 18:48 ` Carlos Pita 0 siblings, 1 reply; 97+ messages in thread From: Carlos Pita @ 2021-10-22 14:55 UTC (permalink / raw) To: martin rudalics; +Cc: 38181 Hi Martin, > > I'll wait a couple of days and do that if Carlos doesn't see any > > problems. sorry I didn't take that couple of days in a literal sense, but was waiting for the weekend to give it a more thorough test. In any case, I'll keep you informed of the results. Thank you very much to both of you for your patience in dealing with me and for your effort in finding a solution to this problem! ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-22 14:55 ` Carlos Pita @ 2021-11-07 18:48 ` Carlos Pita 0 siblings, 0 replies; 97+ messages in thread From: Carlos Pita @ 2021-11-07 18:48 UTC (permalink / raw) To: martin rudalics; +Cc: 38181 Just for the record: I've been running emacs-28 with Martin's patch for a couple of weeks now and I've not seen any issue that may be related to it. I've not done any tests on master yet. ^ permalink raw reply [flat|nested] 97+ messages in thread
[parent not found: <CAEOO5TemeSrLkudEBRbMaLrCXq7A0y5uv+SdcfZwMo77onMMoA@mail.gmail.com>]
* bug#38181: Actual height of mode-line not taken into account [not found] ` <CAEOO5TemeSrLkudEBRbMaLrCXq7A0y5uv+SdcfZwMo77onMMoA@mail.gmail.com> @ 2021-10-19 10:09 ` martin rudalics 0 siblings, 0 replies; 97+ messages in thread From: martin rudalics @ 2021-10-19 10:09 UTC (permalink / raw) To: Carlos Pita, Eli Zaretskii; +Cc: 38181 > 3) Now I add a redisplay before the fit: > > (progn > (switch-to-buffer-other-window "popup") > (erase-buffer) > (insert (mapconcat #'number-to-string (number-sequence 1 30) "\n")) > (redisplay t) > (fit-window-to-buffer)) > > Again, only about half of the numbers are visible and the window looks > as if its buffer has been scrolled down. But now by scrolling up I can > check that all the numbers fit the window. So the height of the window > is right but there is that unnecessary scrolling down of the contents. > > 4) Now I repeat with the forced redisplay even earlier: > > (progn > (switch-to-buffer-other-window "popup") > (redisplay t) > (erase-buffer) > (insert (mapconcat #'number-to-string (number-sequence 1 30) "\n")) > (fit-window-to-buffer)) > > This seems to work around the issue. > > I believe that in 3 there is some miscalculation during the insertion > of text into the buffer that forces a scroll, but I'm having a hard > time trying to explain that. Anyway, it's another case the > redisplay-before-fit advice can't cope with. In (3) the redisplay happens _after_ the insertion so redisplay may have to scroll the buffer to make point, which is at its maximum, visible. The subsequent 'fit-window-to-buffer' and the final implicit redisplay won't change the window's start position after that. If the window after the split were large enough to encompass 30 lines, this won't happen. In (4) the redisplay happens _before_ the insertion so erasing the buffer will set 'window-start' to 'point-min' and the implicit redisplay at the end will see point within the visible portion and not change 'window-start'. martin ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 5:13 ` Carlos Pita 2021-10-15 7:05 ` martin rudalics @ 2021-10-15 7:51 ` Eli Zaretskii 2021-10-15 8:00 ` Carlos Pita 1 sibling, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2021-10-15 7:51 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 > From: Carlos Pita <carlosjosepita2@gmail.com> > Date: Fri, 15 Oct 2021 02:13:14 -0300 > > I'm seeing what I believe is an instance of this issue in a vanilla > build from emacs-28 branch, ns/cocoa backed. > > Here are some instructions for reproduction: > https://github.com/seagle0128/doom-modeline/issues/480#issue-1027051204 That bug was about doom-modeline and similar extensions, and it was never fixed (because we found the solution to be elusive and nowhere near simple), so it's small wonder the issue still exists. Is there something new you see that you think will help us in dealing with this problem? If so, could you please describe the new information? Thanks. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 7:51 ` Eli Zaretskii @ 2021-10-15 8:00 ` Carlos Pita 2021-10-15 10:40 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: Carlos Pita @ 2021-10-15 8:00 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 Hi Eli, > Is there something new you see that you think will help us in dealing > with this problem? If so, could you please describe the new > information? I don't know if it will help you dealing with the problem, but I believe that what I've just answered to Martin is new, indeed the workaround that was working before carefully deactivated itself after the first forced redisplay. What I can't see is why after the first redisplay, if the modeline hasn't changed, the popup will be chopped like that (a fortiori considering that previously it was correctly laid out). Best regards, Carlos ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 8:00 ` Carlos Pita @ 2021-10-15 10:40 ` Eli Zaretskii 2021-10-15 18:33 ` Carlos Pita 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2021-10-15 10:40 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 > From: Carlos Pita <carlosjosepita2@gmail.com> > Date: Fri, 15 Oct 2021 05:00:19 -0300 > Cc: 38181@debbugs.gnu.org > > I don't know if it will help you dealing with the problem, but I > believe that what I've just answered to Martin is new, indeed the > workaround that was working before carefully deactivated itself after > the first forced redisplay. What I can't see is why after the first > redisplay, if the modeline hasn't changed, the popup will be chopped > like that (a fortiori considering that previously it was correctly > laid out). Does the recipe involve any change in the appearance of the mode line? If not, then it's a separate issue. ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 10:40 ` Eli Zaretskii @ 2021-10-15 18:33 ` Carlos Pita 2021-10-15 19:08 ` Eli Zaretskii 0 siblings, 1 reply; 97+ messages in thread From: Carlos Pita @ 2021-10-15 18:33 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 Hi Eli, > Does the recipe involve any change in the appearance of the mode line? > If not, then it's a separate issue. Yes, it does, it's step 1 of the recipe. Best regards, Carlos ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 18:33 ` Carlos Pita @ 2021-10-15 19:08 ` Eli Zaretskii 2021-10-15 20:09 ` Carlos Pita 0 siblings, 1 reply; 97+ messages in thread From: Eli Zaretskii @ 2021-10-15 19:08 UTC (permalink / raw) To: Carlos Pita; +Cc: 38181 > From: Carlos Pita <carlosjosepita2@gmail.com> > Date: Fri, 15 Oct 2021 15:33:00 -0300 > Cc: 38181@debbugs.gnu.org > > > Does the recipe involve any change in the appearance of the mode line? > > If not, then it's a separate issue. > > Yes, it does, it's step 1 of the recipe. "Step 1" being the original recipe of Jonas? Then what is new about this report that Jonas didn't already report and we didn't already discuss and analyze? ^ permalink raw reply [flat|nested] 97+ messages in thread
* bug#38181: Actual height of mode-line not taken into account 2021-10-15 19:08 ` Eli Zaretskii @ 2021-10-15 20:09 ` Carlos Pita 0 siblings, 0 replies; 97+ messages in thread From: Carlos Pita @ 2021-10-15 20:09 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 38181 Hi Eli, > "Step 1" being the original recipe of Jonas? Then what is new about > this report that Jonas didn't already report and we didn't already > discuss and analyze? Perhaps the new steps? I will provide my perspective and the formal procedure to reproduce the issue one last time. Then I let it up to you to decide if you have already discussed it because the exact relationship between what I see and what happens under the hood is way beyond my knowledge. If after that you still feel that I should file a new ticket, just let me know and I will gladly do it as a mere automaton. In message #20 you said: > Why the need to use advising? Your recipe shows that calling > redisplay before fit-window-to-buffer also solves the problem. Can't > you do something like that only when you add such tall images to the > mode line? In message #29: > Code like 'fit-window-to-buffer' works on the text area > only, it doesn't care whether a scroll bar or mode line changed size > since last redisplay. In message #33: > If this is to make the mode line prettier, then it should be done > [calling redisplay] once, at the beginning of a session, right? In message #39 Martin 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. There are more examples but I hope you get the gist of it. Moreover, there is the "conventional" workaround [1] which likely was a consequence of the discussion above. The advice deliberately deactivates itself after the first redisplay. So from what I can see there was some consensus regarding that a single call to redisplay after changing the modeline geometry would suffice. Now that's exactly what I am bringing into question here. I reiterate the recipe: 1. Execute the code. 2. Call test-popup and check that the layout is wrong. 3. Redefine test-popup with (redisplay) uncommented. 4. Call it again and check that the layout is right. 5. Redefine test-popup with (redisplay) commented again. 6. Call it again and check that the layout is wrong again. Specifically, step 6 contradicts the statement that doing a redisplay after modifying the modeline geometry is enough. Now you might say: but then why are you reporting this here, it is not a modeline issue. To what I would answer: you still need step 1 that involves modifying the modeline. And if you then asked: but what's new wrt what was already discussed? I would answer exactly like I'm answering now and we would be going around in circles. I understand the issue is confusing but sadly I don't know enough about the subject to make it clearer to you. Maybe I'm not saying anything new about the internals you already know, but from outside it looks different. Best regards, Carlos --- [1] https://github.com/tarsius/moody/blob/9b679400ca885b8ff51bcfd75b87f79d66c0ee26/moody.el#L303 ^ permalink raw reply [flat|nested] 97+ messages in thread
end of thread, other threads:[~2021-11-07 18:48 UTC | newest] Thread overview: 97+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2019-11-12 16:52 bug#38181: Actual height of mode-line not taken into account Jonas Bernoulli 2019-11-13 8:03 ` martin rudalics 2019-11-15 13:50 ` Eli Zaretskii 2019-11-15 13:48 ` Eli Zaretskii 2019-11-15 14:24 ` Jonas Bernoulli 2019-11-15 15:11 ` Eli Zaretskii 2019-11-15 23:51 ` Jonas Bernoulli 2019-11-16 8:38 ` Eli Zaretskii 2019-11-16 14:54 ` Jonas Bernoulli 2019-11-16 15:59 ` Eli Zaretskii 2019-11-17 16:17 ` Jonas Bernoulli 2019-11-15 19:38 ` Eli Zaretskii 2019-11-16 8:20 ` martin rudalics 2019-11-16 8:35 ` Eli Zaretskii 2019-11-16 8:57 ` martin rudalics 2019-11-16 10:57 ` Eli Zaretskii 2019-11-16 19:28 ` martin rudalics 2019-11-16 19:44 ` Eli Zaretskii 2019-11-17 8:55 ` martin rudalics 2019-11-17 17:26 ` Eli Zaretskii 2019-11-17 18:15 ` martin rudalics 2019-11-17 18:35 ` Eli Zaretskii 2019-11-18 9:44 ` martin rudalics 2019-11-18 15:42 ` Eli Zaretskii 2019-11-18 18:45 ` martin rudalics 2020-05-02 18:06 ` martin rudalics 2020-05-04 13:46 ` Eli Zaretskii 2020-05-04 15:04 ` martin rudalics 2020-05-04 17:05 ` martin rudalics 2020-05-05 8:32 ` martin rudalics 2020-05-05 14:58 ` Eli Zaretskii 2020-05-05 16:57 ` martin rudalics 2020-05-05 17:11 ` Eli Zaretskii 2020-05-06 6:50 ` martin rudalics 2020-05-06 9:27 ` Eli Zaretskii 2020-05-06 9:44 ` martin rudalics 2020-05-06 14:16 ` Eli Zaretskii 2020-05-07 8:34 ` martin rudalics 2020-05-07 12:41 ` Eli Zaretskii 2020-05-06 14:44 ` Eli Zaretskii 2020-05-07 8:34 ` martin rudalics 2020-05-10 14:33 ` Eli Zaretskii 2020-05-11 8:30 ` martin rudalics 2020-05-15 15:00 ` Eli Zaretskii 2020-05-16 8:44 ` martin rudalics 2020-05-16 10:46 ` Eli Zaretskii 2019-11-16 15:27 ` Jonas Bernoulli 2019-11-16 16:19 ` Eli Zaretskii 2019-11-16 19:30 ` martin rudalics 2019-11-16 19:45 ` Eli Zaretskii 2019-11-17 9:01 ` martin rudalics 2019-11-17 17:22 ` Eli Zaretskii 2019-11-17 18:16 ` martin rudalics 2019-11-17 18:39 ` Eli Zaretskii 2019-11-18 9:45 ` martin rudalics 2019-11-18 15:46 ` Eli Zaretskii 2019-11-18 18:46 ` martin rudalics 2019-11-17 16:21 ` Jonas Bernoulli 2019-11-16 19:30 ` martin rudalics 2021-10-15 5:13 ` Carlos Pita 2021-10-15 7:05 ` martin rudalics 2021-10-15 7:26 ` Carlos Pita 2021-10-15 7:54 ` Eli Zaretskii 2021-10-15 8:18 ` Carlos Pita 2021-10-15 8:35 ` martin rudalics 2021-10-15 8:45 ` Carlos Pita [not found] ` <CAEOO5TdaV=tdj23afEcqJGZf4JM3VVQ6TFt4F3q6k6d=f4_36w@mail.gmail.com> [not found] ` <776a35b7-1920-2987-88ae-6dcab958a8e4@gmx.at> 2021-10-15 9:07 ` Carlos Pita 2021-10-16 7:55 ` martin rudalics 2021-10-16 11:23 ` Carlos Pita 2021-10-16 16:48 ` martin rudalics 2021-10-16 18:00 ` Carlos Pita 2021-10-16 19:41 ` martin rudalics 2021-10-16 19:57 ` Carlos Pita 2021-10-16 21:27 ` Carlos Pita 2021-10-17 6:06 ` Eli Zaretskii 2021-10-17 6:45 ` Carlos Pita 2021-10-17 8:34 ` martin rudalics 2021-10-17 8:34 ` martin rudalics 2021-10-17 8:33 ` martin rudalics 2021-10-18 9:34 ` martin rudalics 2021-10-18 15:56 ` Carlos Pita 2021-10-18 17:44 ` martin rudalics 2021-10-18 18:27 ` Eli Zaretskii 2021-10-18 23:35 ` Carlos Pita 2021-10-19 0:11 ` Carlos Pita 2021-10-19 9:25 ` martin rudalics 2021-10-19 12:22 ` Eli Zaretskii 2021-10-22 9:04 ` martin rudalics 2021-10-22 14:55 ` Carlos Pita 2021-11-07 18:48 ` Carlos Pita [not found] ` <CAEOO5TemeSrLkudEBRbMaLrCXq7A0y5uv+SdcfZwMo77onMMoA@mail.gmail.com> 2021-10-19 10:09 ` martin rudalics 2021-10-15 7:51 ` Eli Zaretskii 2021-10-15 8:00 ` Carlos Pita 2021-10-15 10:40 ` Eli Zaretskii 2021-10-15 18:33 ` Carlos Pita 2021-10-15 19:08 ` Eli Zaretskii 2021-10-15 20:09 ` Carlos Pita
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).