Skip to content

Report real cell pixel dimensions before the first redraw - #643

Merged
dakra merged 1 commit into
dakra:mainfrom
ashlineldridge:fix-cold-cell-size-report
Sep 13, 2026
Merged

dakra merged 1 commit into
dakra:mainfrom
ashlineldridge:fix-cold-cell-size-report

Conversation

@ashlineldridge

Copy link
Copy Markdown
Contributor

Kitty graphics images placed by a program's first output come out
stretched: a square image renders about 2.5 times too tall on a 9 by 23
pixel cell. The program is not at fault. It asked for the cell size
(XTWINOPS CSI 16 t) at startup and the terminal answered 1;1.
Renderer.init seeds the terminal with a 1 by 1 placeholder cell, and
the real cell geometry a resize carries is only queued until the next
redraw commits it. The first redraw happens only after the first PTY
output arrives, so the reply is wrong exactly when startup queries run.
The full investigation and a reproducer are in #642.

Renderer.resize now applies the cell pixel geometry immediately,
against the current grid, so the seeding call in ghostel--init-buffer
takes effect before the process starts. The row and column commit stays
deferred to the next redraw for scrollback promotion, as before, and
the CSI 14, 16, and 18 t replies stay mutually consistent while a grid
change is pending. The pixel fields are written directly rather than
through Terminal.resize because that call also resets synchronized
output mode, which Renderer.redraw relies on to suppress rendering
while a program holds mode 2026. This is the same class of bug as the
ghostel-compile 1 by 1 cell fix in 0.49.0.

A new ERT test creates a terminal, seeds the cell dimensions the way
ghostel--init-buffer does, and checks the CSI 14, 16, and 18 t replies
before any redraw, plus their consistency while a grid resize is
pending. It fails on main and passes with this change. The Zig unit
tests, the full elisp suite, and make lint pass on macOS with Zig
0.16.0 and Emacs 31.0.91. Running the patched module in a live Emacs,
a cold CSI 16 t query in a fresh terminal answers the same as a warm
one, and CSI 14 t reports real pixels instead of echoing the grid
size.

The ws_xpixel/ws_ypixel fields of TIOCSWINSZ are still sent as
zero; the issue notes that gap as optional and this change leaves it
for a follow-up.

Fixes #642

A resize only queued its cell pixel geometry until the next redraw
committed it, and Renderer.init seeds the terminal with a 1x1
placeholder cell, so a program that queried XTWINOPS CSI 14/16 t at
startup read 1x1 cells and laid out its kitty graphics as if cells
were square: about 2.5x too tall on a 9x23 cell.  The first redraw
happens only after the first PTY output arrives, so the reply was
wrong exactly when startup queries run.

Renderer.resize now applies the cell pixel geometry immediately,
against the current grid, while the row/column commit stays deferred
to the next redraw for scrollback promotion (see GhostelTerm.resize).
The pixel fields are written directly instead of through
Terminal.resize because that call also resets synchronized-output
mode, which redraw suppression relies on.

Fixes dakra#642
@dakra
dakra force-pushed the fix-cold-cell-size-report branch from 4500a0c to 9bf8c7a Compare September 13, 2026 17:00
@dakra

dakra commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Thanks and sorry for the delay.
I shortened the super long Claude comments and rebased on latest main.

@dakra
dakra merged commit 9bf8c7a into dakra:main Sep 13, 2026
30 checks passed

This branch was successfully deployed

1 active deployment
github-pages — 9bf8c7a7 Deployed Sep 13, 2026 by dakra via deploy #188
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Kitty images render vertically stretched because CSI 16 t reports a 1x1 px cell until the first redraw

2 participants