Pause X screen blanking while an inhibit is active
Browsers don't pause X blanking themselves, so the screen still went black after 10 minutes even with xautolock disabled. Use XScreenSaverSuspend (MIT-SCREEN-SAVER) instead of xset: no global setting is changed, and the X server ends the pause on its own if the daemon exits or crashes. The suspend also holds off DPMS. Add libx11 and libxss to depends.
This commit is contained in:
@@ -9,7 +9,9 @@ pkgdesc='Honor org.freedesktop.ScreenSaver inhibit requests by disabling xautolo
|
|||||||
arch=('any')
|
arch=('any')
|
||||||
url="https://git.shouldnt.work/fuxino/${pkgname}"
|
url="https://git.shouldnt.work/fuxino/${pkgname}"
|
||||||
license=('GPL-3.0-or-later')
|
license=('GPL-3.0-or-later')
|
||||||
depends=('python'
|
depends=('libx11'
|
||||||
|
'libxss'
|
||||||
|
'python'
|
||||||
'python-gobject'
|
'python-gobject'
|
||||||
'xautolock')
|
'xautolock')
|
||||||
makedepends=('git')
|
makedepends=('git')
|
||||||
|
|||||||
+60
-9
@@ -1,7 +1,11 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Own org.freedesktop.ScreenSaver and turn inhibit requests into xautolock -disable/-enable."""
|
"""Own org.freedesktop.ScreenSaver and turn inhibit requests into xautolock -disable/-enable.
|
||||||
|
|
||||||
|
While an inhibit is active, X screen blanking is also paused (like mpv does).
|
||||||
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import ctypes
|
||||||
import itertools
|
import itertools
|
||||||
import signal
|
import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -62,9 +66,49 @@ def xautolock(arg):
|
|||||||
log(f"xautolock {arg} failed: {e}")
|
log(f"xautolock {arg} failed: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
class XBlanking:
|
||||||
|
"""Pause X screen blanking with XScreenSaverSuspend (MIT-SCREEN-SAVER extension).
|
||||||
|
|
||||||
|
Unlike `xset s off -dpms` this changes no global setting: the X server ends the
|
||||||
|
pause by itself when this client releases it or its connection closes (exit, crash).
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.dpy = None
|
||||||
|
try:
|
||||||
|
self.x11 = ctypes.CDLL("libX11.so.6")
|
||||||
|
self.xss = ctypes.CDLL("libXss.so.1")
|
||||||
|
except OSError as e:
|
||||||
|
log(f"Cannot load X11 libraries ({e}); X blanking will not be paused")
|
||||||
|
return
|
||||||
|
self.x11.XOpenDisplay.argtypes = [ctypes.c_char_p]
|
||||||
|
self.x11.XOpenDisplay.restype = ctypes.c_void_p
|
||||||
|
self.x11.XFlush.argtypes = [ctypes.c_void_p]
|
||||||
|
self.xss.XScreenSaverQueryExtension.argtypes = [
|
||||||
|
ctypes.c_void_p, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)]
|
||||||
|
self.xss.XScreenSaverSuspend.argtypes = [ctypes.c_void_p, ctypes.c_int]
|
||||||
|
|
||||||
|
dpy = self.x11.XOpenDisplay(None)
|
||||||
|
if not dpy:
|
||||||
|
log("Cannot open the X display; X blanking will not be paused")
|
||||||
|
return
|
||||||
|
event_base, error_base = ctypes.c_int(), ctypes.c_int()
|
||||||
|
if not self.xss.XScreenSaverQueryExtension(dpy, ctypes.byref(event_base), ctypes.byref(error_base)):
|
||||||
|
log("X server lacks the MIT-SCREEN-SAVER extension; X blanking will not be paused")
|
||||||
|
return
|
||||||
|
self.dpy = dpy
|
||||||
|
|
||||||
|
def suspend(self, on):
|
||||||
|
if self.dpy:
|
||||||
|
self.xss.XScreenSaverSuspend(self.dpy, int(on))
|
||||||
|
self.x11.XFlush(self.dpy)
|
||||||
|
log(f"X blanking {'paused' if on else 'resumed'}")
|
||||||
|
|
||||||
|
|
||||||
class Inhibitor:
|
class Inhibitor:
|
||||||
def __init__(self, ignored_reasons, release_delay):
|
def __init__(self, ignored_reasons, release_delay, blanking):
|
||||||
self.ignored_reasons = ignored_reasons
|
self.ignored_reasons = ignored_reasons
|
||||||
|
self.blanking = blanking
|
||||||
self.release_delay = release_delay
|
self.release_delay = release_delay
|
||||||
self.cookies = {} # cookie -> (sender, application_name, reason, counts)
|
self.cookies = {} # cookie -> (sender, application_name, reason, counts)
|
||||||
self.next_cookie = itertools.count(1)
|
self.next_cookie = itertools.count(1)
|
||||||
@@ -85,8 +129,7 @@ class Inhibitor:
|
|||||||
GLib.source_remove(self.release_timer)
|
GLib.source_remove(self.release_timer)
|
||||||
self.release_timer = 0
|
self.release_timer = 0
|
||||||
if active and not self.disabled:
|
if active and not self.disabled:
|
||||||
xautolock("-disable")
|
self.block()
|
||||||
self.disabled = True
|
|
||||||
elif not active and self.disabled and not self.release_timer:
|
elif not active and self.disabled and not self.release_timer:
|
||||||
# Browsers send quick Inhibit/UnInhibit bursts when a video starts.
|
# Browsers send quick Inhibit/UnInhibit bursts when a video starts.
|
||||||
self.release_timer = GLib.timeout_add_seconds(self.release_delay, self.on_release_timeout)
|
self.release_timer = GLib.timeout_add_seconds(self.release_delay, self.on_release_timeout)
|
||||||
@@ -94,17 +137,25 @@ class Inhibitor:
|
|||||||
def on_release_timeout(self):
|
def on_release_timeout(self):
|
||||||
self.release_timer = 0
|
self.release_timer = 0
|
||||||
if not self.active_count() and self.disabled:
|
if not self.active_count() and self.disabled:
|
||||||
xautolock("-enable")
|
self.unblock()
|
||||||
self.disabled = False
|
|
||||||
return GLib.SOURCE_REMOVE
|
return GLib.SOURCE_REMOVE
|
||||||
|
|
||||||
|
def block(self):
|
||||||
|
xautolock("-disable")
|
||||||
|
self.blanking.suspend(True)
|
||||||
|
self.disabled = True
|
||||||
|
|
||||||
|
def unblock(self):
|
||||||
|
xautolock("-enable")
|
||||||
|
self.blanking.suspend(False)
|
||||||
|
self.disabled = False
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
if self.release_timer:
|
if self.release_timer:
|
||||||
GLib.source_remove(self.release_timer)
|
GLib.source_remove(self.release_timer)
|
||||||
self.release_timer = 0
|
self.release_timer = 0
|
||||||
if self.disabled:
|
if self.disabled:
|
||||||
xautolock("-enable")
|
self.unblock()
|
||||||
self.disabled = False
|
|
||||||
|
|
||||||
# --- D-Bus ------------------------------------------------------------
|
# --- D-Bus ------------------------------------------------------------
|
||||||
|
|
||||||
@@ -205,7 +256,7 @@ def main():
|
|||||||
ignored = set()
|
ignored = set()
|
||||||
else:
|
else:
|
||||||
ignored = set(args.ignore_reason or ["Playing audio"])
|
ignored = set(args.ignore_reason or ["Playing audio"])
|
||||||
inhibitor = Inhibitor(ignored, max(args.release_delay, 0))
|
inhibitor = Inhibitor(ignored, max(args.release_delay, 0), XBlanking())
|
||||||
loop = GLib.MainLoop()
|
loop = GLib.MainLoop()
|
||||||
exit_code = 0
|
exit_code = 0
|
||||||
acquired = False
|
acquired = False
|
||||||
|
|||||||
Reference in New Issue
Block a user