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.

See #23764.

(cherry picked from commit 9b9ec141fbcd604aa8bfc83da6f16fc9bf5c32e0)

Co-authored-by: Colin Kinloch
This commit is contained in:
Paul Cornett 2023-09-30 16:42:58 -07:00 committed by Vadim Zeitlin
parent c81c3538ac
commit 3becb59acd
2 changed files with 112 additions and 1 deletions

View File

@ -295,6 +295,7 @@ wxGTK:
- Fix GSource leak when using wxIdleEvent::RequestMore() (#23364).
- Allow using libwebkit2gtk-4.1 and libsoup-3.0 (Scott Talbert, #23630).
- Support Numpad Enter for ending wxListCtrl editing (Scott Talbert, #23762).
- Improve dark mode detection (Colin Kinloch and Paul Cornett, #23764).
wxMSW:

View File

@ -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, NULL);
// 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, NULL);
}
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 = NULL;
// GTK_THEME environment variable overrides other settings
if (getenv("GTK_THEME") == NULL)
{
m_proxy = g_dbus_proxy_new_for_bus_sync(
G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL,
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Settings",
NULL, NULL);
}
if (m_proxy)
{
g_signal_connect(m_proxy, "g-signal", G_CALLBACK(proxy_g_signal), NULL);
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, NULL, NULL);
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)
{