From 3d08abb060c2df01df30005811fdf273cb057611 Mon Sep 17 00:00:00 2001 From: funman300 Date: Wed, 15 Jul 2026 21:54:17 -0700 Subject: [PATCH] gamemode-watch: single-instance flock guard Prevents a manually-launched watcher and the spawn-at-startup one from racing the same winwatch source; the second instance exits immediately. Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/gamemode-watch.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/scripts/gamemode-watch.py b/scripts/gamemode-watch.py index 851825e..91e7b2c 100755 --- a/scripts/gamemode-watch.py +++ b/scripts/gamemode-watch.py @@ -10,7 +10,9 @@ Launched at niri startup (spawn-at-startup "gamemode-watch"). Reconnects if the event stream drops while niri is still alive, and always releases the source on exit so gamemode can never get stuck on when the watcher stops. """ +import fcntl import json +import os import re import signal import subprocess @@ -133,7 +135,23 @@ def _on_sigterm(signum, frame): raise KeyboardInterrupt +def acquire_single_instance(): + # Hold an exclusive lock so a second watcher (e.g. spawn-at-startup plus a + # manual launch) exits instead of racing the same winwatch source. The open + # file must stay referenced for the process lifetime to keep the lock. + rt = os.environ.get("XDG_RUNTIME_DIR", "/tmp") + f = open(os.path.join(rt, "gamemode-watch.lock"), "w") + try: + fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB) + except OSError: + return None + return f + + if __name__ == "__main__": + _lock = acquire_single_instance() + if _lock is None: + sys.exit(0) # another instance already running signal.signal(signal.SIGTERM, _on_sigterm) try: main()