mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-31 14:33:54 -04:00
Windows: Automatically change colors between light and dark when the system wide preference is changed
This commit is contained in:
parent
1ec0085eff
commit
f695e49bd6
@ -49,8 +49,7 @@ Environment variables
|
|||||||
the system theme -- beware of crashes and hangs.
|
the system theme -- beware of crashes and hangs.
|
||||||
* ``CALIBRE_SHOW_DEPRECATION_WARNINGS`` - causes calibre to print deprecation warnings to stdout. Useful for calibre developers.
|
* ``CALIBRE_SHOW_DEPRECATION_WARNINGS`` - causes calibre to print deprecation warnings to stdout. Useful for calibre developers.
|
||||||
* ``CALIBRE_NO_DEFAULT_PROGRAMS`` - prevent calibre from automatically registering the filetypes it is capable of handling with Windows.
|
* ``CALIBRE_NO_DEFAULT_PROGRAMS`` - prevent calibre from automatically registering the filetypes it is capable of handling with Windows.
|
||||||
* ``CALIBRE_USE_DARK_PALETTE`` - set it to ``1`` to have calibre use dark colors and ``0`` for normal colors (ignored on macOS).
|
* ``CALIBRE_USE_DARK_PALETTE`` - set it to ``1`` to have calibre use dark colors. Works on **Linux only**.
|
||||||
On Windows 10 in the absence of this variable, the Windows system preference for dark colors is used.
|
|
||||||
* ``SYSFS_PATH`` - Use if sysfs is mounted somewhere other than /sys
|
* ``SYSFS_PATH`` - Use if sysfs is mounted somewhere other than /sys
|
||||||
* ``http_proxy``, ``https_proxy`` - used on Linux to specify an HTTP(S) proxy
|
* ``http_proxy``, ``https_proxy`` - used on Linux to specify an HTTP(S) proxy
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ from calibre.ebooks.metadata import MetaInformation
|
|||||||
from calibre.gui2.linux_file_dialogs import (
|
from calibre.gui2.linux_file_dialogs import (
|
||||||
check_for_linux_native_dialogs, linux_native_dialog
|
check_for_linux_native_dialogs, linux_native_dialog
|
||||||
)
|
)
|
||||||
|
from calibre.gui2.palette import dark_palette, fix_palette_colors
|
||||||
from calibre.gui2.qt_file_dialogs import FileDialog
|
from calibre.gui2.qt_file_dialogs import FileDialog
|
||||||
from calibre.ptempfile import base_dir
|
from calibre.ptempfile import base_dir
|
||||||
from calibre.utils.config_base import tweaks
|
from calibre.utils.config_base import tweaks
|
||||||
@ -1076,6 +1077,11 @@ class Application(QApplication):
|
|||||||
QApplication.setDesktopFileName(override_program_name)
|
QApplication.setDesktopFileName(override_program_name)
|
||||||
QApplication.setAttribute(Qt.ApplicationAttribute.AA_ShareOpenGLContexts, True) # needed for webengine
|
QApplication.setAttribute(Qt.ApplicationAttribute.AA_ShareOpenGLContexts, True) # needed for webengine
|
||||||
QApplication.__init__(self, qargs)
|
QApplication.__init__(self, qargs)
|
||||||
|
self.original_palette = self.palette()
|
||||||
|
self.original_palette_modified = fix_palette_colors(self.original_palette)
|
||||||
|
if iswindows:
|
||||||
|
self.win_event_filter = WinEventFilter()
|
||||||
|
self.installNativeEventFilter(self.win_event_filter)
|
||||||
icon_resource_manager.initialize()
|
icon_resource_manager.initialize()
|
||||||
sh = self.styleHints()
|
sh = self.styleHints()
|
||||||
if hasattr(sh, 'setShowShortcutsInContextMenus'):
|
if hasattr(sh, 'setShowShortcutsInContextMenus'):
|
||||||
@ -1146,14 +1152,6 @@ class Application(QApplication):
|
|||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
|
||||||
if iswindows:
|
if iswindows:
|
||||||
# On windows the highlighted colors for inactive widgets are the
|
|
||||||
# same as non highlighted colors. This is a regression from Qt 4.
|
|
||||||
# https://bugreports.qt-project.org/browse/QTBUG-41060
|
|
||||||
p = self.palette()
|
|
||||||
for role in (QPalette.ColorRole.Highlight, QPalette.ColorRole.HighlightedText, QPalette.ColorRole.Base, QPalette.ColorRole.AlternateBase):
|
|
||||||
p.setColor(QPalette.ColorGroup.Inactive, role, p.color(QPalette.ColorGroup.Active, role))
|
|
||||||
self.setPalette(p)
|
|
||||||
|
|
||||||
# Prevent text copied to the clipboard from being lost on quit due to
|
# Prevent text copied to the clipboard from being lost on quit due to
|
||||||
# Qt 5 bug: https://bugreports.qt-project.org/browse/QTBUG-41125
|
# Qt 5 bug: https://bugreports.qt-project.org/browse/QTBUG-41125
|
||||||
self.aboutToQuit.connect(self.flush_clipboard)
|
self.aboutToQuit.connect(self.flush_clipboard)
|
||||||
@ -1221,7 +1219,6 @@ class Application(QApplication):
|
|||||||
load_builtin_fonts()
|
load_builtin_fonts()
|
||||||
|
|
||||||
def set_dark_mode_palette(self):
|
def set_dark_mode_palette(self):
|
||||||
from calibre.gui2.palette import dark_palette
|
|
||||||
self.set_palette(dark_palette())
|
self.set_palette(dark_palette())
|
||||||
|
|
||||||
def setup_styles(self, force_calibre_style):
|
def setup_styles(self, force_calibre_style):
|
||||||
@ -1232,15 +1229,16 @@ class Application(QApplication):
|
|||||||
if force_calibre_style:
|
if force_calibre_style:
|
||||||
using_calibre_style = True
|
using_calibre_style = True
|
||||||
if using_calibre_style:
|
if using_calibre_style:
|
||||||
use_dark_palette = False
|
if iswindows:
|
||||||
if 'CALIBRE_USE_DARK_PALETTE' in os.environ:
|
use_dark_palette = windows_is_system_dark_mode_enabled()
|
||||||
if not ismacos:
|
elif ismacos:
|
||||||
use_dark_palette = os.environ['CALIBRE_USE_DARK_PALETTE'] != '0'
|
use_dark_palette = False
|
||||||
else:
|
else:
|
||||||
if iswindows:
|
use_dark_palette = os.environ.get('CALIBRE_USE_DARK_PALETTE') == '1'
|
||||||
use_dark_palette = windows_is_system_dark_mode_enabled()
|
|
||||||
if use_dark_palette:
|
if use_dark_palette:
|
||||||
self.set_dark_mode_palette()
|
self.set_dark_mode_palette()
|
||||||
|
elif self.original_palette_modified:
|
||||||
|
self.set_palette(self.original_palette)
|
||||||
|
|
||||||
self.using_calibre_style = using_calibre_style
|
self.using_calibre_style = using_calibre_style
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
@ -1249,6 +1247,15 @@ class Application(QApplication):
|
|||||||
self.load_calibre_style()
|
self.load_calibre_style()
|
||||||
self.on_palette_change()
|
self.on_palette_change()
|
||||||
|
|
||||||
|
def check_for_windows_palette_change(self):
|
||||||
|
use_dark_palette = bool(windows_is_system_dark_mode_enabled())
|
||||||
|
if bool(self.is_dark_theme) != use_dark_palette:
|
||||||
|
if use_dark_palette:
|
||||||
|
self.set_dark_mode_palette()
|
||||||
|
else:
|
||||||
|
self.set_palette(self.original_palette)
|
||||||
|
self.on_palette_change()
|
||||||
|
|
||||||
def set_palette(self, pal):
|
def set_palette(self, pal):
|
||||||
self.ignore_palette_changes = True
|
self.ignore_palette_changes = True
|
||||||
self.setPalette(pal)
|
self.setPalette(pal)
|
||||||
@ -1633,6 +1640,24 @@ def add_to_recent_docs(path):
|
|||||||
winutil.add_to_recent_docs(str(path), app.windows_app_uid)
|
winutil.add_to_recent_docs(str(path), app.windows_app_uid)
|
||||||
|
|
||||||
|
|
||||||
|
if iswindows:
|
||||||
|
import ctypes
|
||||||
|
from qt.core import QAbstractNativeEventFilter
|
||||||
|
|
||||||
|
class WinEventFilter(QAbstractNativeEventFilter):
|
||||||
|
|
||||||
|
def nativeEventFilter(self, eventType, message):
|
||||||
|
if eventType == b"windows_generic_MSG":
|
||||||
|
msg = ctypes.wintypes.MSG.from_address(message.__int__())
|
||||||
|
# https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-settingchange
|
||||||
|
if msg.message == 0x001A: # WM_SETTINGCHANGE
|
||||||
|
if ctypes.wstring_at(msg.lParam) == 'ImmersiveColorSet':
|
||||||
|
QApplication.instance().check_for_windows_palette_change()
|
||||||
|
# prevent Qt from handling this event
|
||||||
|
return True, 0
|
||||||
|
return False, 0
|
||||||
|
|
||||||
|
|
||||||
def windows_is_system_dark_mode_enabled():
|
def windows_is_system_dark_mode_enabled():
|
||||||
s = QSettings(r"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", QSettings.Format.NativeFormat)
|
s = QSettings(r"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", QSettings.Format.NativeFormat)
|
||||||
if s.status() == QSettings.Status.NoError:
|
if s.status() == QSettings.Status.NoError:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# License: GPL v3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
from qt.core import QColor, QPalette, Qt
|
from qt.core import QColor, QPalette, Qt
|
||||||
from calibre.constants import dark_link_color
|
from calibre.constants import dark_link_color, iswindows
|
||||||
|
|
||||||
|
|
||||||
dark_link_color = QColor(dark_link_color)
|
dark_link_color = QColor(dark_link_color)
|
||||||
@ -10,6 +10,17 @@ dark_color = QColor(45,45,45)
|
|||||||
dark_text_color = QColor('#ddd')
|
dark_text_color = QColor('#ddd')
|
||||||
|
|
||||||
|
|
||||||
|
def fix_palette_colors(p):
|
||||||
|
if iswindows:
|
||||||
|
# On Windows the highlighted colors for inactive widgets are the
|
||||||
|
# same as non highlighted colors. This is a regression from Qt 4.
|
||||||
|
# https://bugreports.qt-project.org/browse/QTBUG-41060
|
||||||
|
for role in (QPalette.ColorRole.Highlight, QPalette.ColorRole.HighlightedText, QPalette.ColorRole.Base, QPalette.ColorRole.AlternateBase):
|
||||||
|
p.setColor(QPalette.ColorGroup.Inactive, role, p.color(QPalette.ColorGroup.Active, role))
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def dark_palette():
|
def dark_palette():
|
||||||
p = QPalette()
|
p = QPalette()
|
||||||
disabled_color = QColor(127,127,127)
|
disabled_color = QColor(127,127,127)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user