"""Where the pet was left, so it starts there next time. Listed in the README as a known limitation: drag it somewhere deliberate, and the next launch puts it back in the bottom-right corner. For something that lives on your desktop all day that is a small daily annoyance, and it is a config write on drag-end. Lives in the cache dir rather than the repo, next to the restart context: it is per-machine state about this install, not something that belongs in a git diff. Every function swallows its own errors — a corrupt or unwritable state file must never stop the pet from starting, it just means the default corner. Positions are validated against the *current* screen layout on load, because the common case for a stale position is exactly the case where it is dangerous: the pet was last on a monitor that is now unplugged, and restoring it faithfully would put it somewhere you cannot see or reach. """ from __future__ import annotations import json import logging import os import tempfile from pathlib import Path from typing import Optional logger = logging.getLogger("bolt_pet.window_state") DEFAULT_PATH = Path.home() / ".cache" / "bolt-pet" / "window.json" def load(path: Optional[Path] = None) -> Optional[tuple[int, int]]: """The saved position, or None if there isn't a usable one.""" try: data = json.loads(Path(path or DEFAULT_PATH).read_text(encoding="utf-8")) return int(data["x"]), int(data["y"]) except (FileNotFoundError, json.JSONDecodeError, KeyError, TypeError, ValueError, OSError): return None def save(x: int, y: int, path: Optional[Path] = None) -> None: """Remember where it is now. Atomic, so a crash mid-write can't leave a half-file that makes the next start fall back to the corner.""" target = Path(path or DEFAULT_PATH) try: target.parent.mkdir(parents=True, exist_ok=True) descriptor, temp_path = tempfile.mkstemp(dir=target.parent, prefix=".window_", suffix=".tmp") try: with os.fdopen(descriptor, "w", encoding="utf-8") as handle: json.dump({"x": int(x), "y": int(y)}, handle) os.replace(temp_path, target) except BaseException: try: os.unlink(temp_path) except OSError: pass raise except Exception: logger.debug("Could not save the window position", exc_info=True) def is_visible_on(x: int, y: int, size: int, rectangles) -> bool: """Whether that position still lands on a screen that exists. *rectangles* are (left, top, right, bottom) tuples — the caller's job, because this module has no business importing Qt. Requires a real overlap rather than a touching edge, so a pet saved flush against the boundary of a monitor that has since been unplugged is not counted as reachable.""" for left, top, right, bottom in rectangles: overlap_x = min(x + size, right) - max(x, left) overlap_y = min(y + size, bottom) - max(y, top) if overlap_x > size * 0.25 and overlap_y > size * 0.25: return True return False