utils/gatelock/gatelock/__init__.py
Krzysztof kuhy Rudnicki 35f6f95956
Some checks failed
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
gatelock pre-commit / pre-commit (push) Has been cancelled
gatelock tests / test (push) Has been cancelled
music_theory tests / test (push) Has been cancelled
gatelock 0.11.0: Claim.grab_held + held_grabs(), so a reader can tell a locker's X grab is actually held
A live claim was not "input is locked": it is published before the window
grabs, and leetcode-guard's study mode releases the grab while the claim
lives on. leisure-watch (contract C2) must pause shadow billing only while a
grab is really held.

- Claim.grab_held (always serialised; missing key from an old writer reads
  as grab != "none"). Arbitration still uses the declared grab only.
- Arbiter.set_grab_held(held=) rewrites the claim and holder copies in place
  through the owner's flocked fd (O_APPEND cleared, pwrite at 0, padded so
  the file never shrinks) -- same inode, flock liveness untouched. Never raises.
- Set true only after grab_set/grab_set_global succeeded; RecoveryLoop
  reports each tick's real answer (a stolen, un-retaken grab reads false).
  LockWindow.report_grab_held(held=) is the hook for deliberate releases.
- gatelock.held_grabs(claims_dir=None): live claims with grab_held and a real
  grab. Root callers pass /run/user/1000/gatelock/claims.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dsh4Znwh2KnC7q6vbGpX1N
2026-10-19 11:40:46 +02:00

141 lines
3.5 KiB
Python

# Copyright (c) 2026 Krzysztof Rudnicki
"""Shared lock-window and HMAC log-integrity backend for blocking-overlay apps.
Used by ``screen-locker``, ``diet-guard`` and ``wake-alarm``, which all need
the same thing: cover every monitor the user can actually see, take the input
grab, and stay up until their own condition is met.
"""
from __future__ import annotations
from gatelock._arbiter import (
RANK_DIET_GUARD,
RANK_SCREEN_LOCKER,
RANK_WAKE_ALARM,
Arbiter,
)
from gatelock._claimfile import held_grabs
from gatelock._claims import ArbiterVerdict, Claim, default_runtime_dir, grab_strength
from gatelock._config import GrabPolicy, LockConfig, SpaceStep, TypeRole
from gatelock._detect import OutputChangeDetector
from gatelock._escape import (
EscapeDraft,
EscapeHistory,
EscapePolicy,
EscapeTracker,
)
from gatelock._fitcheck import FitResult, measure_fit, report_fit
from gatelock._guards import assert_not_under_pytest, wait_for_x_server
from gatelock._hooks import LockWindowHooks
from gatelock._keyboard import bind_activate, bind_cancel, escape_text_tab_trap
from gatelock._outputs import (
Output,
OutputEnumerator,
OutputRect,
OutputScan,
enumerate_outputs,
)
from gatelock._queue import (
QUEUE_DEADLINE_SECONDS,
QUEUE_HEARTBEAT_SECONDS,
QUEUE_POLL_SECONDS,
QueueResult,
Timebase,
stronger_claims,
wait_for_turn,
)
from gatelock._randr import RandrBackend
from gatelock._recovery import RecoveryLoop, RecoveryReport
from gatelock._root import GateRoot
from gatelock._scrollable import ScrollableSurface
from gatelock._surfaces import (
SurfaceBuilder,
SurfaceDelta,
SurfaceInfo,
SurfaceSet,
mirror_text_widgets,
needs_backdrop_root,
)
from gatelock._theme import LockPalette, LockSpacing, LockTypography
from gatelock._vt import disable_vt_switching, restore_vt_switching
from gatelock._window import LockWindow
from gatelock._xrandr import parse_xrandr_query
from gatelock.widget_group import WidgetGroup
from gatelock.widgets import (
DEFAULT_WRAP,
ButtonStyle,
ButtonVariant,
RowStyle,
heading,
make_button,
row,
)
__all__ = [
"DEFAULT_WRAP",
"QUEUE_DEADLINE_SECONDS",
"QUEUE_HEARTBEAT_SECONDS",
"QUEUE_POLL_SECONDS",
"RANK_DIET_GUARD",
"RANK_SCREEN_LOCKER",
"RANK_WAKE_ALARM",
"Arbiter",
"ArbiterVerdict",
"ButtonStyle",
"ButtonVariant",
"Claim",
"EscapeDraft",
"EscapeHistory",
"EscapePolicy",
"EscapeTracker",
"FitResult",
"GateRoot",
"GrabPolicy",
"LockConfig",
"LockPalette",
"LockSpacing",
"LockTypography",
"LockWindow",
"LockWindowHooks",
"Output",
"OutputChangeDetector",
"OutputEnumerator",
"OutputRect",
"OutputScan",
"QueueResult",
"RandrBackend",
"RecoveryLoop",
"RecoveryReport",
"RowStyle",
"ScrollableSurface",
"SpaceStep",
"SurfaceBuilder",
"SurfaceDelta",
"SurfaceInfo",
"SurfaceSet",
"Timebase",
"TypeRole",
"WidgetGroup",
"assert_not_under_pytest",
"bind_activate",
"bind_cancel",
"default_runtime_dir",
"disable_vt_switching",
"enumerate_outputs",
"escape_text_tab_trap",
"grab_strength",
"heading",
"held_grabs",
"make_button",
"measure_fit",
"mirror_text_widgets",
"needs_backdrop_root",
"parse_xrandr_query",
"report_fit",
"restore_vt_switching",
"row",
"stronger_claims",
"wait_for_turn",
"wait_for_x_server",
]