From fdf40ce07aa9bb4532bce01b35cad074a00fca9b Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 22 May 2020 07:41:25 +0900 Subject: [PATCH] fix: read GTK dark theme setting on Linux (#23678) --- shell/browser/electron_browser_main_parts.cc | 43 ++++++++++++++++++-- shell/browser/electron_browser_main_parts.h | 6 +++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/shell/browser/electron_browser_main_parts.cc b/shell/browser/electron_browser_main_parts.cc index c1b3e105e5cd..e46d662d09a0 100644 --- a/shell/browser/electron_browser_main_parts.cc +++ b/shell/browser/electron_browser_main_parts.cc @@ -67,6 +67,7 @@ #include "ui/base/x/x11_util.h" #include "ui/base/x/x11_util_internal.h" #include "ui/events/devices/x11/touch_factory_x11.h" +#include "ui/gfx/color_utils.h" #include "ui/gfx/x/x11_types.h" #include "ui/gtk/gtk_ui.h" #include "ui/gtk/gtk_ui_delegate.h" @@ -210,10 +211,36 @@ int X11EmptyErrorHandler(Display* d, XErrorEvent* error) { int X11EmptyIOErrorHandler(Display* d) { return 0; } + +// GTK does not provide a way to check if current theme is dark, so we compare +// the text and background luminosity to get a result. +// This trick comes from FireFox. +void UpdateDarkThemeSetting() { + float bg = color_utils::GetRelativeLuminance(gtk::GetBgColor("GtkLabel")); + float fg = color_utils::GetRelativeLuminance(gtk::GetFgColor("GtkLabel")); + bool is_dark = fg > bg; + // Pass it to NativeUi theme, which is used by the nativeTheme module and most + // places in Electron. + ui::NativeTheme::GetInstanceForNativeUi()->set_use_dark_colors(is_dark); + // Pass it to Web Theme, to make "prefers-color-scheme" media query work. + ui::NativeTheme::GetInstanceForWeb()->set_use_dark_colors(is_dark); +} #endif } // namespace +#if defined(USE_X11) +class DarkThemeObserver : public ui::NativeThemeObserver { + public: + DarkThemeObserver() = default; + + // ui::NativeThemeObserver: + void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override { + UpdateDarkThemeSetting(); + } +}; +#endif + // static ElectronBrowserMainParts* ElectronBrowserMainParts::self_ = nullptr; @@ -374,11 +401,19 @@ void ElectronBrowserMainParts::ToolkitInitialized() { // In Aura/X11, Gtk-based LinuxUI implementation is used. gtk_ui_delegate_ = std::make_unique(gfx::GetXDisplay()); ui::GtkUiDelegate::SetInstance(gtk_ui_delegate_.get()); - views::LinuxUI::SetInstance(BuildGtkUi(ui::GtkUiDelegate::instance())); -#endif + views::LinuxUI* linux_ui = BuildGtkUi(gtk_ui_delegate_.get()); + views::LinuxUI::SetInstance(linux_ui); + linux_ui->Initialize(); -#if defined(USE_AURA) && defined(USE_X11) - views::LinuxUI::instance()->Initialize(); + // Chromium does not respect GTK dark theme setting, but they may change + // in future and this code might be no longer needed. Check the Chromium + // issue to keep updated: + // https://bugs.chromium.org/p/chromium/issues/detail?id=998903 + UpdateDarkThemeSetting(); + // Update the naitve theme when GTK theme changes. The GetNativeTheme + // here returns a NativeThemeGtk, which monitors GTK settings. + dark_theme_observer_.reset(new DarkThemeObserver); + linux_ui->GetNativeTheme(nullptr)->AddObserver(dark_theme_observer_.get()); #endif #if defined(USE_AURA) diff --git a/shell/browser/electron_browser_main_parts.h b/shell/browser/electron_browser_main_parts.h index 50ebb4ebfb34..b2f36da53641 100644 --- a/shell/browser/electron_browser_main_parts.h +++ b/shell/browser/electron_browser_main_parts.h @@ -59,6 +59,10 @@ class ViewsDelegate; class ViewsDelegateMac; #endif +#if defined(USE_X11) +class DarkThemeObserver; +#endif + class ElectronBrowserMainParts : public content::BrowserMainParts { public: explicit ElectronBrowserMainParts(const content::MainFunctionParams& params); @@ -129,6 +133,8 @@ class ElectronBrowserMainParts : public content::BrowserMainParts { #if defined(USE_X11) std::unique_ptr gtk_ui_delegate_; + // Used to notify the native theme of changes to dark mode. + std::unique_ptr dark_theme_observer_; #endif std::unique_ptr layout_provider_;