https://gitlab.synchro.net/main/sbbs/-/commit/d10053d16770eb07faf62b30
Added Files:
src/doors/termgfx/test/test_termgfx_termio_fitcanvas.c
Modified Files:
src/doors/termgfx/termgfx_termio.c src/doors/termgfx/test/unit_termgfx_termio.sh
Log Message:
termgfx: fit against the canvas the terminal declared, not a 640x400 guess
termgfx_termio.c starts at g_canvas_w/h = 640x400 and corrects it from the ESC[4;h;wt reply to ESC[14t. SyncTERM never sends that reply -- its CSI t
is the CTerm-private palette setter -- so on SyncTERM the guess stood, and every fit, centering and cell-size derivation was computed against it.
The guess is only right in 80x25 and 80x50. SyncTERM's 80x43 canvas is
640x350 (43 rows of 8px, plus 6 scanlines no character cell covers), and a captured session running Maniac Mansion there traced
canvas=640x400? emit=640x400@0,0 cell=10
-- a 400-line frame emitted into a 350-line canvas, and a 10px cell derived against a real 8. SyncTERM 1.9 discards the oversized JXL blob whole, so
the screen stayed blank; 1.10 clips it, so the picture lost its bottom. The wrong cell size separately misplaced the sixel tier's CUP origin and its dirty-rect boxes. 80x28 (640x392) overshoots by 8 lines the same way;
80x30 (640x480) merely wastes the difference.
The terminal had already answered with the right number. SyncTERM replies
to XTSMGRAPHICS with charwidth*cols x charheight*rows -- its drawable area, 640x336 for that session -- but the reply landed in g_gfx_max_w/h and was applied to the SIXEL tier's ceiling alone.
termgfx_fit_canvas() now clamps the canvas to that declared ceiling, and termgfx_fit_cell_w/h() derive the cell from it over the real 999;999-CPR
grid whenever the terminal reports no cell size of its own. Both are used everywhere the geometry is computed: the fit, the centering, the sixel CUP re-derivation in present() and present_rgbx(), the dirty-box cell size, and
the mouse mapping. The same session now traces
canvas=640x400? fit=640x336 emit=537x336@51,0 cell=8
Clamping rather than adopting is what keeps this safe for a terminal whose reply is a true graphics ceiling rather than a text area (xterm's
~1000x1000): staying inside a declared ceiling is what a ceiling is for,
and such a terminal answers ESC[14t as well, so its real canvas is already known there.
The mouse mapping carried its own copy of the 8x16 guess. Converting a
1-based text cell to canvas pixels with an over-tall cell walks off the
bottom of the image and clamps, so on that terminal every row below about
21 of 42 mapped to the last game row -- felt as the pointer drifting
further out the further down the screen it moved. Its test asserts the mid-screen row maps mid-picture and that the rows produce distinct values:
the endpoints prove nothing, being deliberately snapped to the image edges
so the extreme game rows stay reachable on a cell-granular terminal.
The trace line gains fit=WxH beside canvas=WxH, since the gap between the
two is where this class of bug lives.
Affects every door on this module -- syncconquer, syncretro, syncrpg, syncscumm. 80x25 and the no-ceiling fallback are asserted unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <
noreply@anthropic.com>
---
þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net