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()