From b2f9f100af4a5bbb5a53c4b98b32b594cf51b2c8 Mon Sep 17 00:00:00 2001 From: JezerM Date: Thu, 27 Jan 2022 18:33:15 -0600 Subject: [PATCH] Refactor brightness to use web-greeter's controller --- web-greeter/bridge/Greeter.py | 61 ++---------- web-greeter/bridge/__init__.py | 16 ---- web-greeter/browser/window.py | 15 ++- web-greeter/utils/battery.py | 6 +- web-greeter/utils/brightness.py | 165 ++++++++++++++++++++++++++++++++ 5 files changed, 182 insertions(+), 81 deletions(-) create mode 100644 web-greeter/utils/brightness.py diff --git a/web-greeter/bridge/Greeter.py b/web-greeter/bridge/Greeter.py index 4846058..6eedf8a 100644 --- a/web-greeter/bridge/Greeter.py +++ b/web-greeter/bridge/Greeter.py @@ -42,6 +42,7 @@ from PyQt5.QtCore import QFileSystemWatcher, QVariant, QTimer from config import web_greeter_config from utils.battery import Battery from utils.screensaver import reset_screensaver +from utils.brightness import BrightnessController import globals # This Application @@ -59,54 +60,6 @@ from . import ( LightDMGreeter = LightDM.Greeter() LightDMUsers = LightDM.UserList() - -def changeBrightness(method: str, quantity: int = None): - backlight = web_greeter_config["config"]["features"]["backlight"] - if not backlight["enabled"]: - return - if not quantity: - quantity = backlight["value"] - try: - steps = backlight["steps"] - child = subprocess.run(["xbacklight", method, str(quantity), "-steps", str(steps)]) - if child.returncode == 1: - raise ChildProcessError("xbacklight returned 1") - except Exception as err: - logger.error("Brightness: {}".format(err)) - else: - if globals.greeter: - globals.greeter.greeter.brightness_update.emit() - -def increaseBrightness(quantity: int = None): - backlight = web_greeter_config["config"]["features"]["backlight"] - if not backlight["enabled"]: - return - if not quantity: - quantity = backlight["value"] - thread = threading.Thread(target=changeBrightness, - args=("-inc", quantity)) - thread.start() - -def decreaseBrightness(quantity: int = None): - backlight = web_greeter_config["config"]["features"]["backlight"] - if not backlight["enabled"]: - return - if not quantity: - quantity = backlight["value"] - thread = threading.Thread(target=changeBrightness, - args=("-dec", quantity)) - thread.start() - -def setBrightness(quantity: int = None): - backlight = web_greeter_config["config"]["features"]["backlight"] - if not backlight["enabled"]: - return - if not quantity: - quantity = backlight["value"] - thread = threading.Thread(target=changeBrightness, - args=("-set", quantity)) - thread.start() - def getBrightness(self): if self._config["features"]["backlight"]["enabled"] != True: return -1 @@ -146,6 +99,8 @@ class Greeter(BridgeObject): if self._config["features"]["battery"]: self._battery = Battery() + self._brightness_controller = BrightnessController() + try: LightDMGreeter.connect_to_daemon_sync() except Exception as err: @@ -220,11 +175,11 @@ class Greeter(BridgeObject): @Bridge.prop(int, notify=brightness_update) def brightness(self): - return getBrightness(self) + return self._brightness_controller.brightness @brightness.setter def brightness(self, quantity): - setBrightness(quantity) + self._brightness_controller.brightness = quantity @Bridge.prop(bool, notify=noop_signal) def can_hibernate(self): @@ -353,15 +308,15 @@ class Greeter(BridgeObject): @Bridge.method(int) def brightnessSet(self, quantity): - setBrightness(quantity) + self._brightness_controller.set_brightness(quantity) @Bridge.method(int) def brightnessIncrease(self, quantity): - increaseBrightness(quantity) + self._brightness_controller.inc_brightness(quantity) @Bridge.method(int) def brightnessDecrease(self, quantity): - decreaseBrightness(quantity) + self._brightness_controller.dec_brightness(quantity) @Bridge.method() def cancel_authentication(self): diff --git a/web-greeter/bridge/__init__.py b/web-greeter/bridge/__init__.py index 157a37c..68220d5 100644 --- a/web-greeter/bridge/__init__.py +++ b/web-greeter/bridge/__init__.py @@ -50,22 +50,6 @@ stream_handler.setFormatter(formatter) logger.setLevel(DEBUG) logger.addHandler(stream_handler) - -class setInterval: - def __init__(self, interval, action): - self.interval = interval - self.action = action - self.stopEvent = threading.Event() - thread = threading.Thread(target=self.__setInterval) - thread.start() - - def __setInterval(self): - nextTime = time.time() + self.interval - while not self.stopEvent.wait(nextTime - time.time()): - nextTime += self.interval - self.action() - - def language_to_dict(lang): if (not lang): return dict() diff --git a/web-greeter/browser/window.py b/web-greeter/browser/window.py index 5f8ad95..0925a67 100644 --- a/web-greeter/browser/window.py +++ b/web-greeter/browser/window.py @@ -25,7 +25,6 @@ # You should have received a copy of the GNU General Public License # along with Web Greeter; If not, see . -from bridge.Greeter import changeBrightness, decreaseBrightness, increaseBrightness from PyQt5.QtCore import QFileSystemWatcher, Qt from PyQt5.QtWidgets import QAction, QMainWindow from PyQt5.QtGui import QKeyEvent @@ -37,7 +36,6 @@ class MainWindow(QMainWindow): def __init__(self): super().__init__() self.init_actions() - # self.watchBrightness() def init_actions(self): devAct = QAction(text="&Toggle Devtools", parent=self) @@ -59,14 +57,13 @@ class MainWindow(QMainWindow): globals.greeter.toggle_devtools() def inc_brightness(self): - increaseBrightness() + if globals.greeter: + value = web_greeter_config["config"]["features"]["backlight"]["value"] + globals.greeter.greeter.inc_brightness(value) def dec_brightness(self): - decreaseBrightness() - - def watchBrightness(self): - self.watcher = QFileSystemWatcher(parent=self) - self.watcher.addPath("/sys/class/backlight/intel_backlight/brightness") - self.watcher.fileChanged.connect(self.updateBrightness) + if globals.greeter: + value = web_greeter_config["config"]["features"]["backlight"]["value"] + globals.greeter.greeter.dec_brightness(value) def updateBrightness(self): if globals.greeter: diff --git a/web-greeter/utils/battery.py b/web-greeter/utils/battery.py index 255dd2f..02b7ab3 100644 --- a/web-greeter/utils/battery.py +++ b/web-greeter/utils/battery.py @@ -23,7 +23,7 @@ class Battery: callbacks = [] def __init__(self): - if self._batteries.__len__() == 0: + if len(self._batteries) == 0: scandir_line(self.pspath, self._update_batteries) start_timer(self.full_update, self.onerror) self.full_update() @@ -53,8 +53,8 @@ class Battery: self.ac = match.group() if match else self.ac # Based on "bat" widget from "lain" awesome-wm library - # * (c) 2013, Luca CPZ - # * (c) 2010-2012, Peter Hofmann + # * (c) 2013, Luca CPZ + # * (c) 2010-2012, Peter Hofmann # @see https://github.com/lcpz/lain/blob/master/widget/bat.lua def full_update(self): global running diff --git a/web-greeter/utils/brightness.py b/web-greeter/utils/brightness.py new file mode 100644 index 0000000..b2091cb --- /dev/null +++ b/web-greeter/utils/brightness.py @@ -0,0 +1,165 @@ +# -*- coding: utf-8 -*- +# +# brightness.py +# +# Copyright © 2021 JezerM +# +# This file is part of Web Greeter. +# +# Web Greeter is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Web Greeter is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# The following additional terms are in effect as per Section 7 of the license: +# +# The preservation of all legal notices and author attributions in +# the material or in the Appropriate Legal Notices displayed +# by works containing it is required. +# +# You should have received a copy of the GNU General Public License +# along with Web Greeter; If not, see . + +import os +import stat +import time +import pyinotify +from typing import List +from threading import Thread +import globals +from logger import logger +from config import web_greeter_config + +sys_path = ["/sys/class/backlight/"] + +def get_controllers() -> List[str]: + ctrls: List[str] = [] + for dev in sys_path: + if os.path.exists(dev) and stat.S_ISDIR(os.stat(dev).st_mode): + drs = os.listdir(dev) + for name in drs: + ctrls.append(os.path.join(dev, name)) + return ctrls + +class EventHandler(pyinotify.ProcessEvent): + def process_IN_MODIFY(self, event): + if globals.greeter: + globals.greeter.greeter.brightness_update.emit() + + +# Behavior based on "acpilight" +# Copyright(c) 2016-2019 by wave++ "Yuri D'Elia" +# See https://gitlab.com/wavexx/acpilight +class BrightnessController: + + _controllers: List[str] = [] + _available: bool = False + _brightness_path: str + _max_brightness_path: str + steps: int + delay: int + _brightness: int + _max_brightness: int = -1 + + def __init__(self): + self._controllers = get_controllers() + if (len(self._controllers) == 0 or + self._controllers[0] == None or + web_greeter_config["config"]["features"]["backlight"]["enabled"] == False): + self._available = False + return + b_path = self._controllers[0] + self._available = True + self._brightness_path = os.path.join(b_path, "brightness") + self._max_brightness_path = os.path.join(b_path, "max_brightness") + + with open(self._max_brightness_path, "r") as f: + self._max_brightness = int(f.read()) + + steps = web_greeter_config["config"]["features"]["backlight"]["steps"] + self.steps = 1 if steps <= 1 else steps + self.delay = 200 + self.watch_brightness() + + def _watch(self): + wm = pyinotify.WatchManager() + handler = EventHandler() + wm.add_watch(self._brightness_path, pyinotify.IN_MODIFY) + + notifier = pyinotify.Notifier(wm, handler) + + notifier.loop() + + def watch_brightness(self): + if not self._available: + return + thread = Thread(target = self._watch) + thread.daemon = True + thread.start() + + @property + def max_brightness(self) -> int: + return self._max_brightness + + @property + def real_brightness(self) -> int: + if not self._available: return -1 + try: + with open(self._brightness_path, "r") as f: + return int(f.read()) + except OSError: + logger.error("Couldn't read from \"" + self._brightness_path + "\"") + return -1 + + @real_brightness.setter + def real_brightness(self, v: int): + if not self._available: return + if v > self.max_brightness: v = self.max_brightness + elif v <= 0: v = 0 + + if not os.path.exists(self._brightness_path): return + + try: + with open(self._brightness_path, "w") as f: + f.write(str(round(v))) + except OSError: + logger.error("Couldn't write to \"" + self._brightness_path + "\"") + + @property + def brightness(self) -> int: + if not self._available: return -1 + return round(self.real_brightness * 100 / self.max_brightness) + + @brightness.setter + def brightness(self, v: int): + self.real_brightness = round(v * self.max_brightness / 100) + + def _set_brightness(self, value: int): + if not self._available: return + steps = self.steps or 1 + sleep = self.delay / steps + current = self.brightness + + if steps <= 1: + self.brightness = value + return + + for i in range(steps + 1): + time.sleep(sleep / 1000) + brigh = current + ((value - current) * i) / steps + self.brightness = round(brigh) + + def set_brightness(self, value: int): + thread = Thread(target = self._set_brightness, args = (value,)) + thread.start() + + def inc_brightness(self, value: int): + self.set_brightness(self.brightness + value) + + def dec_brightness(self, value: int): + self.set_brightness(self.brightness - value)