Browse Source

Removed whither package, partially.

sisyphus
JezerM 3 years ago
parent
commit
7c154980ac
No known key found for this signature in database
GPG Key ID: 66BBC5D01388C6B5
  1. 1
      build/utils.sh
  2. 42
      web-greeter/__main__.py
  3. 30
      web-greeter/bridge/Config.py
  4. 147
      web-greeter/bridge/Greeter.py
  5. 19
      web-greeter/bridge/ThemeUtils.py
  6. 46
      web-greeter/bridge/devtools.py
  7. 0
      web-greeter/browser/__init__.py
  8. 46
      web-greeter/browser/bridge.py
  9. 276
      web-greeter/browser/browser.py
  10. 140
      web-greeter/browser/error_prompt.py
  11. 55
      web-greeter/browser/interceptor.py
  12. 74
      web-greeter/browser/url_scheme.py
  13. 83
      web-greeter/config.py
  14. 223
      web-greeter/globals.py
  15. 50
      web-greeter/logger.py
  16. 176
      web-greeter/main.py
  17. 0
      web-greeter/requirements.txt
  18. 62
      web-greeter/whither.yml

1
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} \

42
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 <http://www.gnu.org/licenses/>.
# 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()

30
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 <http://www.gnu.org/licenses/>.
# 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

147
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()

19
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 []

46
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 <http://www.gnu.org/licenses/>.
# 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()

0
web-greeter/browser/__init__.py

46
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 <http://www.gnu.org/licenses/>.
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

276
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 <http://www.gnu.org/licenses/>.
# 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)

140
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 <http://www.gnu.org/licenses/>.
# 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

55
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 <http://www.gnu.org/licenses/>.
# 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)

74
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 <http://www.gnu.org/licenses/>.
""" 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

83
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 <http://www.gnu.org/licenses/>.
# 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()

223
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 <http://www.gnu.org/licenses/>.
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

50
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 <http://www.gnu.org/licenses/>.
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)

176
web-greeter/main.py

@ -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 <http://www.gnu.org/licenses/>.
# 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()

0
web-greeter/requirements.txt

62
web-greeter/whither.yml

@ -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
Loading…
Cancel
Save