Go to file
Krzysztof Rudnicki f0be8c5919 Make lock surfaces keyboard-operable and safe on a 768px screen
gatelock v0.3.0. Every change here works around a Tk *default*, not an
application mistake -- which is why they belong in the shared backend rather
than being fixed four times.

On a lock surface these are not accessibility niceties. The lockers hold a
global input grab with VT switching disabled, so a control the keyboard cannot
reach, or a button clipped off the bottom of the screen, is a bricked machine.

LockConfig gains a type scale, a spacing scale and a focus-ring token:

- font() applies Tk's sign convention. Tk encodes the unit in the SIGN of the
  font size -- positive is points, negative is pixels -- so passing the
  design system's px values straight through rendered every string ~30%
  oversized (measured: body at 16pt has a 26px linespace where 16px gives 20).
  That alone pushed diet_guard's meal gate to 866px of content inside a 739px
  pane on a 1366x768 screen.
- focus_kwargs() sets highlightcolor, the *focused* ring. Tk's default is a 1px
  BLACK ring, invisible against the palette's #211D1B background. Note
  highlightbackground is the UNfocused ring: setting only that one inverts the
  affordance, which is what diet_guard was doing.

_keyboard.py collects three Tk defaults that each make a form unusable:

- tk.Text traps Tab (inserts a literal tab and refocuses itself) and no-ops
  Shift-Tab; the only exits are the undocumented Ctrl+Tab / Ctrl+Shift+Tab.
- tk.Button binds <space> on X11 but never <Return>, so the key a user reaches
  for to submit does nothing.
- Escape needs binding at the toplevel to work wherever focus happens to sit.

_scrollable.py adds ScrollableSurface, a viewport that content can actually be
reached in:

- A place()-centred frame takes its *requested* size and is clipped
  SYMMETRICALLY, so overflow removes the heading and the submit button at the
  same time, with no scrollbar and no hint anything is missing.
- A bare tk.Canvas has no class key bindings, so ::tk::FocusOK rejects it as a
  focus stop and the only way to scroll is dragging the thumb with a pointer.
- Canvas clipping does not unmap children, so scrolled-out fields stay in the
  tab ring while Tk never scrolls to follow focus -- Tab lands on fields the
  user can neither see nor reveal.
- A Canvas holds content in a canvas *item*, so it never propagates the
  content's requested size; a toplevel told to size itself has nothing to grow
  to. _request_content_size() fixes that, clamped to the display.

center_when_fits keeps short screens looking exactly as they did, so the
viewport can replace a centred frame without a visual change.

A scrollable dialog Toplevel is deliberately NOT the mechanism: on an
override-redirect lock surface a second toplevel steals the Tk grab, which the
recovery tick then kills -- the 2026-07-26 failure where a frozen sport
selector logged a walk as table tennis.

unified-design-system gains the two rule families this implements (pointer-free
operability, 1366x768 usable / 1024x600 graceful), a focus-ring token, and the
px/pt sign convention written down so it cannot recur.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 16:01:15 +02:00
.github/workflows Root scaffold: README, LICENSE, per-subdirectory CI for utils monorepo 2026-07-10 13:02:20 +02:00
crdt_sync_dart GitHubClient: add canAccessRepo() + deleteFile() (v0.3.0) 2026-07-11 23:41:10 +02:00
crdt-sync Stop the recovery tick stealing our own grab, and fix pre-commit for the monorepo 2026-07-26 15:08:41 +02:00
gatelock Make lock surfaces keyboard-operable and safe on a 768px screen 2026-07-30 16:01:15 +02:00
guard-lib feat: initial guard-lib - shared tamper-resistance primitives 2026-07-04 11:47:59 +02:00
scripts Stop the recovery tick stealing our own grab, and fix pre-commit for the monorepo 2026-07-26 15:08:41 +02:00
unified-design-system Make lock surfaces keyboard-operable and safe on a 768px screen 2026-07-30 16:01:15 +02:00
.gitignore Stop the recovery tick stealing our own grab, and fix pre-commit for the monorepo 2026-07-26 15:08:41 +02:00
LICENSE Root scaffold: README, LICENSE, per-subdirectory CI for utils monorepo 2026-07-10 13:02:20 +02:00
README.md Consolidate unified-design-system docs into this monorepo 2026-07-22 21:23:47 +02:00

utils

Shared libraries used across kuhyx's other projects. Each subdirectory is a formerly-standalone repo, folded in here with full commit history preserved (see each subdirectory's own git log for its pre-merge history).

crdt_sync_dart/

Dart/Flutter CRDT sync library (pub package name: crdt_sync, not published to pub.dev — consumed via a git dependency). Mirrors crdt-sync (below) module-for-module and test-for-test. Consumed by diet_guard's app, screen-locker's workout_app, wake_alarm's phone_app, and todo (whose notes are stored in the v0.2.0 LogStore).

Consume via:

dependencies:
  crdt_sync:
    git:
      url: https://github.com/kuhyx/utils
      ref: crdt_sync_dart-v0.2.0
      path: crdt_sync_dart

crdt-sync/

Python CRDT sync library (package: crdt_sync, not published to PyPI). Same design as crdt_sync_dart (HLC clocks, per-field LWW, sticky-delete tombstones). Consumed by diet-guard and screen-locker.

Consume via:

crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.2.0#subdirectory=crdt-sync

guard-lib/

Bash tamper-resistance primitives (guardctl: chattr + bind-mount + systemd watcher + pacman hooks). Not a package — installed by running guard-lib/install.sh as root, which copies files onto the system (/usr/local/bin, /usr/local/lib/guard-lib, systemd units, pacman hooks). Consumed by steam-backlog-enforcer (expects a guard-lib/install.sh sibling clone) and referenced by screen-locker.

gatelock/

Python lock-window + HMAC log-integrity backend (package: gatelock, not published to PyPI). Consumed via pip by screen-locker, diet-guard, and wake-alarm:

gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.1.0#subdirectory=gatelock

unified-design-system/

Not a package — the frozen design tokens (colors, spacing, type, radius, shadow policy) and per-stack (Flutter/web/Tkinter) implementation patterns that keep every one of kuhy's repos visually identical, plus annotated component references (components.html, button.html). Read unified-design-system/README.md and tokens.md before touching any theme/CSS/style file in any repo. The unified-design-system Claude Code skill is a thin pointer here, not a duplicate.