fix(termtris): do not select ExposureMask

A map-time Expose arrives before the game has a current piece, and the
game's full-redraw path then draws a bogus piece over the top row: visible
as a blanked well border with stray X tiles (the previous commit's
screenshots showed it). The window is never obscured in this session, so
drop the mask, drop the Expose branch, and note the reason in HANDOFF.md.

Refreshed with verify.sh: move 354/18, panels 346/12, quit 300/10, all
with focus=00400001; evidence re-captured and clean.
This commit is contained in:
opencode.energia.arti.ee committed 2026-11-12 05:19:52 +00:00
1 parent a12fb47d5f
commit 5dd01629b9
11 files changed
+97 -90

No files matched your search

+6 -5
View File
@@ -91,12 +91,12 @@ Last run here (older MAME, VR150 geometry):
smoke PASS type=2 keycode=194 lookup_n=1 ch=61 ks=0061
fmt PASS six formats exact
render PASS flus=464C5553 progress=00FFFFFF
input PASS bytes 60 61 9B 41 9B 42 9B 44 9B 43 30 0A 7F 71 70
(60 is the Expose redraw, then a/up/down/left/right/0/Return/Delete/q/p)
input PASS bytes 61 9B 41 9B 42 9B 44 9B 43 30 0A 7F 71 70
(a/up/down/left/right/0/Return/Delete/q/p)
play PASS DIAG: tick=887 quit=0
play_keys PASS move DIAG: loops=348 events=19 focus=00400001 quit=0
panels DIAG: loops=338 events=13 focus=00400001 quit=0
quit DIAG: loops=292 events=11 focus=00400001 quit=1
play_keys PASS move DIAG: loops=354 events=18 focus=00400001 quit=0
panels DIAG: loops=346 events=12 focus=00400001 quit=0
quit DIAG: loops=300 events=10 focus=00400001 quit=1
```
`focus=00400001` is the window the process created; `quit=1` is the game's own
@@ -113,6 +113,7 @@ window.
| the game exits immediately at startup, sometimes | `XOpenDisplay`/window creation while the display server settles | `main()` retries 40 × 50 ms, then returns 1 |
| window paints once, then hangs; a debug marker stops mid-flush | per-cell flushing overflowed the X socket / `XSync` per row deadlocked the client | flush repaints whole rows (fill + one 80-char string + inverse spans + one `XFlush`) |
| playfield is a white block with invisible pieces | the 1-bit raster cannot show colour | backend drops colour and uses bold (`0x80`) as reverse; pieces are `[`/`]` glyphs |
| blanked well border with stray `X` tiles at the top | `ExposureMask` + map-time Expose runs the game's full redraw before it has a piece | do not select `ExposureMask` (current code); if repainting on expose is ever needed, guard `full_redraw` against `cur_piece < 0` |
## Layout
+11 -5
View File
@@ -89,8 +89,14 @@ level 0).
Keys arrive as X11 `KeyPress` events and go through `XLookupString`; letters are
lower-cased and handed to `game_input()`. Arrows are sent as the game's own CSI
codes (`0x9b` + `A`/`B`/`C`/`D`), which `game_input` translates back to
`w`/`s`/`d`/`a`. `0x7F` is Backspace/Delete. `Expose` (selected with `0x22800F`) triggers a full redraw and
`FocusOut` (only after a `FocusIn`) pauses the game.
`w`/`s`/`d`/`a`. `0x7F` is Backspace/Delete. `FocusOut` pauses and `FocusIn`
resumes (only if we paused it).
`ExposureMask` is deliberately **not** selected: the map-time `Expose` arrives
before the game has a current piece, and the game's full-redraw path then draws
a non-existent piece over the top row — visible as a blanked border with stray
`X` tiles. The window is never obscured in this session (the Terminal Manager
sits beside it), so the mask buys nothing. See `HANDOFF.md`.
## Running it in MAME
@@ -130,9 +136,9 @@ which copies the sections to their linked addresses and calls
Acceptance values from the last full run (`play_keys.sh`):
```
move DIAG: loops=348 events=19 focus=00400001 quit=0
panels DIAG: loops=338 events=13 focus=00400001 quit=0
quit DIAG: loops=292 events=11 focus=00400001 quit=1
move DIAG: loops=354 events=18 focus=00400001 quit=0
panels DIAG: loops=346 events=12 focus=00400001 quit=0
quit DIAG: loops=300 events=10 focus=00400001 quit=1
```
`focus=00400001` is the window this process created (it is the only one in the
Binary file not shown.
+73 -73
View File
@@ -1,7 +1,7 @@
*****************************************************
TMS340 COFF Linker Version 5.01
*****************************************************
Thu Nov 12 05:12:58 2026
Thu Nov 12 05:18:17 2026
OUTPUT FILE NAME: <MAIN.out>
ENTRY POINT SYMBOL: "_start" address: 018a0000
@@ -20,28 +20,28 @@ SECTION ALLOCATION MAP
output attributes/
section page origin length input sections
-------- ---- ---------- ---------- ----------------
.text 0 018a0000 00014b10
.text 0 018a0000 00014a60
018a0000 00000150 ENTRY.obj (.text)
018a0150 00001e60 MAIN.obj (.text)
018a1fb0 0000ce50 GAME.obj (.text)
018aee00 00000d20 SCOREDB.obj (.text)
018afb20 00002a40 X11.obj (.text)
018b2560 00001640 COMPAT.obj (.text)
018b3ba0 00000210 XGFIX.obj (.text)
018b3db0 00000450 rts.lib (.text)
018b4200 000001a0 rts.lib (.text)
018b43a0 00000230 rts.lib (.text)
018b45d0 00000150 rts.lib (.text)
018b4720 00000120 rts.lib (.text)
018b4840 00000110 rts.lib (.text)
018b4950 000001c0 rts.lib (.text)
018a0150 00001db0 MAIN.obj (.text)
018a1f00 0000ce50 GAME.obj (.text)
018aed50 00000d20 SCOREDB.obj (.text)
018afa70 00002a40 X11.obj (.text)
018b24b0 00001640 COMPAT.obj (.text)
018b3af0 00000210 XGFIX.obj (.text)
018b3d00 00000450 rts.lib (.text)
018b4150 000001a0 rts.lib (.text)
018b42f0 00000230 rts.lib (.text)
018b4520 00000150 rts.lib (.text)
018b4670 00000120 rts.lib (.text)
018b4790 00000110 rts.lib (.text)
018b48a0 000001c0 rts.lib (.text)
.cinit 0 018b4b10 000012d0
018b4b10 00000050 MAIN.obj (.cinit)
018b4b60 00001190 GAME.obj (.cinit)
018b5cf0 00000050 SCOREDB.obj (.cinit)
018b5d40 00000050 X11.obj (.cinit)
018b5d90 00000050 rts.lib (.cinit)
.cinit 0 018b4a60 000012d0
018b4a60 00000050 MAIN.obj (.cinit)
018b4ab0 00001190 GAME.obj (.cinit)
018b5c40 00000050 SCOREDB.obj (.cinit)
018b5c90 00000050 X11.obj (.cinit)
018b5ce0 00000050 rts.lib (.cinit)
.bss 0 01a00000 0001ec20 UNINITIALIZED
01a00000 00008000 ENTRY.obj (.bss)
@@ -64,78 +64,78 @@ address name address name
018a0000 .data 018a0000 .text
018a0000 .text 018a0000 _start
01a08a20 _blackpf 018a0000 edata
018a3110 _cleanup_game 018a0150 _now_ms
018a3060 _cleanup_game 018a0150 _now_ms
01a083a0 _dbg_events 018a03d0 _vt_rand_seed
01a083e0 _dbg_focus 018a0420 _sleep_ms
01a083c0 _dbg_last 018a0580 _vt_poll_event
01a08380 _dbg_loops 018a0ef0 _vt_handle_event
01a08400 _dbg_rev 018a18d0 _wait_display
018b2560 _fflush 018a1910 _main
018a86b0 _game_input 018a1fb0 _init_game
018a1fb0 _init_game 018a3110 _cleanup_game
018a1910 _main 018a3300 _update
018b3db0 _memcpy 018a86b0 _game_input
018b3f50 _memmove 018af160 _read_scores
018b4200 _memset 018af4e0 _save_score
01a089c0 _monochrome 018afa70 _print_scores
018a0150 _now_ms 018afb20 _vt_root_window
01a08a00 _onlyascii 018afc00 _vt_x11_init
018afa70 _print_scores 018b03b0 _x11_clearscr
018b25d0 _putchar 018b0570 _x11_reset
01a08960 _quit 018b05b0 _x11_cursor
018b43a0 _rand 018b0610 _x11_setcolor
018af160 _read_scores 018b0730 _x11_setcursor
01a08a40 _rotstep 018b0980 _x11_ibmchar
018af4e0 _save_score 018b0e00 _term_putstr
01a08aa0 _scr 018b0fa0 _vt_x11_flush
018a0420 _sleep_ms 018b21d0 _vt_x11_term_init
018b2de0 _sprintf 018b24f0 _term_init
018b4500 _srand 018b2560 _fflush
018a0000 _start 018b25d0 _putchar
01a1cbe0 _stdout 018b2de0 _sprintf
018b45d0 _strcmp 018b3ba0 _vt_install_xg
018b4720 _strcpy 018b3db0 _memcpy
018b4840 _strlen 018b3f50 _memmove
018b4950 _strncpy 018b4200 _memset
01a1cb00 _term_clearscr 018b43a0 _rand
01a1cb40 _term_cursor 018b4500 _srand
01a08a80 _term_height 018b45d0 _strcmp
01a1cb80 _term_ibmchar 018b4720 _strcpy
018b24f0 _term_init 018b4840 _strlen
018b0e00 _term_putstr 018b4950 _strncpy
01a1cae0 _term_reset 018b4b10 cinit
01a1cb60 _term_setcolor 018b4b10 etext
01a08400 _dbg_rev 018a1820 _wait_display
018b24b0 _fflush 018a1860 _main
018a8600 _game_input 018a1f00 _init_game
018a1f00 _init_game 018a3060 _cleanup_game
018a1860 _main 018a3250 _update
018b3d00 _memcpy 018a8600 _game_input
018b3ea0 _memmove 018af0b0 _read_scores
018b4150 _memset 018af430 _save_score
01a089c0 _monochrome 018af9c0 _print_scores
018a0150 _now_ms 018afa70 _vt_root_window
01a08a00 _onlyascii 018afb50 _vt_x11_init
018af9c0 _print_scores 018b0300 _x11_clearscr
018b2520 _putchar 018b04c0 _x11_reset
01a08960 _quit 018b0500 _x11_cursor
018b42f0 _rand 018b0560 _x11_setcolor
018af0b0 _read_scores 018b0680 _x11_setcursor
01a08a40 _rotstep 018b08d0 _x11_ibmchar
018af430 _save_score 018b0d50 _term_putstr
01a08aa0 _scr 018b0ef0 _vt_x11_flush
018a0420 _sleep_ms 018b2120 _vt_x11_term_init
018b2d30 _sprintf 018b2440 _term_init
018b4450 _srand 018b24b0 _fflush
018a0000 _start 018b2520 _putchar
01a1cbe0 _stdout 018b2d30 _sprintf
018b4520 _strcmp 018b3af0 _vt_install_xg
018b4670 _strcpy 018b3d00 _memcpy
018b4790 _strlen 018b3ea0 _memmove
018b48a0 _strncpy 018b4150 _memset
01a1cb00 _term_clearscr 018b42f0 _rand
01a1cb40 _term_cursor 018b4450 _srand
01a08a80 _term_height 018b4520 _strcmp
01a1cb80 _term_ibmchar 018b4670 _strcpy
018b2440 _term_init 018b4790 _strlen
018b0d50 _term_putstr 018b48a0 _strncpy
01a1cae0 _term_reset 018b4a60 cinit
01a1cb60 _term_setcolor 018b4a60 etext
01a1cb20 _term_setcursor 01a00000 .bss
01a1cbc0 _term_type 01a08380 _dbg_loops
01a08a60 _term_width 01a083a0 _dbg_events
01a1cba0 _termenv 01a083c0 _dbg_last
01a08980 _tick_interval 01a083e0 _dbg_focus
018a3300 _update 01a08400 _dbg_rev
018a3250 _update 01a08400 _dbg_rev
01a089a0 _use_bell 01a08960 _quit
01a089e0 _use_gfxchar 01a08980 _tick_interval
01a0ce60 _username 01a089a0 _use_bell
01a1ca60 _vt_dpy 01a089c0 _monochrome
01a1caa0 _vt_gc 01a089e0 _use_gfxchar
018a0ef0 _vt_handle_event 01a08a00 _onlyascii
018b3ba0 _vt_install_xg 01a08a20 _blackpf
018b3af0 _vt_install_xg 01a08a20 _blackpf
018a0580 _vt_poll_event 01a08a40 _rotstep
018a03d0 _vt_rand_seed 01a08a60 _term_width
018afb20 _vt_root_window 01a08a80 _term_height
018afa70 _vt_root_window 01a08a80 _term_height
01a1ca80 _vt_win 01a08aa0 _scr
018b0fa0 _vt_x11_flush 01a0ce60 _username
018afc00 _vt_x11_init 01a1ca60 _vt_dpy
018b0ef0 _vt_x11_flush 01a0ce60 _username
018afb50 _vt_x11_init 01a1ca60 _vt_dpy
01a1cac0 _vt_x11_progress 01a1ca80 _vt_win
018b21d0 _vt_x11_term_init 01a1caa0 _vt_gc
018a18d0 _wait_display 01a1cac0 _vt_x11_progress
018b03b0 _x11_clearscr 01a1cae0 _term_reset
018b05b0 _x11_cursor 01a1cb00 _term_clearscr
018b0980 _x11_ibmchar 01a1cb20 _term_setcursor
018b0570 _x11_reset 01a1cb40 _term_cursor
018b0610 _x11_setcolor 01a1cb60 _term_setcolor
018b0730 _x11_setcursor 01a1cb80 _term_ibmchar
018b4b10 cinit 01a1cba0 _termenv
018b2120 _vt_x11_term_init 01a1caa0 _vt_gc
018a1820 _wait_display 01a1cac0 _vt_x11_progress
018b0300 _x11_clearscr 01a1cae0 _term_reset
018b0500 _x11_cursor 01a1cb00 _term_clearscr
018b08d0 _x11_ibmchar 01a1cb20 _term_setcursor
018b04c0 _x11_reset 01a1cb40 _term_cursor
018b0560 _x11_setcolor 01a1cb60 _term_setcolor
018b0680 _x11_setcursor 01a1cb80 _term_ibmchar
018b4a60 cinit 01a1cba0 _termenv
018a0000 edata 01a1cbc0 _term_type
01a1ec20 end 01a1cbe0 _stdout
018b4b10 etext 01a1ec20 end
018b4a60 etext 01a1ec20 end
[77 symbols]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

-2
View File
@@ -112,8 +112,6 @@ void vt_handle_event(void)
VT_XGETFOCUS(vt_dpy, &fw, &rv);
dbg_focus = fw;
dbg_rev = (vt_u32)rv;
} else if(evbuf[0] == 12) { /* Expose */
game_input('`');
} else if(evbuf[0] == 9) { /* FocusIn */
focused = 1;
if(vt_paused) { /* resume only what we paused */
+1 -1
View File
@@ -64,7 +64,7 @@ int vt_x11_init(void)
if(!vt_win)
return -1;
vt_x11_progress = 14;
VT_XSELECT(vt_dpy, vt_win, 0x22800FUL); /* + ExposureMask */
VT_XSELECT(vt_dpy, vt_win, 0x22000FUL);
vt_gc = VT_XGC(vt_dpy, vt_win, 0, 0);
if(!vt_gc)
return -1;
+6 -4
View File
@@ -75,7 +75,9 @@ game's own `update()` picks the tick (887 ms at level 0).
`KeyPress` → `XLookupString` → lower-cased letters to `game_input()`; arrows as
the game's CSI codes (`0x9b` + `A`/`B`/`C`/`D`), which it maps back to
`w`/`s`/`d`/`a`; `0x7F` is Backspace/Delete; `Expose` forces a full redraw.
`w`/`s`/`d`/`a`; `0x7F` is Backspace/Delete. `ExposureMask` is not selected:
a map-time `Expose` fires the game's full-redraw before it has a current piece,
which draws a bogus piece over the top row (blank border plus stray `X` tiles).
## Reproduce
@@ -94,9 +96,9 @@ The run is `VT1200_SKIP_LEVEL1=1 LOADER_AT=2500` with the loader payload at bit
Last full acceptance run:
```
move DIAG: loops=348 events=19 focus=00400001 quit=0
panels DIAG: loops=338 events=13 focus=00400001 quit=0
quit DIAG: loops=292 events=11 focus=00400001 quit=1
move DIAG: loops=354 events=18 focus=00400001 quit=0
panels DIAG: loops=346 events=12 focus=00400001 quit=0
quit DIAG: loops=300 events=10 focus=00400001 quit=1
```
`focus=00400001` is the termtris window, and `quit=1` is the game's global after