• src/doors/syncconquer/door/door_io.c src/doors/syncdoom/syncdoom.c src

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Sat Jul 11 15:00:28 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/969a17630973a69b89d980ad
    Modified Files:
    src/doors/syncconquer/door/door_io.c src/doors/syncdoom/syncdoom.c src/doors/syncduke/syncduke.h syncduke_input.c syncduke_io.c src/doors/syncmoo1/syncmoo1_input.c src/doors/syncretro/syncretro_audio.c syncretro_audio.h syncretro_input.c syncretro_io.c src/doors/termgfx/apc.c apc.h audio.c audio.h audio_mgr.c audio_mgr.h caps.c caps.h
    Log Message:
    doors: adopt SyncTERM APC blob media (audio + video), no cache files

    SyncTERM's blob APC verbs (Deuce, ef5b7f98a3) carry base64 media inline and decode straight to a slot/screen with no cache file, gated on CTerm version
    = 1.329. This teaches termgfx and all five doors to use them when the client is new enough, falling back to the existing cache path otherwise.

    Detection (termgfx/caps.{c,h}):
    - termgfx_caps_cterm_version() reads the version from the DA1 reply
    ("ESC[=67;84;101;114;109;MAJ;MIN;...c", 67.. spells "Cterm"): MAJ*1000+MIN.
    - Named thresholds TERMGFX_CTERM_VER_{PPM=1002,BLOB=1329} replace scattered
    magic numbers (syncdoom's inline copy now calls the shared helper).

    Audio (termgfx/audio.c, audio_mgr.c):
    - termgfx_audio_load_blob_file()/_load_blob() build A;LoadBlob (WAV/OGG).
    - stream_chunk() ships inline when the manager's blob_ok is set, else the
    legacy Store+Load with rotating cache names. Wins where audio actually
    streams: syncconquer FMV and syncretro game audio (its OGG chunks now skip
    the cache ring). The SFX/music doors keep the upload-once cache (better for
    repeated sounds) -- blob_ok is set there only for uniformity.

    Video (termgfx/apc.c):
    - termgfx_apc_image() gains a blob mode: C;DrawJXLBlob/DrawPPMBlob inline vs.
    the per-frame C;S Store + Draw. Wired in the JXL/PPM-tier doors
    (syncconquer, syncduke, syncdoom). Sixel is already inline, unaffected.

    Each door's DA1 handler enables the audio/video blob flags at >= 1329. The stats overlay shows a blob token only when actually in use (JXL/PPM tier inline, or retro's "a-blob" audio stream); moo1 has none.

    #256 workaround (non-blob clients): the JXL/PPM frame cache filenames were fixed strings, so two SyncTERM windows of one dialing-entry -- which share a cache dir -- collided. Salt the name per session with the door's PID via termgfx_session_salt() (xpdev GetCurrentProcessId): syncalert_<pid>.jxl etc. Only the cache path is affected; blob clients write no file. (syncterm #256.)

    Compile-verified across all five doors; the blob paths need SyncTERM >= 1.329 to live-test, and the fallback is unchanged so older clients are unaffected.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Mon Jul 13 21:37:59 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/561cd5b998b75665f085c391
    Modified Files:
    src/doors/syncconquer/door/door_io.c src/doors/syncdoom/syncdoom.c src/doors/syncduke/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
    Log Message:
    doors: size the image to what the terminal will DRAW, not to its window

    SyncDOOM (and SyncDuke) rendered all black in an xterm bigger than its default size. The image was fine; xterm was throwing it away whole.

    A sixel whose DECLARED raster exceeds the terminal's graphics limit is not clipped -- xterm discards the entire image (graphics_sixel.c, GetExtent: "raster width %d > max %d" -> finished_parsing + return, nothing drawn). The limit is maxGraphicSize, which defaults to 1000x1000. So any window whose canvas is wider than ~1000px got a sixel xterm refused outright, and the
    screen stayed black; the default small window stayed under the limit and worked, which is exactly the reported symptom.

    And the terminal TELLS us the limit -- we were discarding the answer. XTSMGRAPHICS (ESC[?2;1S) reports Min(window, graphics_max) -- the biggest
    sixel it will accept -- and every door already sends the query as part of termgfx_term_probe. But xterm answers BOTH that and ESC[14t, and the doors either preferred the ESC[14t window size or never parsed the graphics reply at all, so they fitted the image to a window the terminal would not draw into.

    The graphics geometry is now authoritative in every door that uses termgfx, whichever order the replies arrive in:

    SyncDOOM used XTSMGRAPHICS only as a fallback when ESC[14t was silent --
    so on xterm it fitted the 1920x1080 window, emitted a 1280x800
    sixel, and got it discarded. Now prefers it.

    SyncDuke fitted the sixel to the ESC[14t window (syncduke_update_outsize)
    even though syncduke_canvas_*() already preferred the graphics
    geometry for JXL -- and its OUT_W_MAX is 1024, itself over
    xterm's limit. Now fits the canvas.

    SyncMOO1 never parsed the reply at all (only ESC[14t). Added, and it
    outranks the window.

    SyncRetro likewise never parsed it -- and worse, its F4 handler assumed "no
    terminal SENDS a CSI S as input", so the XTSMGRAPHICS reply (CSI
    ? 2;0;W;H S) fell through as an F4 KEYPRESS and silently cycled
    the render tier at startup on any terminal that answers it. The
    '?' private intro now routes it to the canvas handler instead,
    fixing both.

    SyncConquer already landed on the right value, but only because the 't'
    reply happened to arrive before the 'S' one. Made explicit rather
    than left to ordering.

    Verified by driving SyncDOOM through a simulated xterm (answering ESC[14t with 1920x1080, ESC[?2;1S with 1000x1000, DA1 with sixel): it now sizes to win=1000x1000 and emits a 1000x625 image, inside the limit. The old code
    fitted the window and produced 1280x800 -- discarded.

    Pre-existing, not a regression from the recent sixel-scaling work: the width path is unchanged by it. It surfaced now because that work is what got xterm tested at size.
    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Mon Jul 13 21:37:59 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/d45db994a03ca93e4f80858b
    Modified Files:
    src/doors/syncconquer/door/door_io.c src/doors/syncdoom/syncdoom.c src/doors/syncduke/syncduke_input.c src/doors/syncmoo1/syncmoo1_io.c src/doors/syncretro/syncretro_io.c src/doors/termgfx/geometry.h
    Log Message:
    doors: assume xterm's 1000x1000 sixel ceiling when nothing advertises one

    The previous commit made the terminal's XTSMGRAPHICS graphics geometry authoritative, which was right but useless against the terminal that motivated it: xterm ships with window operations DISABLED, so it answers NEITHER ESC[14t NOR the XTSMGRAPHICS query. With no reply to act on, the doors fell back to sizing the image from cols*cell -- the only geometry they can still get -- and a large window yields a large estimate.

    From the reported session's log: cols=369 rows=90, cell=6x13, so win=2214x1170 (369*6 x 90*13, derived, not reported) and image 1024x640. That sixel declares a raster wider than xterm's maxGraphicSize, which defaults to 1000x1000, and xterm does not clip an oversized image -- it aborts the parse and draws
    NOTHING (graphics_sixel.c: GetExtent -> finished_parsing + return). Hence a black screen in any big xterm window, and a correct picture in a small one.

    So the ceiling has to be assumed rather than queried. TERMGFX_SIXEL_SAFE_MAX (1000) caps the canvas in every termgfx door whenever no graphics geometry was advertised. A terminal that can take more says so and gets the bigger image; a silent one now gets a picture instead of a void.

    Verified against both shapes of terminal, driving SyncDOOM through a pty: replaying the reported xterm (answers nothing, 369x90 grid, 6x13 cell) it now sizes win=1000x1000 -> image 1000x625, inside the limit, where before it built 1024x640 and had it discarded; and a SyncTERM that answers XTSMGRAPHICS with its real 640x400 canvas is UNCHANGED at image 640x384, since the cap never engages when the terminal advertises.
    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Mon Jul 13 21:37:59 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/b42e26c050046c896233f631
    Modified Files:
    src/doors/syncconquer/door/door_io.c src/doors/syncdoom/syncdoom.c src/doors/syncduke/syncduke.h syncduke_input.c syncduke_io.c src/doors/syncmoo1/syncmoo1_io.c src/doors/syncretro/syncretro_io.c src/doors/termgfx/geometry.c geometry.h
    Log Message:
    doors: clamp the IMAGE to the graphics ceiling, not the canvas

    The previous commit stopped the black screen by capping the canvas to xterm's 1000x1000 default when the terminal advertises no graphics geometry. That
    fixed the rendering and broke the centering: the canvas is also what the image is CENTERED AGAINST, so a 1000-wide image was centered inside a 1000-wide "canvas" and pinned to the left of a 2214-wide xterm window. Doom sat centered under foot (which reports a canvas) and hugged the left edge under xterm.

    Two different quantities were being conflated. The graphics geometry is a
    limit on what the terminal will DRAW -- exceed it and the sixel is discarded whole. The canvas is the area to CENTER IN, and it is the real terminal, however big. Clamp the fitted image to the former; keep measuring against the latter.

    termgfx_geom_gfx_clamp() shrinks a fitted image to the ceiling preserving aspect, and every door now applies it to the FIT result while centering
    against the true canvas. SyncDOOM and SyncDuke clamp the fit inputs directly (they build the fit themselves); SyncMOO1, SyncRetro and SyncConquer clamp the fitted image after the fact, which leaves their page/reserve math untouched.

    Verified by driving SyncDOOM through a pty against both shapes of terminal: replaying the reported xterm (2214x1170, advertises nothing) it now emits
    image 1000x625 @607,266 -- inside the ceiling AND centered, since
    (2214-1000)/2 = 607 -- where the previous commit produced a correctly-sized image pinned at the left. A SyncTERM that advertises its 640x400 canvas is unchanged at image 640x384, the cap never engaging.
    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net