diff --git a/controller/Changelog.md b/controller/Changelog.md index f07b9fbd..0816552f 100644 --- a/controller/Changelog.md +++ b/controller/Changelog.md @@ -11,6 +11,7 @@ - os: Set noexec for volatile root and persistent storage mounts - os: Restrict remote maintenance to the ZeroTier network - os: Limit permitted SSH modes and forwarding options +- kiosk: Migrate to Qt6 ## Removed diff --git a/kiosk/default.nix b/kiosk/default.nix index 837d0956..861c9e9e 100644 --- a/kiosk/default.nix +++ b/kiosk/default.nix @@ -15,32 +15,37 @@ python3Packages.buildPythonApplication rec { --replace "@system_version@" "${system_version}" ''; - doCheck = false; - - nativeBuildInputs = [ qt5.wrapQtAppsHook mypy ]; - propagatedBuildInputs = with python3Packages; [ dbus-python pygobject3 - pyqtwebengine + pyqt6 + pyqt6-webengine pytest + qt6.full + qt6.qtbase + qt6.qtwebengine requests types-requests ]; + nativeBuildInputs = [ + bashInteractive + makeWrapper + mypy + qt6.wrapQtAppsHook + ]; + postInstall = '' cp -r images/ $out/images ''; - dontWrapQtApps = true; - makeWrapperArgs = [ "\${qtWrapperArgs[@]}" ]; - shellHook = '' # Give access to kiosk_browser module export PYTHONPATH=./:$PYTHONPATH - # Give access to Qt platform plugin "xcb" in nix-shell - export QT_QPA_PLATFORM_PLUGIN_PATH="${qt5.qtbase.bin}/lib/qt-${qt5.qtbase.version}/plugins"; + export QT_QPA_PLATFORM=wayland + bashdir=$(mktemp -d) + makeWrapper "$(type -p bash)" "$bashdir/bash" "''${qtWrapperArgs[@]}" + exec "$bashdir/bash" ''; - } diff --git a/kiosk/kiosk_browser/__init__.py b/kiosk/kiosk_browser/__init__.py index 2a9a0fa8..51389cad 100644 --- a/kiosk/kiosk_browser/__init__.py +++ b/kiosk/kiosk_browser/__init__.py @@ -1,8 +1,8 @@ import sys import logging -from PyQt5.QtCore import Qt, QUrl -from PyQt5.QtGui import QKeySequence -from PyQt5.QtWidgets import QApplication +from PyQt6.QtCore import Qt, QUrl +from PyQt6.QtGui import QKeySequence +from PyQt6.QtWidgets import QApplication from kiosk_browser import main_widget @@ -18,12 +18,12 @@ def start(kiosk_url, settings_url, toggle_settings_key, fullscreen = True): toggle_settings_key = QKeySequence(toggle_settings_key) ) - mainWidget.setContextMenuPolicy(Qt.NoContextMenu) + mainWidget.setContextMenuPolicy(Qt.ContextMenuPolicy.NoContextMenu) if fullscreen: set_fullscreen(app, mainWidget) - app.exec_() + app.exec() def parseUrl(url): parsed_url = QUrl(url) diff --git a/kiosk/kiosk_browser/browser_widget.py b/kiosk/kiosk_browser/browser_widget.py index de06dae8..57a6e72c 100644 --- a/kiosk/kiosk_browser/browser_widget.py +++ b/kiosk/kiosk_browser/browser_widget.py @@ -1,4 +1,4 @@ -from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, QtGui, QtSvg +from PyQt6 import QtCore, QtWidgets, QtWebEngineWidgets, QtWebEngineCore, QtGui, QtSvgWidgets from enum import Enum, auto import logging import re @@ -52,7 +52,7 @@ def __init__(self, url, get_current_proxy, parent): )) # Allow sound playback without user gesture - self._webview.page().settings().setAttribute(QtWebEngineWidgets.QWebEngineSettings.PlaybackRequiresUserGesture, False) + self._webview.page().settings().setAttribute(QtWebEngineCore.QWebEngineSettings.WebAttribute.PlaybackRequiresUserGesture, False) # Load url self._webview.setUrl(url) @@ -60,10 +60,10 @@ def __init__(self, url, get_current_proxy, parent): self._webview.loadFinished.connect(self._load_finished) # Shortcut to manually reload - self._reload_shortcut = QtWidgets.QShortcut('CTRL+R', self) + self._reload_shortcut = QtGui.QShortcut('CTRL+R', self) self._reload_shortcut.activated.connect(self.reload) # Shortcut to perform a hard refresh - self._hard_refresh_shortcut = QtWidgets.QShortcut('CTRL+SHIFT+R', self) + self._hard_refresh_shortcut = QtGui.QShortcut('CTRL+SHIFT+R', self) self._hard_refresh_shortcut.activated.connect(self._hard_refresh) # Prepare reload timer @@ -181,8 +181,8 @@ def network_error_page(parent): paragraph_1 = paragraph("Please ensure the Internet connection to this device is active.", parent) paragraph_2 = paragraph("If the problem persists, contact Senso Service.", parent) - logo = QtSvg.QSvgWidget("images/dividat-logo.svg", parent) - logo.renderer().setAspectRatioMode(QtCore.Qt.KeepAspectRatio) + logo = QtSvgWidgets.QSvgWidget("images/dividat-logo.svg", parent) + logo.renderer().setAspectRatioMode(QtCore.Qt.AspectRatioMode.KeepAspectRatio) logo.setFixedHeight(30) layout = QtWidgets.QVBoxLayout() diff --git a/kiosk/kiosk_browser/captive_portal.py b/kiosk/kiosk_browser/captive_portal.py index 5f78fcc0..8e2eec7a 100644 --- a/kiosk/kiosk_browser/captive_portal.py +++ b/kiosk/kiosk_browser/captive_portal.py @@ -10,7 +10,7 @@ import logging from enum import Enum, auto from http import HTTPStatus -from PyQt5 import QtWidgets +from PyQt6 import QtWidgets from typing import Callable check_connection_url = 'http://captive.dividat.com/' diff --git a/kiosk/kiosk_browser/dialogable_widget.py b/kiosk/kiosk_browser/dialogable_widget.py index 227b907b..14e6200d 100644 --- a/kiosk/kiosk_browser/dialogable_widget.py +++ b/kiosk/kiosk_browser/dialogable_widget.py @@ -1,4 +1,4 @@ -from PyQt5 import QtWidgets, QtCore, QtGui +from PyQt6 import QtWidgets, QtCore, QtGui from typing import Callable overlay_color: str = '#888888' @@ -30,8 +30,8 @@ def __init__( policy = QtWidgets.QSizePolicy() policy.setVerticalStretch(1) policy.setHorizontalStretch(1) - policy.setVerticalPolicy(QtWidgets.QSizePolicy.Preferred) - policy.setHorizontalPolicy(QtWidgets.QSizePolicy.Preferred) + policy.setVerticalPolicy(QtWidgets.QSizePolicy.Policy.Preferred) + policy.setHorizontalPolicy(QtWidgets.QSizePolicy.Policy.Preferred) self.setSizePolicy(policy) # Layout @@ -41,7 +41,7 @@ def __init__( self.setLayout(self._layout) # Shortcuts - QtWidgets.QShortcut('ESC', self).activated.connect(self._on_escape) + QtGui.QShortcut('ESC', self).activated.connect(self._on_escape) def inner_widget(self): return self._inner_widget @@ -118,7 +118,7 @@ def title_line( """) button = QtWidgets.QPushButton("❌", dialog) - button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + button.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.PointingHandCursor)) button.setStyleSheet(""" QPushButton { background-color: rgba(255, 255, 255, 0.2); diff --git a/kiosk/kiosk_browser/main_widget.py b/kiosk/kiosk_browser/main_widget.py index c3bb8f75..686edb6d 100644 --- a/kiosk/kiosk_browser/main_widget.py +++ b/kiosk/kiosk_browser/main_widget.py @@ -1,4 +1,4 @@ -from PyQt5 import QtWidgets, QtCore +from PyQt6 import QtWidgets, QtCore, QtGui from kiosk_browser import browser_widget, captive_portal, dialogable_widget, proxy as proxy_module @@ -23,8 +23,8 @@ def __init__(self, kiosk_url: str, settings_url: str, toggle_settings_key: str): self._dialogable_browser = dialogable_widget.DialogableWidget( parent = self, inner_widget = browser_widget.BrowserWidget( - url = kiosk_url, - get_current_proxy = proxy.get_current, + url = kiosk_url, + get_current_proxy = proxy.get_current, parent = self), on_close = self._close_dialog) @@ -44,7 +44,7 @@ def __init__(self, kiosk_url: str, settings_url: str, toggle_settings_key: str): self.setLayout(self._layout) # Shortcuts - QtWidgets.QShortcut(toggle_settings_key, self).activated.connect(self._toggle_settings) + QtGui.QShortcut(toggle_settings_key, self).activated.connect(self._toggle_settings) # Private diff --git a/kiosk/kiosk_browser/proxy.py b/kiosk/kiosk_browser/proxy.py index d5c26900..5c5c3dd6 100644 --- a/kiosk/kiosk_browser/proxy.py +++ b/kiosk/kiosk_browser/proxy.py @@ -6,7 +6,7 @@ import logging import threading import urllib -from PyQt5.QtNetwork import QNetworkProxy +from PyQt6.QtNetwork import QNetworkProxy from dataclasses import dataclass from dbus.mainloop.glib import DBusGMainLoop from gi.repository import GLib diff --git a/kiosk/mypy.ini b/kiosk/mypy.ini index f7e489a3..ff82608e 100644 --- a/kiosk/mypy.ini +++ b/kiosk/mypy.ini @@ -1,18 +1,18 @@ [mypy] -[mypy-PyQt5] +[mypy-PyQt6] ignore_missing_imports = True -[mypy-PyQt5.QtNetwork] +[mypy-PyQt6.QtNetwork] ignore_missing_imports = True -[mypy-PyQt5.QtCore] +[mypy-PyQt6.QtCore] ignore_missing_imports = True -[mypy-PyQt5.QtGui] +[mypy-PyQt6.QtGui] ignore_missing_imports = True -[mypy-PyQt5.QtWidgets] +[mypy-PyQt6.QtWidgets] ignore_missing_imports = True [mypy-dbus]