utils/gatelock
Krzysztof kuhy Rudnicki 7e3921ad66
Some checks failed
crdt-sync pre-commit / pre-commit (push) Waiting to run
crdt-sync tests / test (push) Waiting to run
dependency freshness / dependencies on newest stable (push) Waiting to run
earned_time pre-commit / pre-commit (push) Waiting to run
earned_time tests / test (push) Waiting to run
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
freedays pre-commit / pre-commit (push) Has been cancelled
freedays tests / test (push) Has been cancelled
gatelock pre-commit / pre-commit (push) Has been cancelled
gatelock tests / test (push) Has been cancelled
music_theory tests / test (push) Has been cancelled
deps(python): ruff 0.17.0 + types-requests 2.33.0.20261006 (CPY001 stays active: every file has a header)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 08:41:53 +02:00
..
docs Add the shared markdown-naming gate and migrate utils' own docs 2026-08-24 15:53:12 +02:00
gatelock gatelock 0.9.0: morning_session, the one reader of wake-alarm's carrot 2026-10-02 13:59:33 +02:00
.pre-commit-config.yaml deps(python): ruff 0.17.0 + types-requests 2.33.0.20261006 (CPY001 stays active: every file has a header) 2026-10-10 08:41:53 +02:00
LICENSE Initial gatelock: shared lock-window + HMAC log-integrity backend 2026-06-19 17:39:44 +02:00
pyproject.toml gatelock 0.9.0: morning_session, the one reader of wake-alarm's carrot 2026-10-02 13:59:33 +02:00
README.md gatelock 0.9.0: morning_session, the one reader of wake-alarm's carrot 2026-10-02 13:59:33 +02:00
requirements.txt deps(python): ruff 0.17.0 + types-requests 2.33.0.20261006 (CPY001 stays active: every file has a header) 2026-10-10 08:41:53 +02:00

gatelock

Shared fullscreen lock-window + HMAC log-integrity backend, extracted from three personal automation tools that each independently implemented "lock the screen with a blocking overlay until a condition is met": diet_guard, wake_alarm, and screen-locker.

Why

All three reimplemented the same tkinter fullscreen mechanics (overrideredirect, input grab, VT-switch disable) at different levels of maturity, and the HMAC-signed-state module had already been hand-copied between two of them because they live in separate repos. gatelock is the one place that logic now lives.

Install

pip install "gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.1.1#subdirectory=gatelock"

Usage

import tkinter as tk
from gatelock import GateRoot, LockConfig, LockWindow

class MyGate:
    def __init__(self, *, demo_mode: bool) -> None:
        self.root = GateRoot()
        self.root.on_callback_error = self._handle_callback_error
        config = LockConfig(mode="soft" if demo_mode else "hard")
        self._lock = LockWindow(self.root, config, hooks=self)
        self._lock.setup()
        # ... build your widgets ...
        self._lock.grab_input()

    def on_focus_ready(self) -> None:
        self.my_entry.focus_force()

    def on_callback_error(self) -> None:
        self.close()

    def on_close(self) -> None:
        ...  # release any hardware/state held while locked

    def close(self) -> None:
        self._lock.close()

    def run(self) -> None:
        self._lock.run()

LockConfig's mode preset bundles the common combination ("soft" = topmost only, typeable, WM-escapable; "hard" = overrideredirect + global grab + VT-disable). overrideredirect and the grab=GrabPolicy(kind=..., disable_vt=..., retry_ms=...) axes can be set explicitly to reproduce a consumer's exact prior behavior where it diverges from the preset. Colours, type scale and spacing are the palette, typography and spacing records (gatelock.LockPalette etc.), overridden as a unit.

gatelock.log_integrity ports the HMAC-signed state module used by all three projects; DEFAULT_HMAC_KEY_FILE (/etc/workout-locker/hmac.key) is unchanged so existing signed history keeps verifying.

gatelock.morning_session.morning_skip is the one reader of wake-alarm's signed morning_session.json (the wake-early carrot: no lock until the signed exempt_until, 11:00 for a morning completed in time). screen-locker, leetcode-guard and book-guard all call it; the policy itself stays in wake-alarm. Path and retry budget are arguments so each consumer's tests keep redirecting their own constant.

Development

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
pytest
pre-commit install && pre-commit install --hook-type pre-push