Detect OS color mode and set as property for stylesheets

Sets the detected OS color mode (dark/light) as a property on the
QApplication so it can be referenced in stylesheets to select style
rules suited to the OS color mode.
This commit is contained in:
Garrett Robinson 2023-09-28 16:21:13 +03:00 committed by Alex Pyrgiotis
parent 23bee23d81
commit 46f978e6f0
No known key found for this signature in database
GPG key ID: B6C15EBA0357C9AA
3 changed files with 38 additions and 1 deletions

View file

@ -1,3 +1,4 @@
import enum
import functools
import logging
import os
@ -33,6 +34,18 @@ from .updater import UpdaterThread
log = logging.getLogger(__name__)
class OSColorMode(enum.Enum):
"""
Operating system color mode, e.g. Light or Dark Mode on macOS 10.14+ or Windows 10+.
The enum values are used as the names of Qt properties that will be selected by QSS
property selectors to set color-mode-specific style rules.
"""
LIGHT = "light"
DARK = "dark"
class Application(QtWidgets.QApplication):
document_selected = QtCore.Signal(list)
application_activated = QtCore.Signal()
@ -61,6 +74,23 @@ class Application(QtWidgets.QApplication):
self.event = monkeypatch_event # type: ignore [method-assign]
self.os_color_mode = self.infer_os_color_mode()
log.debug(f"Inferred system color scheme as {self.os_color_mode}")
def infer_os_color_mode(self) -> OSColorMode:
"""
Qt 6.5+ explicitly provides the OS color scheme via QStyleHints.colorScheme(),
but we still need to support PySide2/Qt 5, so instead we infer the OS color
scheme from the default palette.
"""
text_color, window_color = (
self.palette().color(role)
for role in (QtGui.QPalette.WindowText, QtGui.QPalette.Window)
)
if text_color.lightness() > window_color.lightness():
return OSColorMode.DARK
return OSColorMode.LIGHT
@click.command()
@click.option(

View file

@ -12,6 +12,8 @@ from colorama import Fore
# FIXME: See https://github.com/freedomofpress/dangerzone/issues/320 for more details.
if typing.TYPE_CHECKING:
from PySide2 import QtCore, QtGui, QtWidgets
from . import Application
else:
try:
from PySide6 import QtCore, QtGui, QtWidgets
@ -35,7 +37,7 @@ class DangerzoneGui(DangerzoneCore):
"""
def __init__(
self, app: QtWidgets.QApplication, isolation_provider: IsolationProvider
self, app: "Application", isolation_provider: IsolationProvider
) -> None:
super().__init__(isolation_provider)

View file

@ -162,6 +162,11 @@ class MainWindow(QtWidgets.QMainWindow):
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
# Set the OS color mode as a property on the MainWindow, which is the closest
# thing we have to a top-level container element akin to an HTML `<body>`.
# This allows us to make QSS rules conditional on the OS color mode.
self.setProperty("OSColorMode", self.dangerzone.app.os_color_mode.value)
self.show()
def load_svg_image(self, filename: str) -> QtGui.QPixmap: