Skip to content

Android: build the hex monitor grid in code - #193

Merged
JumpLink merged 2 commits into
mainfrom
fix/android-hex-monitor
Sep 22, 2026
Merged

JumpLink merged 2 commits into
mainfrom
fix/android-hex-monitor

Conversation

@JumpLink

@JumpLink JumpLink commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

hex-monitor.ts looked up a child called grid, which only ever existed in
hex-monitor.xml. Nothing loads that file: this app constructs its widgets
directly (new HexMonitor()), and the only Builder.load calls are in
source-view.ts, gamepad.ts and mdx-view.ts. So the lookup found nothing,
update() returned early, and the Hex Monitor section of the Debugger tab was an
empty card.

Verified on an API 36 emulator before touching anything — the card is blank and
logcat carries the widget's own complaint:

E JS      : CONSOLE ERROR: [HexMonitor] Grid not initialized

The grid is now built in the constructor, the way disassembled.ts, hexdump.ts
and message-console.ts build theirs, and hex-monitor.xml is gone.

What the grid needed beyond the lookup

Both found by running it, not by reading it.

Row specs. A GridLayout with no rows has one implicit row and clamps every
child into it, so all 32 address rows would have stacked on top of each other.
update() now sizes rows to the region.

A default region a label-per-byte grid can render. The old default was Program
Storage, $0600-$FFFF — 39424 bytes, upwards of forty thousand Labels. That
exhausted the 200 MB heap and killed the app before a single row appeared:

java.lang.OutOfMemoryError: Failed to allocate a 352 byte allocation with 128272
free bytes ... growth limit 201326592
FATAL EXCEPTION: main

The default is now Zero Page, which is what the GNOME (hex-monitor.blp
DropDown) and web (Adw.ComboRow) debuggers select first. 256 bytes, 32 rows.

Before / after

Same emulator, same crop, aligned on the section heading. The code reaching the
editor differs (typed in before, the Snake example loaded after) and does not
matter here: the monitor shows $0000-$00ff, and neither program had run at the
last refresh, so 00 is the right dump either way.

before and after

Eight bytes per row, not sixteen

GNOME and web print sixteen into a source view that scrolls sideways. This is a
grid in a vertical ScrollView with nowhere to go: at 420 dpi a byte column is
60 px against roughly 850 px of card, so a sixteen-byte row rendered eleven
columns and $0b-$0f of every row fell off the right edge, unreachable. Here is
that intermediate build — note the addresses stepping by $10 over eleven
columns:

sixteen bytes per row clipped

Checks

gjsify format → gjsify format --check → gjsify lint → gjsify workspace @learn6502/core build → gjsify run build:android. The debug APK builds, and the
after screenshot is from that APK. lint is in the list because the first push
failed CI on unicorn/no-new-array — gjsify format --check does not cover it.

Noticed while measuring, not fixed here

  • Adw.ViewSwitcherBar.reveal defaults to false (faithfully) and main.ts never
    sets it, so the app has no tab navigation at all — the Debugger is reachable
    only via the action button.
  • AdwClamp._allocate() in @gjsify/adwaita-nativescript 0.51.1 calls
    String.prototype.split on a child className that is undefined for any view
    without a CSS class, which is what editor.ts hands it. On main the app dies
    at startup with TypeError: Cannot read properties of undefined (reading 'split'); the emulator run needed a local node_modules patch to get past it.
    That belongs upstream in gjsify.
  • The debugger's "step" signal refreshes only the register panel, never the
    monitor (game-console-event-bridge.ts), so single-stepping never redraws
    memory. Shared common-ui behaviour, same on GNOME and web.

🤖 Generated with Claude Code

The widget looked for a child "grid" from hex-monitor.xml, but this app never
runs Builder.load over a widget XML — it constructs widgets directly — so the
lookup found nothing, update() bailed out with "Grid not initialized" and the
Hex Monitor section rendered an empty card on every device. Build the grid in the
constructor, the way disassembled/hexdump/message-console build theirs, and drop
the XML that described it.

Two things the grid needed beyond the lookup, both measured on an API 36
emulator: row specs, because a GridLayout without them has one implicit row and
stacks every label into it; and a default region a label-per-byte grid can
actually render — Program Storage ($0600-$FFFF, 39424 bytes) exhausted the
200 MB heap and killed the app with an OutOfMemoryError, so the default is now
Zero Page, as in the GNOME and web debuggers. Eight bytes per row instead of
sixteen: only eleven columns fit the card, and the rest were unreachable.
JumpLink added a commit that referenced this pull request Sep 22, 2026
oxlint's unicorn/no-new-array is an error here, and CI's Code Quality job failed
on it. A small named helper says what the string is for as well.
JumpLink added a commit that referenced this pull request Sep 22, 2026
JumpLink added a commit that referenced this pull request Sep 22, 2026
@JumpLink
JumpLink merged commit e855872 into main Sep 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant