diff --git a/share/gpodder/ui/gtk/gpodderpreferences.ui b/share/gpodder/ui/gtk/gpodderpreferences.ui index 7a7e1840..1992cd31 100644 --- a/share/gpodder/ui/gtk/gpodderpreferences.ui +++ b/share/gpodder/ui/gtk/gpodderpreferences.ui @@ -1,5 +1,5 @@ - + @@ -273,6 +273,50 @@ 2 + + + True + False + + + True + False + 8 + Color scheme: + + + False + True + 0 + + + + + True + False + True + 0 + 1 + + System + Light + Dark + + + + False + True + end + 1 + + + + + False + True + 3 + + general @@ -1157,7 +1201,6 @@ False 0 vertical - 0 True diff --git a/src/gpodder/config.py b/src/gpodder/config.py index 0af09f22..7a1f3ead 100644 --- a/src/gpodder/config.py +++ b/src/gpodder/config.py @@ -182,6 +182,7 @@ defaults = { }, 'html_shownotes': True, # enable webkit renderer + 'color_scheme': None, # system, light or dark. Initialized in app.py }, }, diff --git a/src/gpodder/gtkui/app.py b/src/gpodder/gtkui/app.py index 778e0cce..8f7acaa9 100644 --- a/src/gpodder/gtkui/app.py +++ b/src/gpodder/gtkui/app.py @@ -200,8 +200,67 @@ class gPodderApplication(Gtk.Application): # Handle "subscribe to podcast" events from firefox macosx.register_handlers(self.window) + # Set dark mode from color_scheme config key, or from Settings portal + # if it exists and color_scheme is 'system'. + if getattr(gpodder.dbus_session_bus, 'fake', False): + self.have_settings_portal = False + self._set_default_color_scheme('light') + self.set_dark_mode(self.window.config.ui.gtk.color_scheme == 'dark') + else: + self.read_portal_color_scheme() + gpodder.dbus_session_bus.add_signal_receiver( + self.on_portal_setting_changed, "SettingChanged", None, + "org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop") + self.window.gPodder.present() + def _set_default_color_scheme(self, default): + """Set the default value for color_scheme based on GTK settings. + + If gtk_application_prefer_dark_theme is set to 1 (a non-default value), + the user has set it in GTK settings.ini and we set color_scheme to match + this preference. Otherwise we set the key to the given default, which + should be 'system' in case Settings portal is found, or 'light' if it's not. + """ + if self.window.config.ui.gtk.color_scheme is None: + settings = Gtk.Settings.get_default() + self.window.config.ui.gtk.color_scheme = ( + 'dark' if settings.props.gtk_application_prefer_dark_theme == 1 + else default) + + def set_dark_mode(self, dark): + settings = Gtk.Settings.get_default() + settings.props.gtk_application_prefer_dark_theme = 1 if dark else 0 + + def read_portal_color_scheme(self): + gpodder.dbus_session_bus.call_async( + "org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop", + "org.freedesktop.portal.Settings", "ReadOne", "ss", + ("org.freedesktop.appearance", "color-scheme"), + self.on_portal_settings_read, self.on_portal_settings_read_error) + + def on_portal_settings_read(self, value): + self.have_settings_portal = True + self._set_default_color_scheme('system') + if self.window.config.ui.gtk.color_scheme == 'system': + self.set_dark_mode(value == 1) + else: + self.set_dark_mode(self.window.config.ui.gtk.color_scheme == 'dark') + + def on_portal_settings_read_error(self, value): + self.have_settings_portal = False + self._set_default_color_scheme('light') + self.set_dark_mode(self.window.config.ui.gtk.color_scheme == 'dark') + + def on_portal_setting_changed(self, namespace, key, value): + if (namespace == 'org.freedesktop.appearance' + and key == 'color-scheme'): + dark = (value == 1) + if self.window.config.ui.gtk.color_scheme == 'system': + logger.debug( + f"'color-scheme' changed to {value}, setting dark mode to {dark}") + self.set_dark_mode(dark) + def on_menu(self, action, param): self.menu_popover.popup() @@ -265,7 +324,8 @@ class gPodderApplication(Gtk.Application): on_send_full_subscriptions=self.window.on_send_full_subscriptions, on_itemExportChannels_activate=self.window.on_itemExportChannels_activate, on_extension_enabled=self.on_extension_enabled, - on_extension_disabled=self.on_extension_disabled) + on_extension_disabled=self.on_extension_disabled, + have_settings_portal=self.have_settings_portal) def on_goto_mygpo(self, action, param): self.window.mygpo_client.open_website() diff --git a/src/gpodder/gtkui/config.py b/src/gpodder/gtkui/config.py index ad93e222..b0f5f246 100644 --- a/src/gpodder/gtkui/config.py +++ b/src/gpodder/gtkui/config.py @@ -154,6 +154,13 @@ class UIConfig(config.Config): setattr(self, name, togglebutton.get_active()) togglebutton.connect('toggled', _togglebutton_toggled) + def connect_gtk_combo_box_text(self, name, combo_text): + combo_text.set_active_id(getattr(self, name)) + + def _combo_box_text_changed(combo): + setattr(self, name, combo.get_active_id()) + combo_text.connect('changed', _combo_box_text_changed) + def connect_gtk_window(self, window, config_prefix, show_window=False): cfg = getattr(self.ui.gtk.state, config_prefix) diff --git a/src/gpodder/gtkui/desktop/preferences.py b/src/gpodder/gtkui/desktop/preferences.py index 4c640ad3..f13472f3 100644 --- a/src/gpodder/gtkui/desktop/preferences.py +++ b/src/gpodder/gtkui/desktop/preferences.py @@ -205,6 +205,21 @@ class gPodderPreferences(BuilderWidget): index = self.video_player_model.get_index(self._config.player.video) self.combo_video_player_app.set_active(index) + self.combo_color_scheme.remove_all() + self.combo_color_scheme.prepend('dark', 'Dark') + self.combo_color_scheme.prepend('light', 'Light') + cs = self._config.ui.gtk.color_scheme + if self.have_settings_portal: + self.combo_color_scheme.prepend('system', 'System') + self.combo_color_scheme.set_active_id(cs) + else: + if cs == 'system': + self.combo_color_scheme.set_active_id('light') + self._config.ui.gtk.color_scheme = 'light' + else: + self.combo_color_scheme.set_active_id(cs) + self._config.connect_gtk_combo_box_text('ui.gtk.color_scheme', self.combo_color_scheme) + self.preferred_youtube_format_model = YouTubeVideoFormatListModel(self._config) self.combobox_preferred_youtube_format.set_model(self.preferred_youtube_format_model) cellrenderer = Gtk.CellRendererText() diff --git a/src/gpodder/gtkui/main.py b/src/gpodder/gtkui/main.py index 5c069016..14a0b7f5 100644 --- a/src/gpodder/gtkui/main.py +++ b/src/gpodder/gtkui/main.py @@ -1486,6 +1486,11 @@ class gPodder(BuilderWidget, dbus.service.Object): self.update_podcast_list_model() elif name == 'ui.gtk.episode_list.columns': self.update_episode_list_columns_visibility() + elif name == 'ui.gtk.color_scheme': + if new_value == 'system': + self.application.read_portal_color_scheme() + else: + self.application.set_dark_mode(new_value == 'dark') elif name == 'limit.downloads.concurrent_max': # Do not allow value to be set below 1 if new_value < 1: