mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-01 19:17:02 -04:00 
			
		
		
		
	Linux: Use the system dark mode setting
This comes from the desktop settings portal implemented in KDE 5.24 and GNOME 42
This commit is contained in:
		
							parent
							
								
									8bf10b1056
								
							
						
					
					
						commit
						bc97485ff2
					
				| @ -49,7 +49,7 @@ Environment variables | ||||
|       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_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. Works on **Linux only**. | ||||
|     * ``CALIBRE_USE_DARK_PALETTE`` - set it to ``1`` to have calibre use dark colors and ``0`` for light colors. Works on **Linux only**. | ||||
|     * ``SYSFS_PATH`` - Use if sysfs is mounted somewhere other than /sys | ||||
|     * ``http_proxy``, ``https_proxy`` - used on Linux to specify an HTTP(S) proxy | ||||
| 
 | ||||
|  | ||||
| @ -16,7 +16,7 @@ from qt.core import ( | ||||
|     QFileIconProvider, QFileInfo, QFont, QFontDatabase, QFontInfo, QFontMetrics, | ||||
|     QGuiApplication, QIcon, QIODevice, QLocale, QNetworkProxyFactory, QObject, | ||||
|     QPalette, QResource, QSettings, QSocketNotifier, QStringListModel, QStyle, Qt, | ||||
|     QThread, QTimer, QTranslator, QUrl, pyqtSignal | ||||
|     QThread, QTimer, QTranslator, QUrl, pyqtSignal, pyqtSlot | ||||
| ) | ||||
| from threading import Lock, RLock | ||||
| 
 | ||||
| @ -47,6 +47,8 @@ try: | ||||
|     NO_URL_FORMATTING = QUrl.UrlFormattingOption.None_ | ||||
| except AttributeError: | ||||
|     NO_URL_FORMATTING = getattr(QUrl, 'None') | ||||
| if islinux: | ||||
|     from qt.dbus import QDBusConnection, QDBusMessage, QDBusVariant | ||||
| 
 | ||||
| 
 | ||||
| class IconResourceManager: | ||||
| @ -1234,7 +1236,14 @@ class Application(QApplication): | ||||
|             elif ismacos: | ||||
|                 use_dark_palette = False | ||||
|             else: | ||||
|                 use_dark_palette = os.environ.get('CALIBRE_USE_DARK_PALETTE') == '1' | ||||
|                 if 'CALIBRE_USE_DARK_PALETTE' in os.environ: | ||||
|                     use_dark_palette = os.environ.get('CALIBRE_USE_DARK_PALETTE') == '1' | ||||
|                 else: | ||||
|                     use_dark_palette = linux_is_system_dark_mode_enabled() | ||||
|                     bus = QDBusConnection.sessionBus() | ||||
|                     bus.connect( | ||||
|                         'org.freedesktop.portal.Desktop', '/org/freedesktop/portal/desktop', | ||||
|                         'org.freedesktop.portal.Settings', 'SettingChanged', 'ssv', self.linux_desktop_setting_changed) | ||||
|             if use_dark_palette: | ||||
|                 self.set_dark_mode_palette() | ||||
|             elif self.original_palette_modified: | ||||
| @ -1247,6 +1256,18 @@ class Application(QApplication): | ||||
|             self.load_calibre_style() | ||||
|         self.on_palette_change() | ||||
| 
 | ||||
|     if islinux: | ||||
|         @pyqtSlot(str, str, QDBusVariant) | ||||
|         def linux_desktop_setting_changed(self, namespace, key, val): | ||||
|             if (namespace, key) == ('org.freedesktop.appearance', 'color-scheme'): | ||||
|                 use_dark_palette = val.variant() == 1 | ||||
|                 if use_dark_palette != bool(self.is_dark_theme): | ||||
|                     if use_dark_palette: | ||||
|                         self.set_dark_mode_palette() | ||||
|                     else: | ||||
|                         self.set_palette(self.original_palette) | ||||
|                 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: | ||||
| @ -1670,6 +1691,18 @@ def windows_is_system_dark_mode_enabled(): | ||||
|     return False | ||||
| 
 | ||||
| 
 | ||||
| def linux_is_system_dark_mode_enabled(): | ||||
|     bus = QDBusConnection.sessionBus() | ||||
|     m = QDBusMessage.createMethodCall( | ||||
|         'org.freedesktop.portal.Desktop', '/org/freedesktop/portal/desktop', | ||||
|         'org.freedesktop.portal.Settings', 'Read' | ||||
|     ) | ||||
|     m.setArguments(['org.freedesktop.appearance', 'color-scheme']) | ||||
|     reply = bus.call(m, timeout=1000) | ||||
|     a = reply.arguments() | ||||
|     return len(a) and isinstance(a[0], int) and a[0] == 1 | ||||
| 
 | ||||
| 
 | ||||
| def make_view_use_window_background(view): | ||||
|     p = view.palette() | ||||
|     p.setColor(QPalette.ColorRole.Base, p.color(QPalette.ColorRole.Window)) | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| # autogenerated by __main__.py do not edit | ||||
| top_level_module_names=('QtCore', 'QtGui', 'QtWidgets', 'QtNetwork', 'QtSvg', 'QtPrintSupport', 'QtWebEngineCore', 'QtWebEngineWidgets') | ||||
| top_level_module_names=('QtCore', 'QtGui', 'QtWidgets', 'QtNetwork', 'QtSvg', 'QtPrintSupport', 'QtWebEngineCore', 'QtWebEngineWidgets', 'QtDBus') | ||||
| 
 | ||||
