• src/doors/syncmoo1/syncmo

    From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Tue Jul 21 01:49:00 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/d6ab9c05fab10fa46155986f
    Modified Files:
    src/doors/syncmoo1/syncmoo1_io.c
    Log Message:
    syncmoo1: drain paced-frame acks before the sixel vscale probe

    On xterm (and any terminal that draws a sixel at its encoded size rather
    than honoring the raster pan), the picture intermittently rendered at
    half height and the in-game mouse cursor tracked at twice the vertical
    rate -- the game's idea of the pointer drifted from the hardware cursor.

    Both symptoms were one cause: a wrong vertical-scaling verdict. The probe paints two thin slivers (pan=1, then pan=2), each bracketed by a cursor- position report, and infers "scales" when the pan=2 sliver advanced the
    cursor further than the pan=1 one. The three reports must be the probe's
    own [home, after-pan1, after-pan2].

    But sm_io_vscale_probe() fires from present(), AFTER the first few frames
    have already gone out and been paced -- and each paced frame is acked by a cursor report of its own. When a frame's ack was still in flight as the
    probe armed, sm_input_vscale_collect() claimed that straggling pace-ack as
    the probe's `home`, shifting the window by one: the true [1,3,5] (equal
    two-row advances -- xterm ignores pan) was read as [1,1,3] and looked like
    it had scaled. The door then sent a half-height pan=2 encode to a terminal
    that draws at the encoded size, and sm_map_mouse() -- which assumes the
    image fills the full fitted height -- put the cursor at 2x the Y rate. The
    race made it intermittent: whether a leftover ack landed inside the three- report window depended on timing.

    Fix: quiesce the pace pipeline before arming. Wait for every outstanding present()-sent DSR to be acked (draining routes those reports to sm_io_pace_ack(), since the collector is not yet armed), so the probe's
    own three reports are the only cursor reports in flight once it arms. The synchronous probe that follows blocks further presents, so no new DSR can appear before the verdict. Bounded by the probe's existing grace; a silent terminal just proceeds to the safe full-size fallback.

    This restores the invariant the sibling doors already hold a different way
    -- SyncDOOM and SyncDuke run the probe before the first frame (SyncDuke
    holds frame one for it; SyncDOOM reads its own accumulator with nothing in flight), so a stray report is inert there. syncmoo1 paints early frames,
    so it drains instead. Verified on xterm -ti vt340: the probe now collects
    a clean [1,3,5], the verdict is "does not scale", and frames stay pan=1 at
    full height with the cursor aligned.
    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net