From 221be0af1a0b5bcf05c59b3403f969643b42dbaf Mon Sep 17 00:00:00 2001 From: Paul Cornett Date: Sat, 30 Sep 2023 16:42:58 -0700 Subject: [PATCH] Enable using a dark theme when Gnome "dark style" is set The dark style setting does not cause a dark theme to be used automatically, so request it explicitly. Co-authored-by: Colin Kinloch --- src/gtk/settings.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/src/gtk/settings.cpp b/src/gtk/settings.cpp index 304724773711..74898d9bb953 100644 --- a/src/gtk/settings.cpp +++ b/src/gtk/settings.cpp @@ -183,6 +183,64 @@ static void notify_gtk_font_name(GObject*, GParamSpec*, void*) } } +static bool UpdatePreferDark(GVariant* value) +{ + // 0: No preference, 1: Prefer dark appearance, 2: Prefer light appearance + gboolean preferDark = g_variant_get_uint32(value) == 1; + + GtkSettings* settings = gtk_settings_get_default(); + char* themeName; + gboolean preferDarkPrev; + g_object_get(settings, + "gtk-theme-name", &themeName, + "gtk-application-prefer-dark-theme", &preferDarkPrev, nullptr); + + // We don't need to enable prefer-dark if the theme is already dark + if (strstr(themeName, "-dark") || strstr(themeName, "-Dark")) + preferDark = false; + g_free(themeName); + + const bool changed = preferDark != preferDarkPrev; + if (changed) + { + g_object_set(settings, + "gtk-application-prefer-dark-theme", preferDark, nullptr); + } + return changed; +} + +// "g-signal" from GDBusProxy +extern "C" { +static void +proxy_g_signal(GDBusProxy*, const char*, const char* signal_name, GVariant* parameters, void*) +{ + if (strcmp(signal_name, "SettingChanged") != 0) + return; + + const char* nameSpace; + const char* key; + GVariant* value; + g_variant_get(parameters, "(&s&sv)", &nameSpace, &key, &value); + if (strcmp(nameSpace, "org.freedesktop.appearance") == 0 && + strcmp(key, "color-scheme") == 0) + { + if (UpdatePreferDark(value)) + { + for (int i = wxSYS_COLOUR_MAX; i--;) + gs_systemColorCache[i].UnRef(); + + for (auto* win: wxTopLevelWindows) + { + wxSysColourChangedEvent event; + event.SetEventObject(win); + win->HandleWindowEvent(event); + } + } + } + g_variant_unref(value); +} +} + // Some notes on using GtkStyleContext. Style information from a context // attached to a non-visible GtkWidget is not accurate. The context has an // internal visibility state, controlled by the widget, which it presumably @@ -1124,12 +1182,62 @@ bool wxSystemSettingsNative::HasFeature(wxSystemFeature index) class wxSystemSettingsModule: public wxModule { public: - virtual bool OnInit() wxOVERRIDE { return true; } + virtual bool OnInit() wxOVERRIDE; virtual void OnExit() wxOVERRIDE; + +#ifdef __WXGTK3__ + GDBusProxy* m_proxy; +#endif wxDECLARE_DYNAMIC_CLASS(wxSystemSettingsModule); }; wxIMPLEMENT_DYNAMIC_CLASS(wxSystemSettingsModule, wxModule); +bool wxSystemSettingsModule::OnInit() +{ +#ifdef __WXGTK3__ + // Gnome has gone to a dark style setting rather than a selectable dark + // theme, available via GSettings as the 'color-scheme' key under the + // 'org.gnome.desktop.interface' schema. It's also available via a "portal" + // (https://docs.flatpak.org/en/latest/portal-api-reference.html), which + // has the advantage of allowing the setting to be accessed from within a + // virtualized environment such as Flatpak. Since the setting does not + // change the theme, we propagate it to the GtkSettings + // 'gtk-application-prefer-dark-theme' property to get a dark theme. + + m_proxy = nullptr; + + // GTK_THEME environment variable overrides other settings + if (getenv("GTK_THEME") == nullptr) + { + m_proxy = g_dbus_proxy_new_for_bus_sync( + G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, nullptr, + "org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + "org.freedesktop.portal.Settings", + nullptr, nullptr); + } + if (m_proxy) + { + g_signal_connect(m_proxy, "g-signal", G_CALLBACK(proxy_g_signal), nullptr); + + GVariant* ret = g_dbus_proxy_call_sync(m_proxy, "Read", + g_variant_new("(ss)", "org.freedesktop.appearance", "color-scheme"), + G_DBUS_CALL_FLAGS_NONE, -1, nullptr, nullptr); + if (ret) + { + GVariant* child; + g_variant_get(ret, "(v)", &child); + GVariant* value = g_variant_get_variant(child); + UpdatePreferDark(value); + g_variant_unref(value); + g_variant_unref(child); + g_variant_unref(ret); + } + } +#endif // __WXGTK3__ + return true; +} + void wxSystemSettingsModule::OnExit() { #ifdef __WXGTK3__ @@ -1141,6 +1249,8 @@ void wxSystemSettingsModule::OnExit() g_signal_handlers_disconnect_by_func(settings, (void*)notify_gtk_font_name, NULL); } + if (m_proxy) + g_object_unref(m_proxy); #endif if (gs_tlw_parent) { -- 2.46.2