Browse Source

Migrated from python-xlib to python C binding

This fixes screensaver related uses at lockscreen
sisyphus
JezerM 3 years ago
parent
commit
94b30e631a
No known key found for this signature in database
GPG Key ID: 66BBC5D01388C6B5
  1. 1
      requirements.txt
  2. 1
      src/bindings/__init__.py
  3. 64
      src/bindings/screensaver.c
  4. 76
      src/bindings/screensaver.py
  5. 2
      src/bridge/Greeter.py
  6. 2
      src/browser/browser.py
  7. 60
      src/utils/screensaver.py

1
requirements.txt

@ -2,5 +2,4 @@ PyGObject
PyQt5 PyQt5
PyQtWebEngine PyQtWebEngine
ruamel.yaml ruamel.yaml
python-xlib
pyinotify pyinotify

1
src/bindings/__init__.py

@ -0,0 +1 @@
from .screensaver import screensaver

64
src/bindings/screensaver.c

@ -0,0 +1,64 @@
#include <stdlib.h>
#include <stdbool.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
Display* OpenDisplay() {
char *disp = NULL;
Display *display = XOpenDisplay(disp);
return display;
}
typedef struct {
int timeout;
int interval;
int prefer_blank;
int allow_exp;
} ScreenSaver;
ScreenSaver *get_screensaver() {
int timeout, interval, prefer_blank, allow_exp;
Display *display = OpenDisplay();
if (display == NULL) return NULL;
XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
XCloseDisplay(display);
ScreenSaver *data = malloc(sizeof *data);
data->timeout = timeout;
data->interval = interval;
data->prefer_blank = prefer_blank;
data->allow_exp = allow_exp;
return data;
}
void set_screensaver(int timeout, int interval, int prefer_blank, int allow_exp) {
int timeout_i, interval_i, prefer_blank_i, allow_exp_i;
Display *display = OpenDisplay();
if (display == NULL) return;
XGetScreenSaver(display, &timeout_i, &interval_i, &prefer_blank_i, &allow_exp_i);
if (timeout != -1) timeout_i = timeout;
if (interval != -1) interval_i = interval;
if (prefer_blank != -1) prefer_blank_i = prefer_blank;
if (allow_exp != -1) allow_exp_i = allow_exp;
XSetScreenSaver(display, timeout_i, interval_i, prefer_blank_i, allow_exp_i);
XCloseDisplay(display);
}
void force_screensaver(bool value) {
Display *display = OpenDisplay();
if (display == NULL) return;
if (value == true)
XForceScreenSaver(display, ScreenSaverActive);
else
XForceScreenSaver(display, ScreenSaverReset);
XCloseDisplay(display);
}

76
src/bindings/screensaver.py

@ -0,0 +1,76 @@
import ctypes
import os
from typing import Union
from logger import logger
class ScreenSaverData(ctypes.Structure):
"""Screensaver data"""
_fields_ = [
("timeout", ctypes.c_int),
("interval", ctypes.c_int),
("prefer_blank", ctypes.c_int),
("allow_exp", ctypes.c_int),
]
def __str__(self):
timeout = getattr(self, "timeout")
interval = getattr(self, "interval")
prefer_blank = getattr(self, "prefer_blank")
allow_exp = getattr(self, "allow_exp")
return f"{timeout} {interval} {prefer_blank} {allow_exp}"
ScreenSaverDataPointer = ctypes.POINTER(ScreenSaverData)
class ScreenSaver:
"""Screensaver wrapper"""
saved_data: Union[ScreenSaverData, None]
saved: bool = False
def __init__(self):
dir = os.path.dirname(os.path.realpath(__file__))
libname = os.path.join(dir, "_screensaver.so")
self.clib = ctypes.CDLL(libname)
self.clib.get_screensaver.restype = ScreenSaverDataPointer
def get_screensaver(self):
"""Gets screensaver data"""
data: ScreenSaverDataPointer = self.clib.get_screensaver()
if data is None:
return
contents: ScreenSaverData = data.contents
return contents
def set_screensaver(self, timeout = -1, interval = -1, prefer_blank = -1, allow_exp = -1):
"""Sets screensaver properties"""
if self.saved:
return
self.saved_data = self.get_screensaver()
self.saved = True
self.clib.set_screensaver(
ctypes.c_int(timeout),
ctypes.c_int(interval),
ctypes.c_int(prefer_blank),
ctypes.c_int(allow_exp)
)
logger.debug("Screensaver timeout set")
def reset_screensaver(self):
"""Reset screensaver"""
if not self.saved or not self.saved_data:
return
self.clib.set_screensaver(
ctypes.c_int(getattr(self.saved_data, "timeout")),
ctypes.c_int(getattr(self.saved_data, "interval")),
ctypes.c_int(getattr(self.saved_data, "prefer_blank")),
ctypes.c_int(getattr(self.saved_data, "allow_exp"))
)
self.saved = False
logger.debug("Screensaver reset")
def force_screensaver(self, value: bool):
"""Force screensaver"""
self.clib.force_screensaver(ctypes.c_bool(value))
screensaver = ScreenSaver()

2
src/bridge/Greeter.py

@ -43,7 +43,7 @@ from browser.bridge import Bridge, BridgeObject
from config import web_greeter_config from config import web_greeter_config
from utils.battery import Battery from utils.battery import Battery
from utils.screensaver import screensaver from bindings.screensaver import screensaver
from utils.brightness import BrightnessController from utils.brightness import BrightnessController
from . import ( from . import (

2
src/browser/browser.py

@ -61,7 +61,7 @@ from browser.window import MainWindow
from logger import logger from logger import logger
from config import web_greeter_config from config import web_greeter_config
from utils.screensaver import screensaver from bindings.screensaver import screensaver
# pylint: disable-next=unused-import # pylint: disable-next=unused-import
# Do not ever remove this import # Do not ever remove this import

60
src/utils/screensaver.py

@ -1,60 +0,0 @@
from Xlib import X
from Xlib.display import Display
from Xlib.error import DisplayError
from logger import logger
class Screensaver:
"""Screensaver class"""
display: Display
available: bool = False
saved_data: dict[str, int]
saved: bool = False
def __init__(self):
self.init_display()
def init_display(self):
"""Init display"""
try:
self.display = Display()
self.available = True
except DisplayError as err:
logger.error("Xlib error: %s", err)
def set_screensaver(self, timeout: int):
"""Set screensaver timeout"""
if self.saved or not self.available:
return
self.display.sync()
self.display.sync()
# pylint: disable-next=protected-access
data: dict[str, int] = self.display.get_screen_saver()._data or {}
self.saved_data = data
self.saved = True
self.display.set_screen_saver(timeout,
data["interval"],
data["prefer_blanking"],
data["allow_exposures"])
self.display.flush()
logger.debug("Screensaver timeout set")
def reset_screensaver(self):
"""Reset screensaver"""
if not self.saved or not self.available:
return
self.display.sync()
self.display.set_screen_saver(self.saved_data["timeout"],
self.saved_data["interval"],
self.saved_data["prefer_blanking"],
self.saved_data["allow_exposures"])
self.display.flush()
self.saved = False
logger.debug("Screensaver reset")
def force_screensaver(self, value: bool):
"""Force screensaver"""
self.display.force_screen_saver(X.ScreenSaverActive if value else X.ScreenSaverReset)
screensaver = Screensaver()
Loading…
Cancel
Save