fix(frame,layout): keep the mini-window one line of the current font after a font change - #353
Open
tag-und-nacht wants to merge 2 commits into
Open
Conversation
…hange A frame is created with the startup font (Menlo 10, 11px lines on macOS) and user init then sets the default face to a larger font (17px lines). `sync_live_frame_font_state_in_state` updated `char_height` but the minibuffer window kept the 11px it was created with: `window_text_area_bounds_with_chrome` carries the mini-window's pixel height forward verbatim, so every one-line message was laid out 17px tall in an 11px window and showed only its top 11px until something else resized the mini-window (e.g. entering and leaving the minibuffer). GNU's `set_new_font_hook` ends in `adjust_frame_size (..., 3, false, Qfont)` (`ns_new_font`, src/nsterm.m:11425-11428; `x_new_font`, src/xterm.c:27178-27181, emacs-31.0.90). With `font` outside `frame-inhibit-implied-resize` (the NS/X default, src/frame.c:7684-7687) that asks the window system for a frame keeping FRAME_LINES at the new line height and returns (src/frame.c:993-998); the toolkit's `change_frame_size` re-enters `adjust_frame_size` with inhibit 5 (src/nsterm.m:1906, src/dispnew.c:6726-6728), which reaches `resize_frame_windows` (src/frame.c:1076-1082): the mini-window gets `unit + decorations` pixels with `unit` the new FRAME_LINE_HEIGHT (src/window.c:5051-5053,5125-5128) and every window's character edges are re-derived. Apply that one-line rule at the font boundary through the existing `shrink_mini_window` (the mini-window has no mode line, so its box height is `unit`), and re-derive the character edges for any metric change, own or shared minibuffer. Declared, not ported: the implied native resize itself (the frame keeps its pixel size and the root loses lines), the `width`/`height` parameters in the new units, and the toolkit gates that skip the resize (NS fullscreen, X tooltip frames). Verified on macOS: with the user's PragmataPro config the minibuffer went from 11px to 17px at 17px lines and the surface readback shows the echo message with its descenders intact in the same 502x462 window. Linux and Windows were not run; no platform-specific code is touched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NxL1hNkQvGiUyXAHJJuyXC
… check Adversarial review of the previous commit: fixing the font boundary alone left the mechanism. A mini-window shorter than one line of the current font can also arrive through `set-window-configuration` (the saved leaf's 11px bounds are restored verbatim, hooks.rs) or through the engine's own metrics sync (`frame.char_height = geometry.metrics.line_height`, which never touches the mini-window), and the redisplay-time check counted its allocation as `floor(11 / 17).max(1) = 1` row, so a one-line message never asked to grow and the echo area stayed clipped. GNU `resize_mini_window` compares the content's pixel height with the window's (`old_height = WINDOW_BOX_TEXT_HEIGHT (w)`, src/xdisp.c:13276; `height > old_height` / `height != old_height`, 13395-13406) and `grow_mini_window` adds exactly that difference (src/window.c:5896-5930), so the window lands on the content height: one line of the font. - `mini_window_rows` (neovm-core): the one rule for how many whole rows a mini-window height holds, shared by the engine's allocation check and by `grow_mini_window_with_max_lines`. A height shorter than one line holds zero rows, not one, so the grow-only comparison fires as GNU's does; a height within half a pixel of `k` rows is `k` rows, so an f32 unit such as 11.9px cannot make a 3-row window count as 2 and turn the grow it triggers into a no-op that the relayout loop would retry until its budget was gone (second review). - `grow_mini_window_with_max_lines`: land on whole rows of the current unit from the current row count instead of adding rows to the current pixel height, which compounded a stale base (11px + 1 row of 17px gave 28px where GNU gives 17px; a 22px base under 19px lines gave 60px for three rows where GNU gives 57px). Declared, not ported: GNU's unit adds `line-spacing` placed above the line (src/xdisp.c:13324-13325) and grows by exact pixels, so image or line-spacing content lands on a row multiple here where GNU keeps the pixel height; content is never under-grown since the required rows are `ceil(content / char_h)`. Also corrects the same-line-height test's comment from the first commit: GNU skips `resize_frame_windows` there only for a frame whose height is a whole number of lines. Tests: the engine grows a planted sub-line mini-window to exactly one realized line under a one-line echo message (red before: it stayed at 9px); `grow_mini_window` lands on 17px and 57px from stale bases and on four rows from three at an 11.9px unit; `mini_window_rows` at the f32 edge. Verified on macOS; Linux and Windows were not run (no platform-specific code is touched). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NxL1hNkQvGiUyXAHJJuyXC
eval-exec
requested review from
eval-exec
and
a balanced review from Copilot
September 6, 2026 06:20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On macOS, user init that switches the default face from the startup font (Menlo 10, 11px lines) to a larger one (PragmataPro, 17px lines) left the echo area clipped: every one-line message showed only its top 11px until the user entered and left the minibuffer. The native window and the frame agreed on 502x430px throughout, and a surface readback matched the on-screen pixels row for row, so this was not window rounding: the minibuffer window kept the 11px it was created with while the frame's line height became 17px.
Two commits, each mirroring the GNU site that keeps the mini-window at one line of the current font (emacs-31.0.90):
fix(frame): the font boundary. GNU'sset_new_font_hookends inadjust_frame_size (..., 3, false, Qfont)(ns_new_font, src/nsterm.m:11425-11428;x_new_font, src/xterm.c:27178-27181). Withfontoutsideframe-inhibit-implied-resize(the NS/X default, src/frame.c:7684-7687) that requests a frame keeping FRAME_LINES at the new line height and returns (src/frame.c:993-998); the toolkit'schange_frame_sizere-enters with inhibit 5 (src/nsterm.m:1906, src/dispnew.c:6726-6728) and reachesresize_frame_windows(src/frame.c:1076-1082), which gives the mini-windowunit + decorationspixels withunitthe new FRAME_LINE_HEIGHT (src/window.c:5051-5053,5125-5128) and re-derives every window's character edges.sync_live_frame_font_state_in_statenow applies that one-line rule through the existingshrink_mini_windowwhen the line height changes, and resyncs the character edges for any metric change, own or shared minibuffer.fix(layout): the redisplay mechanism. A sub-line mini-window can also arrive throughset-window-configuration(the saved leaf's bounds are restored verbatim) or the engine's own metrics sync, and the redisplay-time check counted its allocation asfloor(11 / 17).max(1) = 1row, so a one-line message never asked to grow. GNUresize_mini_windowcompares pixel heights (src/xdisp.c:13276,13395-13406) andgrow_mini_windowadds exactly the difference (src/window.c:5896-5930).mini_window_rowsis now the one rule for how many whole rows a mini-window height holds, shared by the engine's allocation check and bygrow_mini_window_with_max_lines, which lands on whole rows of the current unit instead of adding rows to a stale pixel base (11px + 1 row of 17px gave 28px where GNU gives 17px). A height within half a pixel ofkrows counts ask, so an f32 unit such as 11.9px cannot make a 3-row window count as 2 and turn the grow into a no-op the relayout loop would retry until its budget was gone.Declared, not ported: the implied native resize itself (the frame keeps its pixel size and the root loses lines; a design note for that follow-up is in progress), the
width/heightframe parameters in the new units (resize_pixelwiseowns those), the toolkit gates that skip the resize (NS fullscreen, X tooltip frames), and GNU's unit adding above-lineline-spacingwith exact-pixel growth (row multiples here; content is never under-grown).Tests (red first)
xfaces::font_size_test::default_face_font_change_resizes_mini_window_to_one_line_of_the_new_font: 11px stayed 11px before, 18px after; plus a previously grown (33px) mini-window resetting to one line, an unchanged line height leaving it alone, and a frame without its own mini-window resyncing its root.engine::tests::inactive_echo_area_grows_a_sub_line_mini_window_to_one_line_of_the_font: a planted sub-line mini-window under a one-line echo message grows to exactly one realized line (stayed at 9px before).window_test::grow_mini_window_lands_on_whole_rows_of_the_current_unit(17px from 11px, 57px from 22px at 19px lines),grow_mini_window_always_moves_from_a_whole_row_count_at_a_fractional_unit,mini_window_rows_tolerates_float_division_at_whole_rows.Verification
cargo fmt --all --checkclean; clippy clean on the changed lines (thenever_looperrors inwindow_test.rsandprocess/testsare pre-existing onmain).cargo test -p neovm-core --libscoped to the font, mini-window and window_cmds tests: 320 pass;cargo test -p neomacs-layout-engine --libecho and minibuffer tests pass exceptlayout_frame_rust_preserves_propertized_echo_message_faces, which fails identically onmainhere (ZWJ clustering).cargo xtask --release, the minibuffer goes from 11px to 17px at 17px lines during init and the surface readback shows the message with its descenders intact in the same 502x462 window.set-window-configurationpath, the GNU path description, the f32 row edge) are what the second commit and the amended first address.Not run: Linux, Windows, TTY (no platform-specific code is touched).
🤖 Generated with Claude Code
https://claude.ai/code/session_01NxL1hNkQvGiUyXAHJJuyXC