init
This commit is contained in:
121 files changed
+17641
No files matched your search
@@ -0,0 +1,106 @@
|
||||
"""Two things a focus app owes you: the screen stays on, and the world shuts up.
|
||||
|
||||
* **Screensaver inhibit** — `org.freedesktop.ScreenSaver.Inhibit`, honoured by
|
||||
KDE, GNOME and anything XDG-ish. Without it a 50-minute interval spent reading
|
||||
ends with a lock screen.
|
||||
* **Do Not Disturb** — Plasma (and any daemon implementing the spec's optional
|
||||
`Inhibit`) silences other apps' banners while you focus. GNOME has no such
|
||||
method, so there we flip the `show-banners` gsetting and put it back after.
|
||||
|
||||
Both are strictly paired: every inhibit is released on exit, including a crash,
|
||||
because the cookie dies with the D-Bus connection.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
from PyQt6.QtDBus import QDBusConnection, QDBusInterface
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
_SCREENSAVER = ("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver")
|
||||
_NOTIFICATIONS = ("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications")
|
||||
|
||||
|
||||
class ScreensaverInhibitor:
|
||||
"""Keeps the session awake for as long as `hold()` is in effect."""
|
||||
|
||||
def __init__(self, app_name: str = "Kadence") -> None:
|
||||
self._app_name = app_name
|
||||
self._interface = QDBusInterface(*_SCREENSAVER, QDBusConnection.sessionBus())
|
||||
self._cookie: int | None = None
|
||||
|
||||
@property
|
||||
def active(self) -> bool:
|
||||
return self._cookie is not None
|
||||
|
||||
def hold(self, reason: str = "Focus interval in progress") -> None:
|
||||
if self._cookie is not None or not self._interface.isValid():
|
||||
return
|
||||
reply = self._interface.call("Inhibit", self._app_name, reason)
|
||||
arguments = reply.arguments()
|
||||
if arguments:
|
||||
self._cookie = int(arguments[0])
|
||||
log.debug("screensaver inhibited (cookie %s)", self._cookie)
|
||||
|
||||
def release(self) -> None:
|
||||
if self._cookie is None:
|
||||
return
|
||||
self._interface.call("UnInhibit", self._cookie)
|
||||
log.debug("screensaver released")
|
||||
self._cookie = None
|
||||
|
||||
|
||||
class DoNotDisturb:
|
||||
"""Silences other applications' notifications during focus."""
|
||||
|
||||
def __init__(self, app_name: str = "Kadence") -> None:
|
||||
self._app_name = app_name
|
||||
self._interface = QDBusInterface(*_NOTIFICATIONS, QDBusConnection.sessionBus())
|
||||
self._cookie: int | None = None
|
||||
self._gnome_restored = True
|
||||
|
||||
@property
|
||||
def active(self) -> bool:
|
||||
return self._cookie is not None or not self._gnome_restored
|
||||
|
||||
def hold(self, reason: str = "Focus interval in progress") -> None:
|
||||
if self.active:
|
||||
return
|
||||
if self._interface.isValid():
|
||||
reply = self._interface.call("Inhibit", self._app_name, reason, {})
|
||||
arguments = reply.arguments()
|
||||
if arguments and not reply.errorName():
|
||||
self._cookie = int(arguments[0])
|
||||
return
|
||||
self._gnome_dnd(True)
|
||||
|
||||
def release(self) -> None:
|
||||
if self._cookie is not None:
|
||||
self._interface.call("UnInhibit", self._cookie)
|
||||
self._cookie = None
|
||||
if not self._gnome_restored:
|
||||
self._gnome_dnd(False)
|
||||
|
||||
def _gnome_dnd(self, enable: bool) -> None:
|
||||
"""GNOME fallback: toggle the banner gsetting, and remember to undo it."""
|
||||
if not shutil.which("gsettings"):
|
||||
return
|
||||
try:
|
||||
subprocess.run(
|
||||
[
|
||||
"gsettings",
|
||||
"set",
|
||||
"org.gnome.desktop.notifications",
|
||||
"show-banners",
|
||||
"false" if enable else "true",
|
||||
],
|
||||
check=False,
|
||||
timeout=5,
|
||||
)
|
||||
self._gnome_restored = not enable
|
||||
except (OSError, subprocess.SubprocessError) as exc: # pragma: no cover
|
||||
log.debug("gsettings DND failed: %s", exc)
|
||||
Reference in new issue
Block a user