diff --git a/build/utils.sh b/build/utils.sh
index 16165f0..c226561 100755
--- a/build/utils.sh
+++ b/build/utils.sh
@@ -28,7 +28,6 @@ do_build() {
# Create "Zip Application"
(cd "${PKGNAME}" \
- && mv main.py __main__.py \
&& zip -rq ../"${PKGNAME}.zip" . -x '**__pycache__**' 'resources/*' \
&& cd - >/dev/null \
&& mkdir -p "${INSTALL_ROOT}${PREFIX}"/{bin,share} \
diff --git a/web-greeter/__main__.py b/web-greeter/__main__.py
new file mode 100644
index 0000000..e6a0a8b
--- /dev/null
+++ b/web-greeter/__main__.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+#
+# __main__.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 .
+
+# Standard lib
+import sys
+import ruamel.yaml as yaml
+import os
+
+# 3rd-Party Libs
+from browser.browser import Browser
+from logger import logger
+import globals
+import config
+
+if __name__ == '__main__':
+ globals.greeter = Browser()
+ greeter = globals.greeter
+ greeter.run()
diff --git a/web-greeter/bridge/Config.py b/web-greeter/bridge/Config.py
index a790cef..c9329bc 100644
--- a/web-greeter/bridge/Config.py
+++ b/web-greeter/bridge/Config.py
@@ -3,6 +3,7 @@
# Config.py
#
# Copyright © 2017 Antergos
+# Copyright © 2021 JezerM
#
# This file is part of Web Greeter.
#
@@ -26,17 +27,15 @@
# along with Web Greeter; If not, see .
# 3rd-Party Libs
-from whither.bridge import (
- BridgeObject,
- bridge,
- Variant,
-)
+from browser.bridge import Bridge, BridgeObject
+from PyQt5.QtCore import QVariant
import gi
gi.require_version('LightDM', '1')
from gi.repository import LightDM
from typing import List
+from config import web_greeter_config
from . import (
layout_to_dict
@@ -56,28 +55,29 @@ def get_layouts(config_layouts: List[str]):
class Config(BridgeObject):
- noop_signal = bridge.signal()
+ noop_signal = Bridge.signal()
- def __init__(self, config, *args, **kwargs):
+ def __init__(self, *args, **kwargs):
super().__init__(name='Config', *args, **kwargs)
- self._branding = config.branding.as_dict()
- self._greeter = config.greeter.as_dict()
- self._features = config.features.as_dict()
- self._layouts = get_layouts(config.layouts)
+ config = web_greeter_config["config"]
+ self._branding = config["branding"]
+ self._greeter = config["greeter"]
+ self._features = config["features"]
+ self._layouts = get_layouts(config["layouts"])
- @bridge.prop(Variant, notify=noop_signal)
+ @Bridge.prop(QVariant, notify=noop_signal)
def branding(self):
return self._branding
- @bridge.prop(Variant, notify=noop_signal)
+ @Bridge.prop(QVariant, notify=noop_signal)
def greeter(self):
return self._greeter
- @bridge.prop(Variant, notify=noop_signal)
+ @Bridge.prop(QVariant, notify=noop_signal)
def features(self):
return self._features
- @bridge.prop(Variant, notify=noop_signal)
+ @Bridge.prop(QVariant, notify=noop_signal)
def layouts(self):
return self._layouts
diff --git a/web-greeter/bridge/Greeter.py b/web-greeter/bridge/Greeter.py
index b9c5307..19deb2c 100644
--- a/web-greeter/bridge/Greeter.py
+++ b/web-greeter/bridge/Greeter.py
@@ -3,6 +3,7 @@
# Greeter.py
#
# Copyright © 2017 Antergos
+# Copyright © 2021 JezerM
#
# This file is part of Web Greeter.
#
@@ -27,19 +28,17 @@
# Standard Lib
import subprocess
-import re
import threading
# 3rd-Party Libs
import gi
gi.require_version('LightDM', '1')
from gi.repository import LightDM
-from whither.bridge import (
- BridgeObject,
- bridge,
- Variant,
-)
-from PyQt5.QtCore import QTimer
+
+from browser.bridge import Bridge, BridgeObject
+from PyQt5.QtCore import QVariant, QTimer
+
+from config import web_greeter_config
# This Application
from . import (
@@ -51,17 +50,17 @@ from . import (
logger
)
-import utils.battery as battery
+# import utils.battery as battery
LightDMGreeter = LightDM.Greeter()
LightDMUsers = LightDM.UserList()
def changeBrightness(self, method: str, quantity: int):
- if self._config.features.backlight["enabled"] != True:
+ if self._config["features"]["backlight"]["enabled"] != True:
return
try:
- steps = self._config.features.backlight["steps"]
+ steps = self._config["features"]["backlight"]["steps"]
child = subprocess.run(["xbacklight", method, str(quantity), "-steps", str(steps)])
if child.returncode == 1:
raise ChildProcessError("xbacklight returned 1")
@@ -72,7 +71,7 @@ def changeBrightness(self, method: str, quantity: int):
def getBrightness(self):
- if self._config.features.backlight["enabled"] != True:
+ if self._config["features"]["backlight"]["enabled"] != True:
return -1
try:
level = subprocess.run(["xbacklight", "-get"], stdout=subprocess.PIPE,
@@ -85,30 +84,30 @@ def getBrightness(self):
class Greeter(BridgeObject):
# LightDM.Greeter Signals
- authentication_complete = bridge.signal()
- autologin_timer_expired = bridge.signal()
- idle = bridge.signal()
- reset = bridge.signal()
- show_message = bridge.signal(str, LightDM.MessageType, arguments=('text', 'type'))
- show_prompt = bridge.signal(str, LightDM.PromptType, arguments=('text', 'type'))
+ authentication_complete = Bridge.signal()
+ autologin_timer_expired = Bridge.signal()
+ idle = Bridge.signal()
+ reset = Bridge.signal()
+ show_message = Bridge.signal(str, LightDM.MessageType, arguments=('text', 'type'))
+ show_prompt = Bridge.signal(str, LightDM.PromptType, arguments=('text', 'type'))
- brightness_update = bridge.signal()
- battery_update = bridge.signal()
+ brightness_update = Bridge.signal()
+ battery_update = Bridge.signal()
- noop_signal = bridge.signal()
- property_changed = bridge.signal()
+ noop_signal = Bridge.signal()
+ property_changed = Bridge.signal()
_battery = None
- def __init__(self, config, *args, **kwargs):
+ def __init__(self, *args, **kwargs):
super().__init__(name='LightDMGreeter', *args, **kwargs)
- self._config = config
+ self._config = web_greeter_config["config"]
self._shared_data_directory = ''
- self._themes_directory = config.themes_dir
+ self._themes_directory = web_greeter_config["app"]["theme_dir"]
- if self._config.features.battery == True:
- self._battery = battery.Battery()
+ # if self._config.features.battery == True:
+ # self._battery = battery.Battery()
LightDMGreeter.connect_to_daemon_sync()
@@ -149,27 +148,27 @@ class Greeter(BridgeObject):
self.property_changed.emit()
QTimer().singleShot(300, lambda: _signal.emit(*args))
- @bridge.prop(str, notify=property_changed)
+ @Bridge.prop(str, notify=property_changed)
def authentication_user(self):
return LightDMGreeter.get_authentication_user() or ''
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def autologin_guest(self):
return LightDMGreeter.get_autologin_guest_hint()
- @bridge.prop(int, notify=noop_signal)
+ @Bridge.prop(int, notify=noop_signal)
def autologin_timeout(self):
return LightDMGreeter.get_autologin_timeout_hint()
- @bridge.prop(str, notify=noop_signal)
+ @Bridge.prop(str, notify=noop_signal)
def autologin_user(self):
return LightDMGreeter.get_autologin_user_hint()
- @bridge.prop(Variant, notify=battery_update)
+ @Bridge.prop(QVariant, notify=battery_update)
def batteryData(self):
return battery_to_dict(self._battery)
- @bridge.prop(int, notify=brightness_update)
+ @Bridge.prop(int, notify=brightness_update)
def brightness(self):
return getBrightness(self)
@@ -179,63 +178,63 @@ class Greeter(BridgeObject):
args=(self, "-set", quantity))
thread.start()
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def can_hibernate(self):
return LightDM.get_can_hibernate()
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def can_restart(self):
return LightDM.get_can_restart()
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def can_shutdown(self):
return LightDM.get_can_shutdown()
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def can_suspend(self):
return LightDM.get_can_suspend()
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def can_access_brightness(self):
- return self._config.features.backlight["enabled"]
+ return self._config["features"]["backlight"]["enabled"]
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def can_access_battery(self):
- return self._config.features.battery
+ return self._config["features"]["battery"]
- @bridge.prop(str, notify=noop_signal)
+ @Bridge.prop(str, notify=noop_signal)
def default_session(self):
return LightDMGreeter.get_default_session_hint()
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def has_guest_account(self):
return LightDMGreeter.get_has_guest_account_hint()
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def hide_users_hint(self):
return LightDMGreeter.get_hide_users_hint()
- @bridge.prop(str, notify=noop_signal)
+ @Bridge.prop(str, notify=noop_signal)
def hostname(self):
return LightDM.get_hostname()
- @bridge.prop(bool, notify=property_changed)
+ @Bridge.prop(bool, notify=property_changed)
def in_authentication(self):
return LightDMGreeter.get_in_authentication()
- @bridge.prop(bool, notify=property_changed)
+ @Bridge.prop(bool, notify=property_changed)
def is_authenticated(self):
return LightDMGreeter.get_is_authenticated()
- @bridge.prop(Variant, notify=property_changed)
+ @Bridge.prop(QVariant, notify=property_changed)
def language(self):
return language_to_dict(LightDM.get_language())
- @bridge.prop(Variant, notify=noop_signal)
+ @Bridge.prop(QVariant, notify=noop_signal)
def languages(self):
return [language_to_dict(lang) for lang in LightDM.get_languages()]
- @bridge.prop(Variant, notify=noop_signal)
+ @Bridge.prop(QVariant, notify=noop_signal)
def layout(self):
return layout_to_dict(LightDM.get_layout())
@@ -250,117 +249,117 @@ class Greeter(BridgeObject):
)
return LightDM.set_layout(LightDM.Layout(**lay))
- @bridge.prop(Variant, notify=noop_signal)
+ @Bridge.prop(QVariant, notify=noop_signal)
def layouts(self):
return [layout_to_dict(layout) for layout in LightDM.get_layouts()]
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def lock_hint(self):
return LightDMGreeter.get_lock_hint()
- @bridge.prop(Variant, notify=property_changed)
+ @Bridge.prop(QVariant, notify=property_changed)
def remote_sessions(self):
return [session_to_dict(session) for session in LightDM.get_remote_sessions()]
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def select_guest_hint(self):
return LightDMGreeter.get_select_guest_hint()
- @bridge.prop(str, notify=noop_signal)
+ @Bridge.prop(str, notify=noop_signal)
def select_user_hint(self):
return LightDMGreeter.get_select_user_hint() or ''
- @bridge.prop(Variant, notify=noop_signal)
+ @Bridge.prop(QVariant, notify=noop_signal)
def sessions(self):
return [session_to_dict(session) for session in LightDM.get_sessions()]
- @bridge.prop(str, notify=noop_signal)
+ @Bridge.prop(str, notify=noop_signal)
def shared_data_directory(self):
return self._shared_data_directory
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def show_manual_login_hint(self):
return LightDMGreeter.get_show_manual_login_hint()
- @bridge.prop(bool, notify=noop_signal)
+ @Bridge.prop(bool, notify=noop_signal)
def show_remote_login_hint(self):
return LightDMGreeter.get_show_remote_login_hint()
- @bridge.prop(str, notify=noop_signal)
+ @Bridge.prop(str, notify=noop_signal)
def themes_directory(self):
return self._themes_directory
- @bridge.prop(Variant, notify=noop_signal)
+ @Bridge.prop(QVariant, notify=noop_signal)
def users(self):
return [user_to_dict(user) for user in LightDMUsers.get_users()]
- @bridge.method(str)
+ @Bridge.method(str)
def authenticate(self, username):
LightDMGreeter.authenticate(username)
self.property_changed.emit()
- @bridge.method()
+ @Bridge.method()
def authenticate_as_guest(self):
LightDMGreeter.authenticate_as_guest()
self.property_changed.emit()
- @bridge.method(int)
+ @Bridge.method(int)
def brightnessSet(self, quantity):
thread = threading.Thread(target=changeBrightness,
args=(self, "-set", quantity))
thread.start()
- @bridge.method(int)
+ @Bridge.method(int)
def brightnessIncrease(self, quantity):
thread = threading.Thread(target=changeBrightness,
args=(self, "-inc", quantity))
thread.start()
- @bridge.method(int)
+ @Bridge.method(int)
def brightnessDecrease(self, quantity):
thread = threading.Thread(target=changeBrightness,
args=(self, "-dec", quantity))
thread.start()
- @bridge.method()
+ @Bridge.method()
def cancel_authentication(self):
LightDMGreeter.cancel_authentication()
self.property_changed.emit()
- @bridge.method()
+ @Bridge.method()
def cancel_autologin(self):
LightDMGreeter.cancel_autologin()
self.property_changed.emit()
- @bridge.method(result=bool)
+ @Bridge.method(result=bool)
def hibernate(self):
return LightDM.hibernate()
- @bridge.method(str)
+ @Bridge.method(str)
def respond(self, response):
LightDMGreeter.respond(response)
self.property_changed.emit()
- @bridge.method(result=bool)
+ @Bridge.method(result=bool)
def restart(self):
return LightDM.restart()
- @bridge.method(str)
+ @Bridge.method(str)
def set_language(self, lang):
if self.is_authenticated:
LightDMGreeter.set_language(lang)
self.property_changed.emit()
- @bridge.method(result=bool)
+ @Bridge.method(result=bool)
def shutdown(self):
return LightDM.shutdown()
- @bridge.method(str, result=bool)
+ @Bridge.method(str, result=bool)
def start_session(self, session):
if not session.strip():
return
return LightDMGreeter.start_session_sync(session)
- @bridge.method(result=bool)
+ @Bridge.method(result=bool)
def suspend(self):
return LightDM.suspend()
diff --git a/web-greeter/bridge/ThemeUtils.py b/web-greeter/bridge/ThemeUtils.py
index 5f4fdf4..fb614ba 100644
--- a/web-greeter/bridge/ThemeUtils.py
+++ b/web-greeter/bridge/ThemeUtils.py
@@ -3,6 +3,7 @@
# ThemeUtils.py
#
# Copyright © 2017 Antergos
+# Copyright © 2021 JezerM
#
# This file is part of Web Greeter.
#
@@ -31,29 +32,27 @@ from glob import glob
import tempfile
# 3rd-Party Libs
-from whither.bridge import (
- BridgeObject,
- bridge,
- Variant,
-)
+from browser.bridge import Bridge, BridgeObject
+from PyQt5.QtCore import QVariant
+from config import web_greeter_config
class ThemeUtils(BridgeObject):
- def __init__(self, greeter, config, *args, **kwargs):
+ def __init__(self, greeter, *args, **kwargs):
super().__init__(name='ThemeUtils', *args, **kwargs)
- self._config = config
+ self._config = web_greeter_config
self._greeter = greeter
self._allowed_dirs = (
- self._config.themes_dir,
- self._config.branding.background_images_dir,
+ self._config["app"]["theme_dir"],
+ self._config["config"]["branding"]["background_images_dir"],
self._greeter.shared_data_directory,
tempfile.gettempdir(),
)
- @bridge.method(str, bool, result=Variant)
+ @Bridge.method(str, bool, result=QVariant)
def dirlist(self, dir_path, only_images=True):
if not dir_path or not isinstance(dir_path, str) or '/' == dir_path:
return []
diff --git a/web-greeter/bridge/devtools.py b/web-greeter/bridge/devtools.py
new file mode 100644
index 0000000..6c00ca5
--- /dev/null
+++ b/web-greeter/bridge/devtools.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+#
+# devtools.py
+#
+# Copyright © 2016-2017 Antergos
+#
+# This file is part of whither.
+#
+# whither 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.
+#
+# whither 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 whither; If not, see .
+
+# 3rd-Party Libs
+from PyQt5.QtCore import QUrl
+from PyQt5.QtWebEngineWidgets import (
+ QWebEngineView,
+ QWebEnginePage,
+)
+
+
+class DevTools:
+
+ def __init__(self):
+ super().__init__()
+
+ self.view = QWebEngineView()
+ self.page = self.view.page() # type: QWebEnginePage
+
+ self.view.load(QUrl('http://127.0.0.1:12345'))
+ self.view.show()
+
diff --git a/web-greeter/browser/__init__.py b/web-greeter/browser/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/web-greeter/browser/bridge.py b/web-greeter/browser/bridge.py
new file mode 100644
index 0000000..f5c87ad
--- /dev/null
+++ b/web-greeter/browser/bridge.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+#
+# bridge.py
+#
+# Copyright © 2016-2017 Antergos
+#
+# 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 .
+
+from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty
+
+class Bridge:
+ @staticmethod
+ def method(*args, **kwargs):
+ return pyqtSlot(*args, **kwargs)
+
+ @staticmethod
+ def prop(*args, **kwargs):
+ return pyqtProperty(*args, **kwargs)
+
+ @staticmethod
+ def signal(*args, **kwargs):
+ return pyqtSignal(*args, **kwargs)
+
+class BridgeObject(QObject):
+ def __init__(self, name: str):
+ super().__init__(parent=None)
+ self._name = name
diff --git a/web-greeter/browser/browser.py b/web-greeter/browser/browser.py
new file mode 100644
index 0000000..a46013f
--- /dev/null
+++ b/web-greeter/browser/browser.py
@@ -0,0 +1,276 @@
+# -*- coding: utf-8 -*-
+#
+# browser.py
+#
+# Copyright © 2017 Antergos
+# 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 .
+
+# Standard lib
+
+from bridge.devtools import DevTools
+import os
+from typing import (
+ Dict,
+ Tuple,
+ TypeVar,
+)
+
+# 3rd-Party Libs
+from PyQt5.QtCore import QUrl, Qt, QCoreApplication, QFile
+from PyQt5.QtWidgets import QApplication, QDesktopWidget, QMainWindow
+from PyQt5.QtWebEngineCore import QWebEngineUrlScheme
+from PyQt5.QtWebEngineWidgets import QWebEngineScript, QWebEngineProfile, QWebEngineSettings, QWebEngineView
+from PyQt5.QtGui import QColor
+from PyQt5.QtWebChannel import QWebChannel
+
+from browser.error_prompt import WebPage, errorPrompt
+from browser.url_scheme import QtUrlSchemeHandler
+from browser.interceptor import QtUrlRequestInterceptor
+
+from logger import logger
+from config import web_greeter_config
+from bridge import Greeter, Config, ThemeUtils
+import resources
+
+# Typing Helpers
+BridgeObjects = Tuple['BridgeObject']
+Url = TypeVar('Url', str, QUrl)
+
+os.environ["QT_DEVICE_PIXEL_RATIO"] = "0"
+os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
+os.environ["QT_SCREEN_SCALE_FACTORS"] = "1"
+os.environ["QT_SCALE_FACTOR"] = "1"
+
+WINDOW_STATES = {
+ 'NORMAL': Qt.WindowNoState,
+ 'MINIMIZED': Qt.WindowMinimized,
+ 'MAXIMIZED': Qt.WindowMaximized,
+ 'FULLSCREEN': Qt.WindowFullScreen,
+} # type: Dict[str, Qt.WindowState]
+
+DISABLED_SETTINGS = [
+ 'PluginsEnabled', # Qt 5.6+
+]
+
+ENABLED_SETTINGS = [
+ 'FocusOnNavigationEnabled', # Qt 5.8+
+ 'FullScreenSupportEnabled', # Qt 5.6+
+ 'LocalContentCanAccessFileUrls',
+ 'ScreenCaptureEnabled', # Qt 5.7+
+ 'ScrollAnimatorEnabled',
+ 'FocusOnNavigationEnabled', # Qt 5.11+
+]
+
+class Application:
+ app: QApplication
+ desktop: QDesktopWidget
+ window: QMainWindow
+ states = WINDOW_STATES
+
+ def __init__(self):
+ QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
+ QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
+
+ self.app = QApplication([])
+ self.window = QMainWindow()
+ self.desktop = self.app.desktop()
+
+ self.window.setAttribute(Qt.WA_DeleteOnClose)
+ self.window.setWindowTitle("Web Greeter")
+
+ self.window.setWindowFlags(self.window.windowFlags() | Qt.FramelessWindowHint)
+
+ self.window.setWindowFlags(
+ self.window.windowFlags() | Qt.MaximizeUsingFullscreenGeometryHint
+ )
+
+ state = self.states['NORMAL']
+ try:
+ self.window.windowHandle().setWindowState(state)
+ except Exception:
+ self.window.setWindowState(state)
+
+ self.window.setCursor(Qt.ArrowCursor)
+
+ self.app.aboutToQuit.connect(self._before_exit)
+
+ def _before_exit(self):
+ pass
+
+ def show(self):
+ self.window.show()
+ logger.debug("Window is ready")
+
+ def run(self) -> int:
+ logger.debug("Web Greeter started")
+ return self.app.exec_()
+
+
+class Browser(Application):
+ url_scheme: QWebEngineUrlScheme
+
+ def __init__(self):
+ super().__init__()
+ self.init()
+ self.load()
+
+ def init(self):
+ logger.debug("Initializing Browser Window")
+ web_greeter_config["config"]["greeter"]["debug_mode"] = True
+
+ if web_greeter_config["config"]["greeter"]["debug_mode"]:
+ os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = '12345'
+
+ url_scheme = "web-greeter"
+ self.url_scheme = QWebEngineUrlScheme(url_scheme.encode())
+ self.url_scheme.setDefaultPort(QWebEngineUrlScheme.SpecialPort.PortUnspecified)
+ self.url_scheme.setFlags(QWebEngineUrlScheme.Flag.SecureScheme or
+ QWebEngineUrlScheme.Flag.LocalScheme or
+ QWebEngineUrlScheme.Flag.LocalAccessAllowed)
+ QWebEngineUrlScheme.registerScheme(self.url_scheme)
+
+ self.profile = QWebEngineProfile.defaultProfile()
+ self.interceptor = QtUrlRequestInterceptor(url_scheme)
+ self.url_scheme_handler = QtUrlSchemeHandler()
+
+ self.view = QWebEngineView(parent=self.window)
+ self.page = WebPage()
+ self.view.setPage(self.page)
+
+ self.channel = QWebChannel(self.page)
+ self.bridge_initialized = False
+
+ self.profile.installUrlSchemeHandler(url_scheme.encode(), self.url_scheme_handler)
+
+ self._initialize_page()
+
+ if web_greeter_config["config"]["greeter"]["debug_mode"]:
+ self.devtools = DevTools()
+
+ if web_greeter_config["config"]["greeter"]["secure_mode"]:
+ self.profile.setUrlRequestInterceptor(self.interceptor)
+
+ self.page.setBackgroundColor(QColor(0, 0, 0))
+
+ self.view.show()
+ self.window.setCentralWidget(self.view)
+
+ logger.debug("Browser Window created")
+
+ self.show()
+
+ def load(self):
+ self.greeter = Greeter()
+ self.greeter_config = Config()
+ self.theme_utils = ThemeUtils(self.greeter)
+
+ self.bridge_objects = (self.greeter, self.greeter_config, self.theme_utils)
+ self.initialize_bridge_objects()
+ self.load_script(':/_greeter/js/bundle.js', 'Web Greeter Bundle')
+ self.load_theme()
+
+ def _initialize_page(self):
+ page_settings = self.page.settings().globalSettings()
+
+ if not web_greeter_config["config"]["greeter"]["secure_mode"]:
+ ENABLED_SETTINGS.append('LocalContentCanAccessRemoteUrls')
+ else:
+ DISABLED_SETTINGS.append('LocalContentCanAccessRemoteUrls')
+
+ for setting in DISABLED_SETTINGS:
+ try:
+ page_settings.setAttribute(getattr(QWebEngineSettings, setting), False)
+ except AttributeError:
+ pass
+
+ for setting in ENABLED_SETTINGS:
+ try:
+ page_settings.setAttribute(getattr(QWebEngineSettings, setting), True)
+ except AttributeError:
+ pass
+
+ self.page.setView(self.view)
+
+ def load_theme(self):
+ theme = web_greeter_config["config"]["greeter"]["theme"]
+ dir = "/usr/share/web-greeter/themes/"
+ path_to_theme = os.path.join(dir, theme, "index.html")
+ def_theme = "gruvbox"
+
+ if (theme.startswith("/")): path_to_theme = theme
+ elif (theme.__contains__(".") or theme.__contains__("/")):
+ path_to_theme = os.path.join(os.getcwd(), theme)
+
+ if (not path_to_theme.endswith(".html")):
+ path_to_theme = os.path.join(path_to_theme, "index.html")
+
+ if (not os.path.exists(path_to_theme)):
+ print("Path does not exists")
+ path_to_theme = os.path.join(dir, def_theme, "index.html")
+
+ url = QUrl("web-greeter://app/{0}".format(path_to_theme))
+ self.page.load(url)
+
+ logger.debug("Theme loaded")
+
+ @staticmethod
+ def _create_webengine_script(path: Url, name: str) -> QWebEngineScript:
+ script = QWebEngineScript()
+ script_file = QFile(path)
+
+ # print(script_file, path)
+
+ if script_file.open(QFile.ReadOnly):
+ script_string = str(script_file.readAll(), 'utf-8')
+
+ script.setInjectionPoint(QWebEngineScript.DocumentCreation)
+ script.setName(name)
+ script.setWorldId(QWebEngineScript.MainWorld)
+ script.setSourceCode(script_string)
+ # print(script_string)
+
+ return script
+
+ def _get_channel_api_script(self) -> QWebEngineScript:
+ return self._create_webengine_script(':/qtwebchannel/qwebchannel.js', 'QWebChannel API')
+
+ def _init_bridge_channel(self) -> None:
+ self.page.setWebChannel(self.channel)
+ self.page.scripts().insert(self._get_channel_api_script())
+ self.bridge_initialized = True
+
+ def initialize_bridge_objects(self) -> None:
+ if not self.bridge_initialized:
+ self._init_bridge_channel()
+ registered_objects = self.channel.registeredObjects()
+
+ for obj in self.bridge_objects:
+ if obj not in registered_objects:
+ self.channel.registerObject(obj._name, obj)
+ # print("Registered", obj._name)
+
+ def load_script(self, path: Url, name: str):
+ script = self._create_webengine_script(path, name)
+ self.page.scripts().insert(script)
+
diff --git a/web-greeter/browser/error_prompt.py b/web-greeter/browser/error_prompt.py
new file mode 100644
index 0000000..1a38cf4
--- /dev/null
+++ b/web-greeter/browser/error_prompt.py
@@ -0,0 +1,140 @@
+# -*- coding: utf-8 -*-
+#
+# error_prompt.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 .
+
+# Standard lib
+
+# 3rd-Party Libs
+from PyQt5.QtWebEngineWidgets import QWebEnginePage
+from PyQt5.QtWidgets import QDialogButtonBox, QDialog, QVBoxLayout, QLabel, QPushButton
+from config import web_greeter_config
+
+import globals
+from logging import (
+ getLogger,
+ DEBUG,
+ 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("javascript")
+logger.propagate = False
+stream_handler = StreamHandler()
+stream_handler.setLevel(DEBUG)
+stream_handler.setFormatter(formatter)
+logger.setLevel(DEBUG)
+logger.addHandler(stream_handler)
+
+class WebPage(QWebEnginePage):
+
+ def javaScriptConsoleMessage(self, level: QWebEnginePage.JavaScriptConsoleMessageLevel, message: str, lineNumber: int, sourceID: str):
+ if sourceID == "":
+ sourceID = "console"
+
+ logLevel = 0
+ if level == WebPage.JavaScriptConsoleMessageLevel.ErrorMessageLevel:
+ logLevel = 40
+ elif level == WebPage.JavaScriptConsoleMessageLevel.WarningMessageLevel:
+ logLevel = 30
+ elif level == WebPage.JavaScriptConsoleMessageLevel.InfoMessageLevel:
+ return
+ else:
+ return
+
+ 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)
+
+class ErrorDialog(QDialog):
+ def __init__(self, parent=None, err=""):
+ super().__init__(parent)
+
+ self.setWindowTitle("Error")
+
+ self.buttonBox = QDialogButtonBox()
+ cancelBtn = QPushButton("Cancel")
+ defaultBtn = QPushButton("Set default theme")
+ reloadBtn = QPushButton("Reload theme")
+
+ reloadBtn.clicked.connect(self.handle_reload)
+
+ self.buttonBox.addButton(defaultBtn, QDialogButtonBox.ButtonRole.AcceptRole)
+ self.buttonBox.addButton(reloadBtn, QDialogButtonBox.ButtonRole.ResetRole)
+ self.buttonBox.addButton(cancelBtn, QDialogButtonBox.ButtonRole.RejectRole)
+
+ self.buttonBox.accepted.connect(self.accept)
+ self.buttonBox.rejected.connect(self.reject)
+
+ self.layout = QVBoxLayout()
+ message = QLabel("An error ocurred. Do you want to change to default theme?")
+ err = QLabel(err)
+ self.layout.addWidget(message)
+ self.layout.addWidget(err)
+ self.layout.addWidget(self.buttonBox)
+ self.setLayout(self.layout)
+
+ def handle_reload(self, value: bool):
+ self.done(2)
+
+
+def errorPrompt(err):
+ if not web_greeter_config["config"]["greeter"]["detect_theme_errors"]:
+ return
+
+ dia = ErrorDialog(globals.greeter.window, err)
+
+ dia.exec()
+ result = dia.result()
+
+ if result == 0: # Cancel
+ return
+ elif result == 1: # Default theme
+ web_greeter_config["config"]["greeter"]["theme"] = "gruvbox"
+ globals.greeter.load_theme()
+ return
+ elif result == 2: # Reload
+ globals.greeter.load_theme()
+ return
+
+ return
diff --git a/web-greeter/browser/interceptor.py b/web-greeter/browser/interceptor.py
new file mode 100644
index 0000000..f5d7307
--- /dev/null
+++ b/web-greeter/browser/interceptor.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+#
+# interceptor.py
+#
+# Copyright © 2016-2017 Antergos
+#
+# 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 .
+
+# 3rd-Party Libs
+from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor, QWebEngineUrlRequestInfo
+
+class QtUrlRequestInterceptor(QWebEngineUrlRequestInterceptor):
+
+ def __init__(self, url_scheme: str):
+ super().__init__()
+ self._url_scheme = url_scheme
+
+ def intercept_request(self, info: QWebEngineUrlRequestInfo) -> None:
+ url = info.requestUrl().toString()
+ not_webg_uri = self._url_scheme != info.requestUrl().scheme()
+ not_data_uri = 'data' != info.requestUrl().scheme()
+ not_local_file = not info.requestUrl().isLocalFile()
+
+ # print(url)
+
+ not_devtools = (
+ not url.startswith('http://127.0.0.1') and not url.startswith('ws://127.0.0.1')
+ )
+
+ block_request = not_devtools and not_data_uri and not_webg_uri and not_local_file
+
+ info.block(block_request) # Block everything that is not allowed
+
+ def interceptRequest(self, info: QWebEngineUrlRequestInfo) -> None:
+ self.intercept_request(info)
+
diff --git a/web-greeter/browser/url_scheme.py b/web-greeter/browser/url_scheme.py
new file mode 100644
index 0000000..b3216f6
--- /dev/null
+++ b/web-greeter/browser/url_scheme.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+#
+# url_scheme.py
+#
+# Copyright © 2016-2018 Antergos
+# 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 .
+
+""" Custom Url Scheme Handler """
+
+# Standard Lib
+import os
+import mimetypes
+
+# 3rd-Party Libs
+from PyQt5.QtCore import QBuffer, QIODevice
+from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler, QWebEngineUrlRequestJob
+
+
+class QtUrlSchemeHandler(QWebEngineUrlSchemeHandler):
+
+ def requestStarted(self, job: QWebEngineUrlRequestJob) -> None:
+ path = job.requestUrl().path()
+ path = os.path.realpath(path)
+
+ # print("PATH", job.requestUrl().path())
+
+ if not path:
+ # print("JOB FAIL", path)
+ job.fail(QWebEngineUrlRequestJob.UrlInvalid)
+ return
+
+ if not os.path.exists(path):
+ # print("NOT FOUND", path)
+ job.fail(QWebEngineUrlRequestJob.UrlNotFound)
+ return
+
+ try:
+ with open(path, 'rb') as file:
+ content_type = mimetypes.guess_type(path)
+ if not content_type[0]:
+ content_type = ["text/plain", None]
+ buffer = QBuffer(parent=self)
+
+ buffer.open(QIODevice.WriteOnly)
+ buffer.write(file.read())
+ buffer.seek(0)
+ buffer.close()
+
+ job.reply(content_type[0].encode(), buffer)
+
+ except Exception as err:
+ raise err
+
diff --git a/web-greeter/config.py b/web-greeter/config.py
new file mode 100644
index 0000000..a40cfb1
--- /dev/null
+++ b/web-greeter/config.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+#
+# config.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 .
+# Standard lib
+
+import sys
+import os
+import ruamel.yaml as yaml
+
+import globals
+from logger import logger
+
+path_to_config = "/etc/lightdm/web-greeter.yml"
+
+global web_greeter_config
+web_greeter_config = {
+ "config": {
+ "branding": {
+ "background_images_dir": "/usr/share/backgrounds",
+ "logo_image": "",
+ "user_image": "",
+ },
+ "greeter": {
+ "debug_mode": False,
+ "detect_theme_errors": True,
+ "screensaver_timeout": 300,
+ "secure_mode": True,
+ "theme": "gruvbox",
+ "icon_theme": None,
+ "time_language": None,
+ },
+ "layouts": ["us", "latam"],
+ "features": {
+ "battery": False,
+ "backlight": {
+ "enabled": False,
+ "value": 10,
+ "steps": 0,
+ }
+ }
+ },
+ "app": {
+ "fullscreen": True,
+ "frame": False,
+ "debug_mode": False,
+ "theme_dir": "/usr/share/web-greeter/themes/"
+ }
+}
+
+def load_config():
+ try:
+ if (not os.path.exists(path_to_config)):
+ raise Exception("Config file not found")
+ file = open(path_to_config, "r")
+ web_greeter_config["config"] = yaml.safe_load(file)
+ except Exception as err:
+ logger.error("Config was not loaded:\n\t{0}".format(err))
+ pass
+
+load_config()
diff --git a/web-greeter/globals.py b/web-greeter/globals.py
index 3ed597c..4ce29d8 100644
--- a/web-greeter/globals.py
+++ b/web-greeter/globals.py
@@ -1,222 +1 @@
-# -*- coding: utf-8 -*-
-#
-# globals.py
-#
-# Copyright © 2017 Antergos
-#
-# 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 sys
-import pkg_resources
-import os
-from typing import (
- ClassVar,
- Type,
- List,
- Tuple,
-)
-
-# 3rd-Party Libs
-from whither.app import App
-from whither.base.config_loader import ConfigLoader
-from whither.bridge import BridgeObject
-
-# This Application
-import resources
-from bridge import (
- Config,
- Greeter,
- ThemeUtils,
-)
-from logging import (
- getLogger,
- DEBUG,
- ERROR,
- Formatter,
- StreamHandler,
-)
-
-from PyQt5.QtWidgets import QMainWindow
-from PyQt5.QtGui import QColor
-from PyQt5.QtCore import QResource
-import subprocess
-
-from utils import theme
-
-# 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)
-
-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:
- logger.error("Screensaver timeout couldn't be set")
- else:
- logger.debug("Screensaver timeout set")
-
-
-def resetScreenSaver():
- try:
- subprocess.run(["xset", "s", str(initial_timeout)])
- except Exception as err:
- logger.error("Screensaver reset failed")
- else:
- logger.debug("Screensaver reset")
-
-
-def getDefaultCursor():
- cursor_theme = ""
- try:
- child = subprocess.Popen(["cat", "/usr/share/icons/default/index.theme"],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
- awk = subprocess.run(
- ["awk", "-F=", "/Inherits/ {print $2}"], stdout=subprocess.PIPE, stdin=child.stdout, text=True)
- cursor_theme = awk.stdout.replace("\n", "")
- except Exception as err:
- logger.error("Default cursor couldn't be get")
- return cursor_theme
-
-
-def loadStyle(path):
- file = QResource(path)
- file = file.uncompressedData()
- file = str(file.data(), encoding='utf-8')
- return file
-
-
-BASE_DIR = os.path.dirname(os.path.realpath(__file__))
-CONFIG_FILE = os.path.join(BASE_DIR, 'whither.yml')
-
-
-class WebGreeter(App):
- greeter = None # type: ClassVar[BridgeObj] | None
- greeter_config = None # type: ClassVar[BridgeObj] | None
- theme_utils = None # type: ClassVar[BridgeObj] | None
-
- def __init__(self, *args, **kwargs) -> None:
- super().__init__('WebGreeter', *args, **kwargs)
- self.logger.debug('Web Greeter started.')
- self.greeter = Greeter(self.config)
- self.greeter_config = Config(self.config)
- self.theme_utils = ThemeUtils(self.greeter, self.config)
- self._web_container.bridge_objects = (self.greeter, self.greeter_config, self.theme_utils)
-
- style = loadStyle(":/_greeter/css/style.css")
- self._main_window.widget.setStyleSheet(style)
- 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()
-
- @classmethod
- def __pre_init__(cls):
- ConfigLoader.add_filter(cls.validate_greeter_config_data)
-
- def _before_main_window_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:
- return data
-
- if 'WebGreeter' == key:
- path = '../build/web-greeter/whither.yml'
- else:
- path = '../build/dist/web-greeter.yml'
-
- return open(path, 'r').read()
-
- def get_and_apply_user_config(self):
- self.logger.debug("Aplying config")
- config_file = os.path.join(self.config.config_dir, 'web-greeter.yml')
- branding_config = ConfigLoader('branding', config_file).config
- greeter_config = ConfigLoader('greeter', config_file).config
- features_config = ConfigLoader('features', config_file).config
- layouts_config = ConfigLoader('layouts', config_file).config
-
- greeter_config.update(custom_config["app"]["greeter"])
-
- self.config.branding.update(branding_config)
- self.config.greeter.update(greeter_config)
- self.config.features.update(features_config)
- self.config.layouts = layouts_config
-
- cursor_theme = greeter_config["icon_theme"]
- os.environ["XCURSOR_THEME"] = cursor_theme if cursor_theme != None else getDefaultCursor()
-
- self._config.debug_mode = greeter_config['debug_mode']
- self._config.allow_remote_urls = not greeter_config['secure_mode']
- self._config.context_menu.enabled = greeter_config['debug_mode']
- self._config.window.update(custom_config["whither"]["window"])
-
- def load_theme(self):
- self.logger.debug('Loading theme...')
- theme_url = theme.checkTheme(self)
- self._web_container.load(theme_url)
-
-
-global custom_config
-global greeter
-custom_config = {
- "whither": {
- "window": {}
- },
- "app": {
- "greeter": {}
- }
-}
+global greeter # type: Browser
diff --git a/web-greeter/logger.py b/web-greeter/logger.py
new file mode 100644
index 0000000..a409a3b
--- /dev/null
+++ b/web-greeter/logger.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+#
+# logger.py
+#
+# Copyright © 2017 Antergos
+# 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 .
+
+from logging import (
+ getLogger,
+ DEBUG,
+ Formatter,
+ StreamHandler
+)
+
+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()
+
+global logger
+logger = getLogger("debug")
+
+stream_handler.setLevel(DEBUG)
+stream_handler.setFormatter(formatter)
+logger.propagate = False
+logger.setLevel(DEBUG)
+logger.addHandler(stream_handler)
diff --git a/web-greeter/main.py b/web-greeter/main.py
deleted file mode 100644
index 064dd33..0000000
--- a/web-greeter/main.py
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/usr/bin/python3
-# -*- coding: utf-8 -*-
-#
-# main.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 .
-
-# Standard Lib
-import sys
-import ruamel.yaml as yaml
-import pkg_resources
-import os
-from typing import ( List )
-
-# 3rd-Party Libs
-
-# This Application
-from utils import errorPrompt, keyboard
-
-import globals
-from globals import WebGreeter, logger
-
-
-def loadWhitherConf():
- global whither_yaml
- global webGreeter_conf
- global file_test
- try:
- file_test = pkg_resources.resource_string("__main__", 'whither.yml').decode('utf-8')
- except Exception:
- file_test = pkg_resources.resource_string(__file__, 'whither.yml').decode('utf-8')
-
- whither_yaml = yaml.safe_load(file_test)
- webGreeter_conf = whither_yaml["WebGreeter"]
-
-
-def show_help():
- version = webGreeter_conf["app"]["version"]["full"]
- help_text = """Usage:
- web-greeter [OPTION...] - LightDM Web Greeter
-
- --debug Runs the greeter in debug mode
- --normal Runs in non-debug mode
-
- --list Lists available themes
- --theme Sets the theme to use
-
- -h, --help Show this help list
- -v, --version Print program version""".format(
- version = version
-)
- print(help_text)
-
-
-def show_version():
- version = webGreeter_conf["app"]["version"]["full"]
- print("{version}".format(version = version))
-
-def changeConfig(option: str, value):
- custom_config[option] = value
- return
-
-
-def debugMode(value: bool):
- window = dict(custom_config["whither"]["window"])
- greeter = dict(custom_config["app"]["greeter"])
- if value:
- greeter["debug_mode"] = True
- window["decorated"] = True
- window["stays_on_top"] = False
- window["initial_state"] = "normal"
- else:
- greeter["debug_mode"] = False
- window["decorated"] = False
- window["stays_on_top"] = True
- custom_config["whither"]["window"] = window
- custom_config["app"]["greeter"] = greeter
-
-
-def changeTheme(theme: str):
- custom_config["app"]["greeter"]["theme"] = theme
-
-
-def listThemes(quiet = False):
- themes_dir = webGreeter_conf["app"]["themes_dir"]
- themes_dir = themes_dir if os.path.exists(themes_dir) else "/usr/share/web-greeter/themes"
- filenames = os.listdir(themes_dir)
-
- dirlist = []
- for file in filenames:
- if os.path.isdir(os.path.join(themes_dir, file)):
- dirlist.append(file)
-
- if not quiet:
- print("Themes are located in {themes_dir}\n".format(themes_dir = themes_dir))
- for theme in dirlist:
- print("-", theme)
-
- return dirlist
-
-
-args_lenght = sys.argv.__len__()
-
-
-def yargs(args: List[str]):
- loadWhitherConf()
- used = 0
-
- if args[0] == "--help" or args[0] == "-h":
- show_help()
- used += 1
- exit()
- elif args[0] == "--version" or args[0] == "-v":
- show_version()
- used += 1
- exit()
- elif args[0] == "--debug":
- debugMode(True)
- used += 1
- elif args[0] == "--normal":
- debugMode(False)
- used += 1
- elif args[0] == "--theme":
- if args.__len__() > 1:
- changeTheme(args[1])
- used += 2
- else:
- print("No theme provided")
- used += 1
- exit(1)
- elif args[0] == "--list":
- listThemes()
- used += 1
- exit()
- else:
- show_help()
- used += 1
- exit(1)
- for x in range(used):
- args.pop(0)
- if args.__len__() != 0:
- yargs(args)
-
-
-if __name__ == '__main__':
- custom_config = globals.custom_config
-
- if args_lenght > 1:
- args = sys.argv
- args.pop(0)
- yargs(args)
-
- globals.greeter = WebGreeter()
-
- globals.greeter.run()
diff --git a/web-greeter/requirements.txt b/web-greeter/requirements.txt
new file mode 100644
index 0000000..e69de29
diff --git a/web-greeter/whither.yml b/web-greeter/whither.yml
deleted file mode 100644
index 7cd2937..0000000
--- a/web-greeter/whither.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-# Whither (Universal Linux Apps) Configuration
-
-# App Name
-WebGreeter:
- # Whither's Config
- whither:
- allow_remote_urls: False
- at_spi_service:
- enabled: '@at_spi_service@'
- command: /usr/lib/at-spi2-core/at-spi-bus-launcher
- arg: --launch-immediately
- app_id: web-greeter
- url_scheme: web-greeter
- context_menu:
- enabled: False
- debug_mode: '@debug_mode@'
- entry_point:
- autoload: False
- toolbar:
- enabled: False
- toolkit: auto
- window:
- decorated: '@decorated@'
- initial_state: maximized
- stays_on_top: '@stays_on_top@'
- title: Web Greeter for LightDM
-
- # App's Config
- app:
- branding:
- background_images_dir: '@background_images_dir@'
- logo_image: '@logo_image@'
- user_image: '@user_image@'
- config_dir: '@config_dir@'
- greeter:
- debug_mode: '@debug_mode@'
- detect_theme_errors: True
- screensaver_timeout: 300
- secure_mode: True
- theme: gruvbox
- icon_theme:
- time_language:
- layouts:
- - us
- - latam
- features:
- battery: False
- backlight:
- enabled: False
- value: 10
- steps: 0
- greeters_dir: '@greeters_dir@'
- locale_dir: '@locale_dir@'
- themes_dir: '@themes_dir@'
- version:
- full: '3.0.0'
- major: 3
- minor: 0
- micro: 0
- alpha: False
- beta: False
- rc: False