| 
 | ||||
| def __getattr__(name): | ||||
|  | ||||
| @ -22,6 +22,9 @@ module_lists = { | ||||
|         'QtWebEngineCore', | ||||
|         'QtWebEngineWidgets', | ||||
|     ), | ||||
|     'dbus': ( | ||||
|         'QtDBus', | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -54,7 +57,7 @@ def scan(name): | ||||
| 
 | ||||
| 
 | ||||
| top_level_module_names = () | ||||
| for name in ('core', 'webengine'): | ||||
| for name in ('core', 'webengine', 'dbus'): | ||||
|     top_level_module_names += module_lists[name] | ||||
|     scan(name) | ||||
| with open(f'{base}/__init__.py', 'w') as f: | ||||
|  | ||||
							
								
								
									
										14
									
								
								src/qt/dbus.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/qt/dbus.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| #!/usr/bin/env python | ||||
| # vim:fileencoding=utf-8 | ||||
| # License: GPL v3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net> | ||||
| 
 | ||||
| 
 | ||||
| from .loader import dynamic_load | ||||
| from .dbus_name_map import name_map, module_names | ||||
| 
 | ||||
| already_imported = {} | ||||
| qt_modules = {} | ||||
| 
 | ||||
| 
 | ||||
| def __getattr__(name): | ||||
|     return dynamic_load(name, name_map, already_imported, qt_modules, module_names) | ||||
							
								
								
									
										20
									
								
								src/qt/dbus.pyi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/qt/dbus.pyi
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| # autogenerated by __main__.py do not edit | ||||
| import PyQt6.QtDBus | ||||
| QDBus = PyQt6.QtDBus.QDBus | ||||
| QDBusAbstractAdaptor = PyQt6.QtDBus.QDBusAbstractAdaptor | ||||
| QDBusAbstractInterface = PyQt6.QtDBus.QDBusAbstractInterface | ||||
| QDBusArgument = PyQt6.QtDBus.QDBusArgument | ||||
| QDBusConnection = PyQt6.QtDBus.QDBusConnection | ||||
| QDBusConnectionInterface = PyQt6.QtDBus.QDBusConnectionInterface | ||||
| QDBusError = PyQt6.QtDBus.QDBusError | ||||
| QDBusInterface = PyQt6.QtDBus.QDBusInterface | ||||
| QDBusMessage = PyQt6.QtDBus.QDBusMessage | ||||
| QDBusObjectPath = PyQt6.QtDBus.QDBusObjectPath | ||||
| QDBusPendingCall = PyQt6.QtDBus.QDBusPendingCall | ||||
| QDBusPendingCallWatcher = PyQt6.QtDBus.QDBusPendingCallWatcher | ||||
| QDBusPendingReply = PyQt6.QtDBus.QDBusPendingReply | ||||
| QDBusReply = PyQt6.QtDBus.QDBusReply | ||||
| QDBusServiceWatcher = PyQt6.QtDBus.QDBusServiceWatcher | ||||
| QDBusSignature = PyQt6.QtDBus.QDBusSignature | ||||
| QDBusUnixFileDescriptor = PyQt6.QtDBus.QDBusUnixFileDescriptor | ||||
| QDBusVariant = PyQt6.QtDBus.QDBusVariant | ||||
							
								
								
									
										22
									
								
								src/qt/dbus_name_map.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/qt/dbus_name_map.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| # autogenerated by __main__.py do not edit | ||||
| name_map = {'QDBus': 'PyQt6.QtDBus', | ||||
|  'QDBusAbstractAdaptor': 'PyQt6.QtDBus', | ||||
|  'QDBusAbstractInterface': 'PyQt6.QtDBus', | ||||
|  'QDBusArgument': 'PyQt6.QtDBus', | ||||
|  'QDBusConnection': 'PyQt6.QtDBus', | ||||
|  'QDBusConnectionInterface': 'PyQt6.QtDBus', | ||||
|  'QDBusError': 'PyQt6.QtDBus', | ||||
|  'QDBusInterface': 'PyQt6.QtDBus', | ||||
|  'QDBusMessage': 'PyQt6.QtDBus', | ||||
|  'QDBusObjectPath': 'PyQt6.QtDBus', | ||||
|  'QDBusPendingCall': 'PyQt6.QtDBus', | ||||
|  'QDBusPendingCallWatcher': 'PyQt6.QtDBus', | ||||
|  'QDBusPendingReply': 'PyQt6.QtDBus', | ||||
|  'QDBusReply': 'PyQt6.QtDBus', | ||||
|  'QDBusServiceWatcher': 'PyQt6.QtDBus', | ||||
|  'QDBusSignature': 'PyQt6.QtDBus', | ||||
|  'QDBusUnixFileDescriptor': 'PyQt6.QtDBus', | ||||
|  'QDBusVariant': 'PyQt6.QtDBus', | ||||
|  'QtDBus': 'PyQt6.QtDBus'} | ||||
| module_names = frozenset(('QtDBus',) | ||||
| ) | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user