diff --git a/web-greeter/bridge/Greeter.py b/web-greeter/bridge/Greeter.py index 3460d35..d77104f 100644 --- a/web-greeter/bridge/Greeter.py +++ b/web-greeter/bridge/Greeter.py @@ -47,6 +47,7 @@ from . import ( session_to_dict, user_to_dict, battery_to_dict, + debugLog ) LightDMGreeter = LightDM.Greeter() @@ -62,9 +63,9 @@ def changeBrightness(self, method: str, quantity: int): if child.returncode == 1: raise ChildProcessError("xbacklight returned 1") except Exception as err: - print("[ERROR] Brightness:", err) - finally: - self.property_changed.emit() + debugLog("Brightness: {}".format(err), 4) + else: + self.brightness_update.emit() pass def getBrightness(self): @@ -74,7 +75,7 @@ def getBrightness(self): level = subprocess.run(["xbacklight", "-get"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True) return int(level.stdout) except Exception as err: - print("[ERROR] Battery:", err) + debugLog("Battery: {}".format(err), 4) return -1 def updateBattery(self): @@ -90,7 +91,7 @@ def updateBattery(self): self._battery = int(level) self._acpi = acpi.stdout except Exception as err: - print("[ERROR] Battery: ", err) + debugLog("Battery: {}".format(err), 4) else: self.property_changed.emit() @@ -104,6 +105,8 @@ class Greeter(BridgeObject): show_message = bridge.signal(str, LightDM.MessageType, arguments=('text', 'type')) show_prompt = bridge.signal(str, LightDM.PromptType, arguments=('text', 'type')) + brightness_update = bridge.signal() + noop_signal = bridge.signal() property_changed = bridge.signal() @@ -149,6 +152,7 @@ class Greeter(BridgeObject): lambda greeter, msg, mtype: self._emit_signal(self.show_prompt, msg, mtype) ) + def _emit_signal(self, _signal, *args): self.property_changed.emit() QTimer().singleShot(300, lambda: _signal.emit(*args)) @@ -173,7 +177,7 @@ class Greeter(BridgeObject): def batteryData(self): return battery_to_dict(self._acpi) - @bridge.prop(int, notify=property_changed) + @bridge.prop(int, notify=brightness_update) def brightness(self): return getBrightness(self) @@ -291,6 +295,10 @@ class Greeter(BridgeObject): LightDMGreeter.authenticate_as_guest() self.property_changed.emit() + @bridge.method() + def batteryUpdate(self): + return updateBattery(self) + @bridge.method(int) def brightnessSet(self, quantity): return changeBrightness(self, "-set", quantity) @@ -338,13 +346,11 @@ class Greeter(BridgeObject): @bridge.method(str, result=bool) def start_session(self, session): - return LightDMGreeter.start_session_sync(session) + if not session.strip(): + return + return LightDMGreeter.start_session(session) @bridge.method(result=bool) def suspend(self): return LightDM.suspend() - @bridge.method() - def batteryUpdate(self): - return updateBattery(self) - diff --git a/web-greeter/bridge/__init__.py b/web-greeter/bridge/__init__.py index e401038..8660913 100644 --- a/web-greeter/bridge/__init__.py +++ b/web-greeter/bridge/__init__.py @@ -27,6 +27,38 @@ # along with Web Greeter; If not, see . import re +from logging import ( + getLogger, + DEBUG, + ERROR, + Formatter, + StreamHandler, +) + +log_format = ''.join([ + '%(asctime)s [ %(levelname)s ] %(filename)s %(', + 'lineno)d: %(message)s' +]) +formatter = Formatter(fmt=log_format, datefmt="%Y-%m-%d %H:%M:%S") +logger = getLogger("greeter") +logger.propagate = False +stream_handler = StreamHandler() +stream_handler.setLevel(DEBUG) +stream_handler.setFormatter(formatter) +logger.setLevel(DEBUG) +logger.addHandler(stream_handler) + +def debugLog(txt: str, level: int = 1): + if (level == 1): + logger.debug(txt) + elif (level == 2): + logger.info(txt) + elif (level == 3): + logger.warn(txt) + elif (level == 4): + logger.error(txt) + else: + logger.debug(txt) def language_to_dict(lang): @@ -60,10 +92,6 @@ def user_to_dict(user): logged_in=user.get_logged_in(), session=user.get_session(), username=user.get_name(), - # ---->>> BEGIN DEPRECATED! <<<---- - name=user.get_name(), - real_name=user.get_real_name(), - # ---->>> END DEPRECATED! <<<---- ) def battery_to_dict(batt): diff --git a/web-greeter/globals.py b/web-greeter/globals.py index 9480d68..05ae316 100644 --- a/web-greeter/globals.py +++ b/web-greeter/globals.py @@ -48,14 +48,75 @@ from bridge import ( Greeter, ThemeUtils, ) +from logging import ( + getLogger, + DEBUG, + ERROR, + Formatter, + StreamHandler, +) from PyQt5.QtWidgets import QMainWindow from PyQt5.QtGui import QColor +import subprocess # Typing Helpers BridgeObj = Type[BridgeObject] +log_format = ''.join([ + '%(asctime)s [ %(levelname)s ] %(module)s - %(filename)s:%(', + 'lineno)d : %(funcName)s | %(message)s' +]) +formatter = Formatter(fmt=log_format, datefmt="%Y-%m-%d %H:%M:%S") +stream_handler = StreamHandler() +logger = getLogger("debug") + +stream_handler.setLevel(DEBUG) +stream_handler.setFormatter(formatter) +logger.propagate = False +logger.setLevel(DEBUG) +logger.addHandler(stream_handler) + +def debugLog(txt: str, level: int = 1): + if (level == 1): + logger.debug(txt) + elif (level == 2): + logger.info(txt) + elif (level == 3): + logger.warn(txt) + elif (level == 4): + logger.error(txt) + else: + logger.debug(txt) + +initial_timeout = 0 + +def setScreenSaver(timeout: int): + global initial_timeout + timeout = timeout if timeout >= 0 else 300 + try: + child = subprocess.Popen(["xset", "q"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + awk = subprocess.run(["awk", "/^ timeout: / {print $2}"], stdout=subprocess.PIPE, stdin=child.stdout, text=True) + + initial_timeout = int(awk.stdout.replace("\n", "")) + + subprocess.run(["xset", "s", str(timeout)], check=True) + + except Exception as err: + debugLog("Screensaver timeout couldn't be set", 4) + else: + debugLog("Screensaver timeout set") + +def resetScreenSaver(): + try: + subprocess.run(["xset", "s", str(initial_timeout)]) + except Exception as err: + debugLog("Screensaver reset failed", 4) + else: + debugLog("Screensaver reset") + + BASE_DIR = os.path.dirname(os.path.realpath(__file__)) CONFIG_FILE = os.path.join(BASE_DIR, 'whither.yml') @@ -75,6 +136,8 @@ class WebGreeter(App): page = self._main_window.widget.centralWidget().page() page.setBackgroundColor(QColor(0,0,0)) + setScreenSaver(self.config.greeter["screensaver_timeout"]) + self._web_container.initialize_bridge_objects() self._web_container.load_script(':/_greeter/js/bundle.js', 'Web Greeter Bundle') self.load_theme() @@ -86,6 +149,9 @@ class WebGreeter(App): def _before_web_container_init(self): self.get_and_apply_user_config() + def _before_exit(self): + resetScreenSaver() + @classmethod def validate_greeter_config_data(cls, key: str, data: str) -> str: if "'@" not in data: diff --git a/web-greeter/greeter.py b/web-greeter/greeter.py index 0c668e7..093d594 100644 --- a/web-greeter/greeter.py +++ b/web-greeter/greeter.py @@ -37,12 +37,6 @@ from typing import ( List, Tuple, ) -from logging import ( - getLogger, - DEBUG, - Formatter, - StreamHandler, -) # 3rd-Party Libs @@ -64,23 +58,6 @@ def loadWhitherConf(): whither_yaml = yaml.safe_load(file_test) webGreeter_conf = whither_yaml["WebGreeter"] - -def debugLog(txt: str): - log_format = ''.join([ - '%(asctime)s [ %(levelname)s ] %(module)s - %(filename)s:%(', - 'lineno)d : %(funcName)s | %(message)s' - ]) - - formatter = Formatter(fmt=log_format, datefmt="%Y-%m-%d %H:%M:%S") - stream_handler = StreamHandler() - logger = getLogger() - - stream_handler.setLevel(DEBUG) - stream_handler.setFormatter(formatter) - logger.setLevel(DEBUG) - logger.addHandler(stream_handler) - logger.debug(txt) - def show_help(): version = webGreeter_conf["app"]["version"]["full"] help_text = """Usage: @@ -124,7 +101,7 @@ def changeTheme(theme: str): if theme in dirlist: custom_config["theme"] = theme else: - debugLog("Theme not found. Going with config theme") + globals.debugLog("Theme not found. Going with config theme", 4) return def listThemes(quiet = False): @@ -196,7 +173,6 @@ if __name__ == '__main__': args.pop(0) yargs(args) - globals.greeter = WebGreeter() globals.greeter.run() diff --git a/web-greeter/resources/js/ThemeUtils.js b/web-greeter/resources/js/ThemeUtils.js index 787739b..9fcbd45 100644 --- a/web-greeter/resources/js/ThemeUtils.js +++ b/web-greeter/resources/js/ThemeUtils.js @@ -100,11 +100,11 @@ class ThemeUtils { */ dirlist( path, only_images = true, callback ) { if ( '' === path || 'string' !== typeof path ) { - console.error('[ERROR] theme_utils.dirlist(): path must be a non-empty string!'); + console.error(`theme_utils.dirlist(): path must be a non-empty string!`); return callback([]); } else if ( null !== path.match(/^[^/].+/) ) { - console.error('[ERROR] theme_utils.dirlist(): path must be absolute!'); + console.error(`theme_utils.dirlist(): path must be absolute!`); return callback([]); } @@ -116,7 +116,7 @@ class ThemeUtils { try { return _ThemeUtils.dirlist( path, only_images, callback ); } catch( err ) { - console.error( `[ERROR] theme_utils.dirlist(): ${err}` ); + console.error(`theme_utils.dirlist(): ${err}`); return callback([]); } } diff --git a/web-greeter/resources/js/docs/Greeter.js b/web-greeter/resources/js/docs/Greeter.js index b69222b..141c551 100644 --- a/web-greeter/resources/js/docs/Greeter.js +++ b/web-greeter/resources/js/docs/Greeter.js @@ -314,19 +314,19 @@ class Greeter { get brightness() {} /** - * Set the brightness + * Set the brightness to quantity * @arg {Number} quantity The quantity to set */ brightnessSet( quantity ) {} /** - * Increase the brightness + * Increase the brightness by quantity * @arg {Number} quantity The quantity to increase */ brightnessIncrease( quantity ) {} /** - * Decrease the brightness + * Decrease the brightness by quantity * @arg {Number} quantity The quantity to decrease */ brightnessDecrease( quantity ) {} @@ -345,6 +345,11 @@ class Greeter { */ get can_access_battery() {} + /** + * Updates the battery data + */ + batteryUpdate() {} + /** * Whether or not the greeter can control display brightness * @type {boolean} diff --git a/web-greeter/utils/config.py b/web-greeter/utils/config.py index ca21e80..5cacba6 100644 --- a/web-greeter/utils/config.py +++ b/web-greeter/utils/config.py @@ -31,28 +31,56 @@ from PyQt5.QtCore import QUrl, pyqtSignal, Qt from PyQt5.QtWidgets import QDialogButtonBox, QDialog, QVBoxLayout, QLabel, QPushButton, QAbstractButton from PyQt5.QtGui import QKeyEvent +from logging import ( + getLogger, + DEBUG, + ERROR, + Formatter, + StreamHandler, +) + import globals +log_format = ''.join([ + '%(asctime)s [ %(levelname)s ] %(filename)s %(', + 'lineno)d: %(message)s' +]) +formatter = Formatter(fmt=log_format, datefmt="%Y-%m-%d %H:%M:%S") +logger = getLogger("javascript") +logger.propagate = False +stream_handler = StreamHandler() +stream_handler.setLevel(DEBUG) +stream_handler.setFormatter(formatter) +logger.setLevel(DEBUG) +logger.addHandler(stream_handler) + def javaScriptConsoleMessage(self, level: WebPage.JavaScriptConsoleMessageLevel, message: str, lineNumber: int, sourceID: str): if sourceID == "": sourceID = "console" - error = False - typeLog = "" + logLevel = 0 if level == WebPage.JavaScriptConsoleMessageLevel.ErrorMessageLevel: - typeLog = "[ERROR]" - error = True + logLevel = 40 elif level == WebPage.JavaScriptConsoleMessageLevel.WarningMessageLevel: - typeLog = "[WARNING]" + logLevel = 30 elif level == WebPage.JavaScriptConsoleMessageLevel.InfoMessageLevel: return else: return - logMessage = "{typ} {source} {line}: {msg}".format(typ = typeLog, msg = message, source = sourceID, line = lineNumber) - print(logMessage) - - if error: + record = logger.makeRecord( + name="javascript", + level=logLevel, + fn="", + lno=lineNumber, + msg=message, + args=(), + exc_info=None + ) + record.filename = sourceID + logger.handle(record) + + if logLevel == 40: errorMessage = "{source} {line}: {msg}".format(source = sourceID, line = lineNumber, msg = message) errorPrompt(errorMessage)