mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-13 01:10:59 +01:00
_window.py was the repo's largest file and could not be read in one piece. Split along the seams the file already marked out, keeping the public API and every existing import path intact: _config.py (215) — LockConfig, the design tokens and preset resolution _arming.py (178) — the way up: VT-disable, backdrop, surfaces, input grab _preempt.py (118) — naming a blocked grab's holder, standing a weaker one down _hooks.py (51) — the LockWindowHooks Protocol, pure interface _window.py (243) — construction, focus, and teardown _arming takes an explicit ArmingCollaborators bundle rather than the window itself, mirroring the existing RecoveryCollaborators; setup() returns whether VT was disabled instead of mutating the window. That leaves no reach-back into private members (ruff SLF001 clean) and makes the arming sequence testable without a window. LockConfig is re-exported from _window, so `from gatelock._window import LockConfig` — which five sibling modules and the tests already do — still resolves. Tests that patched moved symbols were retargeted to their new home; the dead _maybe_preempt delegate, whose only callers were tests, is gone. 389 passed, 100% branch coverage — identical to before the split. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CFSGeWxHPY5rHUGrPqhcmG
52 lines
2.0 KiB
Python
52 lines
2.0 KiB
Python
"""The callback interface an app embedding :class:`~gatelock.LockWindow` fills.
|
|
|
|
Split out of :mod:`gatelock._window` so the pure *interface* -- what an app
|
|
must implement -- can be read without the window mechanics that call it. This
|
|
module deliberately imports nothing from the runtime half, so an app can type
|
|
against the protocol without pulling in Tk window machinery.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, Protocol
|
|
|
|
if TYPE_CHECKING:
|
|
import tkinter as tk
|
|
|
|
from gatelock._surfaces import SurfaceInfo
|
|
|
|
|
|
class LockWindowHooks(Protocol):
|
|
"""Callbacks :class:`LockWindow` invokes; the embedding app supplies all."""
|
|
|
|
def build_surface(self, parent: tk.Misc, surface: SurfaceInfo) -> None:
|
|
"""Build this app's widgets inside ``parent``, for one output.
|
|
|
|
Called once per live output, and again whenever an output comes back.
|
|
Tk variables should stay mastered on the root so every surface shows
|
|
the same state, and every surface's submit path should call the same
|
|
handler -- solving the lock on any monitor dismisses all of them.
|
|
"""
|
|
|
|
def teardown_surface(self, surface: SurfaceInfo) -> None:
|
|
"""Forget per-surface state; that output went dark and is closing."""
|
|
|
|
def on_focus_ready(self, surface: SurfaceInfo | None) -> None:
|
|
"""Called once the lock is mapped and (if applicable) grabbed.
|
|
|
|
Args:
|
|
surface: The surface that took initial focus, or None when no
|
|
output is live and there is therefore nothing to focus.
|
|
"""
|
|
|
|
def on_callback_error(self) -> None:
|
|
"""Called when a Tk callback raised (see :class:`~gatelock.GateRoot`)."""
|
|
|
|
def on_close(self) -> None:
|
|
"""Called once, from :meth:`LockWindow.close`, before VT is restored.
|
|
|
|
Runs on every exit path -- normal dismiss, SIGTERM, SIGINT -- not just
|
|
a clean close, so app-specific teardown (restoring hardware state,
|
|
etc.) can't be skipped by killing the process.
|
|
"""
|