• src/doors/termgfx/test/test_term_sdm.csrc/doors/syncdoom/syncdoom.c sr

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Tue Aug 4 22:12:22 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/b3caee6dd45544986bcbd5d1
    Added Files:
    src/doors/termgfx/test/test_term_sdm.c
    Modified Files:
    src/doors/syncdoom/syncdoom.c src/doors/syncduke/syncduke.h syncduke_input.c syncduke_io.c src/doors/syncmoo1/syncmoo1.h syncmoo1_input.c syncmoo1_io.c src/doors/syncretro/syncretro.h syncretro_input.c syncretro_io.c test_axis.c src/doors/termgfx/caps.h sixel.c sixel.h term.c term.h termgfx_termio.c src/doors/termgfx/test/CMakeLists.txt
    Log Message:
    doors: ask each terminal for the mode-80 sense IT reads as sixel-at-cursor

    DEC private mode 80 (DECSDM) decides where a sixel lands: at the text
    cursor, or at the screen origin with the cursor ignored. Every door here
    wants the cursor, because that is how a frame is centered and how a
    dirty-rect patch reaches the cells it belongs over.

    cterm reversed the mode's set/reset sense in 117de27530 (2026-06-28),
    revision 1.327 -> 1.328. SyncTERM 1.8, the current release, ships 1.327.
    So the "\x1b[?80l" termgfx_term_enter has always sent asks a released
    SyncTERM for the opposite of what it means: the picture anchored top-left
    and the cursor ignored.

    On a full-screen door that cost only the centering, which is why it went unnoticed. SyncRetro made it visible. Its frames are portrait arcade
    cabinets with wide margins, and since 39b1af971b (2026-07-21) it patches
    the cells that changed rather than repainting, positioning each patch with nothing but the cursor address in front of it. Every patch therefore landed
    in the top-left corner, one per frame, over the picture drawn there: a
    block of scrambled graphics that redraws continuously while the game plays below it. Reported against SyncArcade on vert (GitLab #1214).

    termgfx_term_sixel_at_cursor() answers which of the two sequences a given
    peer reads as draw-at-cursor, from the CTerm revision in its DA1 reply. term_enter still commits to the DEC-correct ?80l before anyone has
    identified themselves; a door corrects it when the reply lands, and
    repaints, since whatever is on the terminal was drawn under the other rule. SyncDOOM needs no correction: it captures the revision in its startup probe before it emits mode 80 at all.

    termgfx_term_leave drops its ?80h, and no door replaces it. That sequence
    was the old polarity's idea of the default, and from cterm 1.328 on it left
    the terminal origin-anchored after every door exit. Nothing is needed in
    its place: draw-at-cursor is every terminal's own default, and the
    correction above has already established it.

    SyncDOOM stops toggling mode 80 per tier. It reset the mode to stop a full-height sixel scrolling the page; the bottom-cell reserve in compute_geometry() does that now, on every terminal rather than only those implementing mode 80, so the sequence is free to mean what it says.

    termgfx_sixel_vscale_probe() led with a bare ?80l of its own, which ran
    after the correction and silently undid it. It takes the peer's revision
    now. The probe measures how far the cursor advanced past each sliver, so
    the wrong sequence also made it read "does not scale" on a terminal that
    does.

    Verified on the wire against each door's real binary, driven by a fake
    terminal answering DA1 as 1.327 and as 1.332: the corrective sequence
    precedes the first sixel in every case, and no door emits the
    origin-anchoring one to either peer. test_term_sdm covers the polarity
    table and the 1328 boundary.

    Reported by Keyop.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net