chromium/chromium-113-WebUIDarkMode....

455 lines
16 KiB
Diff

diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 3470da1..ff39851b 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -5628,8 +5628,12 @@
sources += [
"views/chrome_browser_main_extra_parts_views_linux.cc",
"views/chrome_browser_main_extra_parts_views_linux.h",
+ "views/dark_mode_manager_linux.cc",
+ "views/dark_mode_manager_linux.h",
]
deps += [
+ "//components/dbus/thread_linux",
+ "//dbus",
"//ui/base/cursor",
"//ui/ozone",
]
diff --git a/chrome/browser/ui/DEPS b/chrome/browser/ui/DEPS
index fc3fab23..b56a704e 100644
--- a/chrome/browser/ui/DEPS
+++ b/chrome/browser/ui/DEPS
@@ -42,6 +42,9 @@
"browser_navigator_browsertest\.cc": [
"+ash/shell.h",
],
+ "dark_mode_manager_linux\.cc": [
+ "+dbus",
+ ],
"fullscreen_controller_interactive_browsertest\.cc": [
"+ash/shell.h",
],
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
index dbc9cc4e..d7fad5b 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
@@ -7,6 +7,7 @@
#include "base/metrics/histogram_macros.h"
#include "chrome/browser/themes/theme_service_aura_linux.h"
#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/views/dark_mode_manager_linux.h"
#include "chrome/browser/ui/views/theme_profile_key.h"
#include "ui/base/buildflags.h"
#include "ui/base/cursor/cursor_factory.h"
@@ -56,6 +57,8 @@
UMA_HISTOGRAM_ENUMERATION("Linux.SystemTheme.Default",
linux_ui_theme->GetNativeTheme()->system_theme());
}
+
+ dark_mode_manager_ = std::make_unique<ui::DarkModeManagerLinux>();
}
void ChromeBrowserMainExtraPartsViewsLinux::PreCreateThreads() {
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
index 392d14c..6deb520 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
@@ -13,6 +13,7 @@
namespace ui {
class LinuxUiGetter;
+class DarkModeManagerLinux;
}
// Extra parts, which are used by both Ozone/X11/Wayland and inherited by the
@@ -41,6 +42,8 @@
absl::optional<display::ScopedDisplayObserver> display_observer_;
std::unique_ptr<ui::LinuxUiGetter> linux_ui_getter_;
+
+ std::unique_ptr<ui::DarkModeManagerLinux> dark_mode_manager_;
};
#endif // CHROME_BROWSER_UI_VIEWS_CHROME_BROWSER_MAIN_EXTRA_PARTS_VIEWS_LINUX_H_
diff --git a/chrome/browser/ui/views/dark_mode_manager_linux.cc b/chrome/browser/ui/views/dark_mode_manager_linux.cc
new file mode 100644
index 0000000..bb638f7
--- /dev/null
+++ b/chrome/browser/ui/views/dark_mode_manager_linux.cc
@@ -0,0 +1,160 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/dark_mode_manager_linux.h"
+
+#include "base/functional/bind.h"
+#include "base/logging.h"
+#include "components/dbus/thread_linux/dbus_thread_linux.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "dbus/object_proxy.h"
+#include "ui/linux/linux_ui.h"
+#include "ui/linux/linux_ui_factory.h"
+#include "ui/native_theme/native_theme.h"
+
+namespace {
+
+constexpr char kFreedesktopSettingsService[] = "org.freedesktop.portal.Desktop";
+constexpr char kFreedesktopSettingsObjectPath[] =
+ "/org/freedesktop/portal/desktop";
+constexpr char kFreedesktopSettingsInterface[] =
+ "org.freedesktop.portal.Settings";
+constexpr char kSettingChangedSignal[] = "SettingChanged";
+constexpr char kReadMethod[] = "Read";
+constexpr char kSettingsNamespace[] = "org.freedesktop.appearance";
+constexpr char kColorSchemeKey[] = "color-scheme";
+constexpr int kFreedesktopColorSchemeDark = 1;
+
+scoped_refptr<dbus::Bus> CreateBus() {
+ dbus::Bus::Options options;
+ options.bus_type = dbus::Bus::SESSION;
+ options.connection_type = dbus::Bus::PRIVATE;
+ options.dbus_task_runner = dbus_thread_linux::GetTaskRunner();
+ return base::MakeRefCounted<dbus::Bus>(options);
+}
+
+} // namespace
+
+namespace ui {
+
+DarkModeManagerLinux::DarkModeManagerLinux()
+ : bus_(CreateBus()),
+ settings_proxy_(bus_->GetObjectProxy(
+ kFreedesktopSettingsService,
+ dbus::ObjectPath(kFreedesktopSettingsObjectPath))) {
+ // Subscribe to changes in the color scheme preference.
+ settings_proxy_->ConnectToSignal(
+ kFreedesktopSettingsInterface, kSettingChangedSignal,
+ base::BindRepeating(&DarkModeManagerLinux::OnPortalSettingChanged,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::BindOnce(&DarkModeManagerLinux::OnSignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Read initial color scheme preference.
+ dbus::MethodCall method_call(kFreedesktopSettingsInterface, kReadMethod);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(kSettingsNamespace);
+ writer.AppendString(kColorSchemeKey);
+ settings_proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::BindOnce(&DarkModeManagerLinux::OnReadColorSchemeResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Read the toolkit preference while asynchronously fetching the
+ // portal preference.
+ if (auto* linux_ui_theme = ui::GetDefaultLinuxUiTheme()) {
+ auto* native_theme = linux_ui_theme->GetNativeTheme();
+ native_theme_observer_.Observe(native_theme);
+ SetColorScheme(native_theme->ShouldUseDarkColors());
+ }
+}
+
+DarkModeManagerLinux::~DarkModeManagerLinux() {
+ settings_proxy_ = nullptr;
+ dbus::Bus* const bus_ptr = bus_.get();
+ bus_ptr->GetDBusTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&dbus::Bus::ShutdownAndBlock, std::move(bus_)));
+}
+
+void DarkModeManagerLinux::OnNativeThemeUpdated(
+ ui::NativeTheme* observed_theme) {
+ SetColorScheme(observed_theme->ShouldUseDarkColors());
+}
+
+void DarkModeManagerLinux::OnSignalConnected(const std::string& interface_name,
+ const std::string& signal_name,
+ bool connected) {
+ // Nothing to do. Continue using the toolkit setting if !connected.
+}
+
+void DarkModeManagerLinux::OnPortalSettingChanged(dbus::Signal* signal) {
+ dbus::MessageReader reader(signal);
+
+ std::string namespace_changed;
+ std::string key_changed;
+ dbus::MessageReader variant_reader(nullptr);
+ if (!reader.PopString(&namespace_changed) ||
+ !reader.PopString(&key_changed) || !reader.PopVariant(&variant_reader)) {
+ LOG(ERROR) << "Received malformed Setting Changed signal from "
+ "org.freedesktop.portal.Settings";
+ return;
+ }
+
+ if (namespace_changed != kSettingsNamespace ||
+ key_changed != kColorSchemeKey) {
+ return;
+ }
+
+ uint32_t new_color_scheme;
+ if (!variant_reader.PopUint32(&new_color_scheme)) {
+ LOG(ERROR)
+ << "Failed to read color-scheme value from SettingChanged signal";
+ return;
+ }
+
+ SetColorScheme(new_color_scheme == kFreedesktopColorSchemeDark);
+}
+
+void DarkModeManagerLinux::OnReadColorSchemeResponse(dbus::Response* response) {
+ if (!response) {
+ // Continue using the toolkit setting.
+ return;
+ }
+
+ dbus::MessageReader reader(response);
+ dbus::MessageReader variant_reader(nullptr);
+ if (!reader.PopVariant(&variant_reader)) {
+ LOG(ERROR) << "Failed to read variant from Read method response";
+ return;
+ }
+
+ uint32_t new_color_scheme;
+ if (!variant_reader.PopVariantOfUint32(&new_color_scheme)) {
+ LOG(ERROR) << "Failed to read color-scheme value from Read "
+ "method response";
+ return;
+ }
+
+ // Ignore future updates from the toolkit theme.
+ native_theme_observer_.Reset();
+
+ SetColorScheme(new_color_scheme == kFreedesktopColorSchemeDark);
+}
+
+void DarkModeManagerLinux::SetColorScheme(bool prefer_dark_theme) {
+ if (prefer_dark_theme_ == prefer_dark_theme) {
+ return;
+ }
+ prefer_dark_theme_ = prefer_dark_theme;
+
+ NativeTheme* web_theme = NativeTheme::GetInstanceForWeb();
+ web_theme->set_use_dark_colors(prefer_dark_theme_);
+ web_theme->set_preferred_color_scheme(
+ prefer_dark_theme_ ? NativeTheme::PreferredColorScheme::kDark
+ : NativeTheme::PreferredColorScheme::kLight);
+ web_theme->NotifyOnNativeThemeUpdated();
+}
+
+} // namespace ui
diff --git a/chrome/browser/ui/views/dark_mode_manager_linux.h b/chrome/browser/ui/views/dark_mode_manager_linux.h
new file mode 100644
index 0000000..34b07ff
--- /dev/null
+++ b/chrome/browser/ui/views/dark_mode_manager_linux.h
@@ -0,0 +1,62 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_DARK_MODE_MANAGER_LINUX_H_
+#define CHROME_BROWSER_UI_VIEWS_DARK_MODE_MANAGER_LINUX_H_
+
+#include <string>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observation.h"
+#include "ui/native_theme/native_theme_observer.h"
+
+namespace dbus {
+class Bus;
+class ObjectProxy;
+class Response;
+class Signal;
+} // namespace dbus
+
+namespace ui {
+
+// Observes the system color scheme preference using
+// org.freedesktop.portal.Settings. Falls back to the toolkit preference if
+// org.freedesktop.portal.Settings is unavailable. Propagates the dark mode
+// preference to the web theme.
+class DarkModeManagerLinux : public NativeThemeObserver {
+ public:
+ DarkModeManagerLinux();
+ DarkModeManagerLinux(const DarkModeManagerLinux&) = delete;
+ DarkModeManagerLinux& operator=(const DarkModeManagerLinux&) = delete;
+ ~DarkModeManagerLinux() override;
+
+ private:
+ // ui::NativeThemeObserver:
+ void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
+
+ // D-Bus async handlers
+ void OnSignalConnected(const std::string& interface_name,
+ const std::string& signal_name,
+ bool connected);
+ void OnPortalSettingChanged(dbus::Signal* signal);
+ void OnReadColorSchemeResponse(dbus::Response* response);
+
+ // Sets `prefer_dark_theme_` and propagates to the web theme.
+ void SetColorScheme(bool prefer_dark_theme);
+
+ scoped_refptr<dbus::Bus> bus_;
+ raw_ptr<dbus::ObjectProxy> settings_proxy_;
+
+ bool prefer_dark_theme_ = false;
+
+ base::ScopedObservation<NativeTheme, NativeThemeObserver>
+ native_theme_observer_{this};
+
+ base::WeakPtrFactory<DarkModeManagerLinux> weak_ptr_factory_{this};
+};
+
+} // namespace ui
+
+#endif // CHROME_BROWSER_UI_VIEWS_DARK_MODE_MANAGER_LINUX_H_
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 91b1e98..7adddbd 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -1448,17 +1448,17 @@
BASE_FEATURE(kWebShare, "WebShare", base::FEATURE_DISABLED_BY_DEFAULT);
#endif
-// Whether to enable "dark mode" enhancements in Mac Mojave or Windows 10 for
-// UIs implemented with web technologies.
+// Whether to enable "dark mode" enhancements in Mac Mojave, Windows 10, or
+// Linux for UIs implemented with web technologies.
BASE_FEATURE(kWebUIDarkMode,
"WebUIDarkMode",
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || \
- BUILDFLAG(IS_CHROMEOS)
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
#endif // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) ||
- // BUILDFLAG(IS_CHROMEOS)
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
);
#if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/ui/qt/qt_ui.cc b/ui/qt/qt_ui.cc
index b188ad0..6c0d2cd 100644
--- a/ui/qt/qt_ui.cc
+++ b/ui/qt/qt_ui.cc
@@ -98,6 +98,13 @@
QtNativeTheme& operator=(const QtNativeTheme&) = delete;
~QtNativeTheme() override = default;
+ void ThemeChanged(bool prefer_dark_theme) {
+ set_use_dark_colors(IsForcedDarkMode() || prefer_dark_theme);
+ set_preferred_color_scheme(CalculatePreferredColorScheme());
+
+ NotifyOnNativeThemeUpdated();
+ }
+
// ui::NativeTheme:
DISABLE_CFI_VCALL
void PaintFrameTopArea(cc::PaintCanvas* canvas,
@@ -387,7 +394,7 @@
}
void QtUi::ThemeChanged() {
- native_theme_->NotifyOnNativeThemeUpdated();
+ native_theme_->ThemeChanged(PreferDarkTheme());
}
DISABLE_CFI_VCALL
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index decfb02b6817e..108e2af907e25 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -5632,20 +5632,24 @@ static_library("ui") {
]
}
- if (use_aura) {
+ if (use_aura && (is_linux || is_chromeos_lacros)) {
# These files can do Gtk+-based theming for builds with gtk enabled.
- if (is_linux || is_chromeos_lacros) {
+ sources += [
+ "views/chrome_browser_main_extra_parts_views_linux.cc",
+ "views/chrome_browser_main_extra_parts_views_linux.h",
+ ]
+ deps += [
+ "//ui/base/cursor",
+ "//ui/ozone",
+ ]
+ if (use_dbus) {
sources += [
- "views/chrome_browser_main_extra_parts_views_linux.cc",
- "views/chrome_browser_main_extra_parts_views_linux.h",
"views/dark_mode_manager_linux.cc",
"views/dark_mode_manager_linux.h",
]
deps += [
"//components/dbus/thread_linux",
"//dbus",
- "//ui/base/cursor",
- "//ui/ozone",
]
}
}
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
index d7fad5b5b9007..23d0611fdb2b5 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
@@ -7,7 +7,6 @@
#include "base/metrics/histogram_macros.h"
#include "chrome/browser/themes/theme_service_aura_linux.h"
#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/views/dark_mode_manager_linux.h"
#include "chrome/browser/ui/views/theme_profile_key.h"
#include "ui/base/buildflags.h"
#include "ui/base/cursor/cursor_factory.h"
@@ -19,6 +18,10 @@
#include "ui/native_theme/native_theme.h"
#include "ui/ozone/public/ozone_platform.h"
+#if defined(USE_DBUS)
+#include "chrome/browser/ui/views/dark_mode_manager_linux.h"
+#endif
+
namespace {
class LinuxUiGetterImpl : public ui::LinuxUiGetter {
@@ -57,8 +60,9 @@ void ChromeBrowserMainExtraPartsViewsLinux::ToolkitInitialized() {
UMA_HISTOGRAM_ENUMERATION("Linux.SystemTheme.Default",
linux_ui_theme->GetNativeTheme()->system_theme());
}
-
+#if defined(USE_DBUS)
dark_mode_manager_ = std::make_unique<ui::DarkModeManagerLinux>();
+#endif
}
void ChromeBrowserMainExtraPartsViewsLinux::PreCreateThreads() {
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
index 6deb5205d198a..bc9167bda1fc3 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
@@ -13,7 +13,9 @@
namespace ui {
class LinuxUiGetter;
+#if defined(USE_DBUS)
class DarkModeManagerLinux;
+#endif
}
// Extra parts, which are used by both Ozone/X11/Wayland and inherited by the
@@ -42,8 +44,9 @@ class ChromeBrowserMainExtraPartsViewsLinux
absl::optional<display::ScopedDisplayObserver> display_observer_;
std::unique_ptr<ui::LinuxUiGetter> linux_ui_getter_;
-
+#if defined(USE_DBUS)
std::unique_ptr<ui::DarkModeManagerLinux> dark_mode_manager_;
+#endif
};
#endif // CHROME_BROWSER_UI_VIEWS_CHROME_BROWSER_MAIN_EXTRA_PARTS_VIEWS_LINUX_H_