diff --git a/BUILD.gn b/BUILD.gn index ad4ca86be..9008c47b9 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -774,6 +774,8 @@ source_set("libcef_static") { "libcef/browser/views/browser_view_view.h", "libcef/browser/views/button_impl.h", "libcef/browser/views/button_view.h", + "libcef/browser/views/color_provider_tracker.cc", + "libcef/browser/views/color_provider_tracker.h", "libcef/browser/views/display_impl.cc", "libcef/browser/views/display_impl.h", "libcef/browser/views/fill_layout_impl.cc", @@ -809,7 +811,11 @@ source_set("libcef_static") { "libcef/browser/views/view_util.cc", "libcef/browser/views/view_util.h", "libcef/browser/views/view_view.h", + "libcef/browser/views/widget.cc", + "libcef/browser/views/widget.h", "libcef/browser/views/widget_destruction_observer.h", + "libcef/browser/views/widget_impl.cc", + "libcef/browser/views/widget_impl.h", "libcef/browser/views/window_impl.cc", "libcef/browser/views/window_impl.h", "libcef/browser/views/window_view.cc", @@ -1123,22 +1129,23 @@ source_set("libcef_static") { "libcef/common/util_linux.cc", ] - if (ozone_platform_x11) { - sources += [ - "libcef/browser/native/window_x11.cc", - "libcef/browser/native/window_x11.h", - ] - } - deps += [ "//build/config/freetype", "//third_party/fontconfig", ] - if (is_linux && !ozone_platform_x11) { - deps += [ - "//third_party/angle:libEGL", + if (ozone_platform_x11) { + sources += [ + "libcef/browser/native/window_x11.cc", + "libcef/browser/native/window_x11.h", ] + } else { + deps += [ "//third_party/angle:libEGL" ] + } + + if (use_dbus) { + deps += [ "//dbus" ] + defines = [ "USE_DBUS" ] } } diff --git a/include/capi/cef_request_context_capi.h b/include/capi/cef_request_context_capi.h index 73cfcd0cc..8f31267ef 100644 --- a/include/capi/cef_request_context_capi.h +++ b/include/capi/cef_request_context_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=23302ef6e4458aa3e7065aeaca3421a6f0b58361$ +// $hash=7df03921b2ee743fb059f13e545ccf89904eb060$ // #ifndef CEF_INCLUDE_CAPI_CEF_REQUEST_CONTEXT_CAPI_H_ @@ -368,6 +368,39 @@ typedef struct _cef_request_context_t { const cef_string_t* top_level_url, cef_content_setting_types_t content_type, cef_content_setting_values_t value); + + /// + /// Sets the Chrome color scheme for all browsers that share this request + /// context. |variant| values of SYSTEM, LIGHT and DARK change the underlying + /// color mode (e.g. light vs dark). Other |variant| values determine how + /// |user_color| will be applied in the current color mode. If |user_color| is + /// transparent (0) the default color will be used. + /// + void(CEF_CALLBACK* set_chrome_color_scheme)( + struct _cef_request_context_t* self, + cef_color_variant_t variant, + cef_color_t user_color); + + /// + /// Returns the current Chrome color scheme mode (SYSTEM, LIGHT or DARK). Must + /// be called on the browser process UI thread. + /// + cef_color_variant_t(CEF_CALLBACK* get_chrome_color_scheme_mode)( + struct _cef_request_context_t* self); + + /// + /// Returns the current Chrome color scheme color, or transparent (0) for the + /// default color. Must be called on the browser process UI thread. + /// + cef_color_t(CEF_CALLBACK* get_chrome_color_scheme_color)( + struct _cef_request_context_t* self); + + /// + /// Returns the current Chrome color scheme variant. Must be called on the + /// browser process UI thread. + /// + cef_color_variant_t(CEF_CALLBACK* get_chrome_color_scheme_variant)( + struct _cef_request_context_t* self); } cef_request_context_t; /// diff --git a/include/capi/views/cef_view_capi.h b/include/capi/views/cef_view_capi.h index c8c1c537c..5104cf8b3 100644 --- a/include/capi/views/cef_view_capi.h +++ b/include/capi/views/cef_view_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=0ea5c2c5c1a8e8349f199a46642631be0c1bfb6b$ +// $hash=08f13de764f30261616372dfffb7f97c57957f73$ // #ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_VIEW_CAPI_H_ @@ -339,18 +339,29 @@ typedef struct _cef_view_t { /// /// Sets the background color for this View. The background color will be - /// automatically reset if the current theme changes. See - /// cef_view_delegate_t::OnThemeChanged for related documentation. + /// automatically reset when cef_view_delegate_t::OnThemeChanged is called. /// void(CEF_CALLBACK* set_background_color)(struct _cef_view_t* self, cef_color_t color); /// - /// Returns the background color for this View. If the background color has - /// not been explicitly set then the current theme color will be returned. + /// Returns the background color for this View. If the background color is + /// unset then the current `GetThemeColor(CEF_ColorPrimaryBackground)` value + /// will be returned. If this View belongs to an overlay (created with + /// cef_window_t::AddOverlayView), and the background color is unset, then a + /// value of transparent (0) will be returned. /// cef_color_t(CEF_CALLBACK* get_background_color)(struct _cef_view_t* self); + /// + /// Returns the current theme color associated with |color_id|, or the + /// placeholder color (red) if unset. See cef_color_ids.h for standard ID + /// values. Standard colors can be overridden and custom colors can be added + /// using cef_window_t::SetThemeColor. + /// + cef_color_t(CEF_CALLBACK* get_theme_color)(struct _cef_view_t* self, + int color_id); + /// /// Convert |point| from this View's coordinate system to DIP screen /// coordinates. This View must belong to a Window when calling this function. diff --git a/include/capi/views/cef_view_delegate_capi.h b/include/capi/views/cef_view_delegate_capi.h index 6fb6c6512..2c3ca01eb 100644 --- a/include/capi/views/cef_view_delegate_capi.h +++ b/include/capi/views/cef_view_delegate_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=d3624baa94bb722c48880b4319f5d5e8035eaa46$ +// $hash=0f562c026f64ca19a32834dcc1e1cd3a98be2f1f$ // #ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_VIEW_DELEGATE_CAPI_H_ @@ -143,11 +143,22 @@ typedef struct _cef_view_delegate_t { /// /// Called when the theme for |view| has changed, after the new theme colors - /// have already been applied. This will be called at least one time when - /// |view| is added to a parent View. Further theme changes can be disabled by - /// passing the `--force-dark-mode` or `--force-light-mode` command-line flag. - /// Optionally use this callback to override the new theme colors by calling - /// the appropriate cef_view_t functions (SetBackgroundColor, etc). + /// have already been applied. Views are notified via the component hierarchy + /// in depth-first reverse order (children before parents). + /// + /// This will be called in the following cases: + /// + /// 1. When |view|, or a parent of |view|, is added to a Window. 2. When the + /// native/OS or Chrome theme changes for the Window that contains + /// |view|. See CefWindowDelegate::OnThemeColorsChanged documentation. + /// 3. When the client explicitly calls cef_window_t::ThemeChanged on the + /// Window + /// that contains |view|. + /// + /// Optionally use this callback to override the new per-View theme colors by + /// calling cef_view_t::SetBackgroundColor or the appropriate component- + /// specific function. See cef_window_t::SetThemeColor documentation for how + /// to customize additional Window theme colors. /// void(CEF_CALLBACK* on_theme_changed)(struct _cef_view_delegate_t* self, struct _cef_view_t* view); diff --git a/include/capi/views/cef_window_capi.h b/include/capi/views/cef_window_capi.h index 358111a04..d4c086ba6 100644 --- a/include/capi/views/cef_window_capi.h +++ b/include/capi/views/cef_window_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=dbe89dfdd14eb114e3f2d16fbfc55624bb91e7ce$ +// $hash=2abb3759a22a95ffc0207f0538c645a74a5030c6$ // #ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_WINDOW_CAPI_H_ @@ -364,6 +364,43 @@ typedef struct _cef_window_t { /// Remove all keyboard accelerators. /// void(CEF_CALLBACK* remove_all_accelerators)(struct _cef_window_t* self); + + /// + /// Override a standard theme color or add a custom color associated with + /// |color_id|. See cef_color_ids.h for standard ID values. Recommended usage + /// is as follows: + /// + /// 1. Customize the default native/OS theme by calling SetThemeColor before + /// showing the first Window. When done setting colors call + /// CefWindow::ThemeChanged to trigger CefViewDelegate::OnThemeChanged + /// notifications. + /// 2. Customize the current native/OS or Chrome theme after it changes by + /// calling SetThemeColor from the CefWindowDelegate::OnThemeColorsChanged + /// callback. CefViewDelegate::OnThemeChanged notifications will then be + /// triggered automatically. + /// + /// The configured color will be available immediately via + /// cef_view_t::GetThemeColor and will be applied to each View in this + /// Window's component hierarchy when cef_view_delegate_t::OnThemeChanged is + /// called. See OnThemeColorsChanged documentation for additional details. + /// + /// Clients wishing to add custom colors should use |color_id| values >= + /// CEF_ChromeColorsEnd. + /// + void(CEF_CALLBACK* set_theme_color)(struct _cef_window_t* self, + int color_id, + cef_color_t color); + + /// + /// Trigger cef_view_delegate_t::OnThemeChanged callbacks for each View in + /// this Window's component hierarchy. Unlike a native/OS or Chrome theme + /// change this function does not reset theme colors to standard values and + /// does not result in a call to cef_window_delegate_t::OnThemeColorsChanged. + /// + /// Do not call this function from cef_window_delegate_t::OnThemeColorsChanged + /// or cef_view_delegate_t::OnThemeChanged. + /// + void(CEF_CALLBACK* theme_changed)(struct _cef_window_t* self); } cef_window_t; /// diff --git a/include/capi/views/cef_window_delegate_capi.h b/include/capi/views/cef_window_delegate_capi.h index ff5e2ac9a..041f44ee9 100644 --- a/include/capi/views/cef_window_delegate_capi.h +++ b/include/capi/views/cef_window_delegate_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=c1c2705cdef7d9189557b57531dc2d53e9f68d0c$ +// $hash=b292cdf6e293dfd42c30ea9189b2a8a2ed77ba7a$ // #ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_WINDOW_DELEGATE_CAPI_H_ @@ -224,6 +224,43 @@ typedef struct _cef_window_delegate_t { int(CEF_CALLBACK* on_key_event)(struct _cef_window_delegate_t* self, struct _cef_window_t* window, const cef_key_event_t* event); + + /// + /// Called after the native/OS or Chrome theme for |window| has changed. + /// |chrome_theme| will be true (1) if the notification is for a Chrome theme. + /// + /// Native/OS theme colors are configured globally and do not need to be + /// customized for each Window individually. An example of a native/OS theme + /// change that triggers this callback is when the user switches between dark + /// and light mode during application lifespan. Native/OS theme changes can be + /// disabled by passing the `--force-dark-mode` or `--force-light-mode` + /// command-line flag. + /// + /// Chrome theme colors will be applied and this callback will be triggered + /// if/when a BrowserView is added to the Window's component hierarchy. Chrome + /// theme colors can be configured on a per-RequestContext basis using + /// cef_request_context_t::SetChromeColorScheme or (Chrome runtime only) by + /// visiting chrome://settings/manageProfile. Any theme changes using those + /// mechanisms will also trigger this callback. Chrome theme colors will be + /// persisted and restored from disk cache with the Chrome runtime, and with + /// the Alloy runtime if persist_user_preferences is set to true (1) via + /// CefSettings or cef_request_context_tSettings. + /// + /// This callback is not triggered on Window creation so clients that wish to + /// customize the initial native/OS theme must call + /// cef_window_t::SetThemeColor and cef_window_t::ThemeChanged before showing + /// the first Window. + /// + /// Theme colors will be reset to standard values before this callback is + /// called for the first affected Window. Call cef_window_t::SetThemeColor + /// from inside this callback to override a standard color or add a custom + /// color. cef_view_delegate_t::OnThemeChanged will be called after this + /// callback for the complete |window| component hierarchy. + /// + void(CEF_CALLBACK* on_theme_colors_changed)( + struct _cef_window_delegate_t* self, + struct _cef_window_t* window, + int chrome_theme); } cef_window_delegate_t; #ifdef __cplusplus diff --git a/include/cef_api_hash.h b/include/cef_api_hash.h index 45e290ccb..033077fd6 100644 --- a/include/cef_api_hash.h +++ b/include/cef_api_hash.h @@ -42,13 +42,13 @@ // way that may cause binary incompatibility with other builds. The universal // hash value will change if any platform is affected whereas the platform hash // values will change only if that particular platform is affected. -#define CEF_API_HASH_UNIVERSAL "a741045ff32b6feeaedf4e767ee0a18ed1c68007" +#define CEF_API_HASH_UNIVERSAL "ed9b17c85e769cb4d087390a77bed6613fed9166" #if defined(OS_WIN) -#define CEF_API_HASH_PLATFORM "1180df9630b71b08a4c4874aa66484c3ca391327" +#define CEF_API_HASH_PLATFORM "5f47de7bf681782160a81ee201cef71f82ac9d69" #elif defined(OS_MAC) -#define CEF_API_HASH_PLATFORM "eaed012692fa480863cb78189e21ddf738fb8d5d" +#define CEF_API_HASH_PLATFORM "d4ca78dc9bc6357c4a05679b2da0863b543f96fa" #elif defined(OS_LINUX) -#define CEF_API_HASH_PLATFORM "e17a9dca9ce61905920a734e71333729578da10e" +#define CEF_API_HASH_PLATFORM "2dfd768af8ca7aa0474a2014b05cec33f64d83b0" #endif #ifdef __cplusplus diff --git a/include/cef_request_context.h b/include/cef_request_context.h index 1ecaf44f9..e977ea3eb 100644 --- a/include/cef_request_context.h +++ b/include/cef_request_context.h @@ -381,6 +381,38 @@ class CefRequestContext : public CefPreferenceManager { const CefString& top_level_url, cef_content_setting_types_t content_type, cef_content_setting_values_t value) = 0; + + /// + /// Sets the Chrome color scheme for all browsers that share this request + /// context. |variant| values of SYSTEM, LIGHT and DARK change the underlying + /// color mode (e.g. light vs dark). Other |variant| values determine how + /// |user_color| will be applied in the current color mode. If |user_color| is + /// transparent (0) the default color will be used. + /// + /*--cef()--*/ + virtual void SetChromeColorScheme(cef_color_variant_t variant, + cef_color_t user_color) = 0; + + /// + /// Returns the current Chrome color scheme mode (SYSTEM, LIGHT or DARK). Must + /// be called on the browser process UI thread. + /// + /*--cef(default_retval=CEF_COLOR_VARIANT_SYSTEM)--*/ + virtual cef_color_variant_t GetChromeColorSchemeMode() = 0; + + /// + /// Returns the current Chrome color scheme color, or transparent (0) for the + /// default color. Must be called on the browser process UI thread. + /// + /*--cef(default_retval=0)--*/ + virtual cef_color_t GetChromeColorSchemeColor() = 0; + + /// + /// Returns the current Chrome color scheme variant. Must be called on the + /// browser process UI thread. + /// + /*--cef(default_retval=CEF_COLOR_VARIANT_SYSTEM)--*/ + virtual cef_color_variant_t GetChromeColorSchemeVariant() = 0; }; #endif // CEF_INCLUDE_CEF_REQUEST_CONTEXT_H_ diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index 44dfb5c6a..231626c9c 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -3854,6 +3854,20 @@ typedef enum { CEF_ZOOM_COMMAND_IN, } cef_zoom_command_t; +/// +/// Specifies the color variants supported by +/// CefRequestContext::SetChromeThemeColor. +/// +typedef enum { + CEF_COLOR_VARIANT_SYSTEM, + CEF_COLOR_VARIANT_LIGHT, + CEF_COLOR_VARIANT_DARK, + CEF_COLOR_VARIANT_TONAL_SPOT, + CEF_COLOR_VARIANT_NEUTRAL, + CEF_COLOR_VARIANT_VIBRANT, + CEF_COLOR_VARIANT_EXPRESSIVE, +} cef_color_variant_t; + #ifdef __cplusplus } #endif diff --git a/include/views/cef_view.h b/include/views/cef_view.h index cd4a4dd71..4795da860 100644 --- a/include/views/cef_view.h +++ b/include/views/cef_view.h @@ -358,19 +358,30 @@ class CefView : public CefBaseRefCounted { /// /// Sets the background color for this View. The background color will be - /// automatically reset if the current theme changes. See - /// CefViewDelegate::OnThemeChanged for related documentation. + /// automatically reset when CefViewDelegate::OnThemeChanged is called. /// /*--cef()--*/ virtual void SetBackgroundColor(cef_color_t color) = 0; /// - /// Returns the background color for this View. If the background color has - /// not been explicitly set then the current theme color will be returned. + /// Returns the background color for this View. If the background color is + /// unset then the current `GetThemeColor(CEF_ColorPrimaryBackground)` value + /// will be returned. If this View belongs to an overlay (created with + /// CefWindow::AddOverlayView), and the background color is unset, then a + /// value of transparent (0) will be returned. /// /*--cef()--*/ virtual cef_color_t GetBackgroundColor() = 0; + /// + /// Returns the current theme color associated with |color_id|, or the + /// placeholder color (red) if unset. See cef_color_ids.h for standard ID + /// values. Standard colors can be overridden and custom colors can be added + /// using CefWindow::SetThemeColor. + /// + /*--cef()--*/ + virtual cef_color_t GetThemeColor(int color_id) = 0; + /// /// Convert |point| from this View's coordinate system to DIP screen /// coordinates. This View must belong to a Window when calling this method. diff --git a/include/views/cef_view_delegate.h b/include/views/cef_view_delegate.h index 13908c344..73686847d 100644 --- a/include/views/cef_view_delegate.h +++ b/include/views/cef_view_delegate.h @@ -134,11 +134,21 @@ class CefViewDelegate : public virtual CefBaseRefCounted { /// /// Called when the theme for |view| has changed, after the new theme colors - /// have already been applied. This will be called at least one time when - /// |view| is added to a parent View. Further theme changes can be disabled by - /// passing the `--force-dark-mode` or `--force-light-mode` command-line flag. - /// Optionally use this callback to override the new theme colors by calling - /// the appropriate CefView methods (SetBackgroundColor, etc). + /// have already been applied. Views are notified via the component hierarchy + /// in depth-first reverse order (children before parents). + /// + /// This will be called in the following cases: + /// + /// 1. When |view|, or a parent of |view|, is added to a Window. + /// 2. When the native/OS or Chrome theme changes for the Window that contains + /// |view|. See CefWindowDelegate::OnThemeColorsChanged documentation. + /// 3. When the client explicitly calls CefWindow::ThemeChanged on the Window + /// that contains |view|. + /// + /// Optionally use this callback to override the new per-View theme colors by + /// calling CefView::SetBackgroundColor or the appropriate component-specific + /// method. See CefWindow::SetThemeColor documentation for how to customize + /// additional Window theme colors. /// /*--cef()--*/ virtual void OnThemeChanged(CefRefPtr view) {} diff --git a/include/views/cef_window.h b/include/views/cef_window.h index 6d979b1bf..04ab5bb36 100644 --- a/include/views/cef_window.h +++ b/include/views/cef_window.h @@ -377,6 +377,43 @@ class CefWindow : public CefPanel { /// /*--cef()--*/ virtual void RemoveAllAccelerators() = 0; + + /// + /// Override a standard theme color or add a custom color associated with + /// |color_id|. See cef_color_ids.h for standard ID values. Recommended usage + /// is as follows: + /// + /// 1. Customize the default native/OS theme by calling SetThemeColor before + /// showing the first Window. When done setting colors call + /// CefWindow::ThemeChanged to trigger CefViewDelegate::OnThemeChanged + /// notifications. + /// 2. Customize the current native/OS or Chrome theme after it changes by + /// calling SetThemeColor from the CefWindowDelegate::OnThemeColorsChanged + /// callback. CefViewDelegate::OnThemeChanged notifications will then be + /// triggered automatically. + /// + /// The configured color will be available immediately via + /// CefView::GetThemeColor and will be applied to each View in this Window's + /// component hierarchy when CefViewDelegate::OnThemeChanged is called. See + /// OnThemeColorsChanged documentation for additional details. + /// + /// Clients wishing to add custom colors should use |color_id| values >= + /// CEF_ChromeColorsEnd. + /// + /*--cef()--*/ + virtual void SetThemeColor(int color_id, cef_color_t color) = 0; + + /// + /// Trigger CefViewDelegate::OnThemeChanged callbacks for each View in this + /// Window's component hierarchy. Unlike a native/OS or Chrome theme change + /// this method does not reset theme colors to standard values and does not + /// result in a call to CefWindowDelegate::OnThemeColorsChanged. + /// + /// Do not call this method from CefWindowDelegate::OnThemeColorsChanged or + /// CefViewDelegate::OnThemeChanged. + /// + /*--cef()--*/ + virtual void ThemeChanged() = 0; }; #endif // CEF_INCLUDE_VIEWS_CEF_WINDOW_H_ diff --git a/include/views/cef_window_delegate.h b/include/views/cef_window_delegate.h index 6c0f239a4..3231c45ab 100644 --- a/include/views/cef_window_delegate.h +++ b/include/views/cef_window_delegate.h @@ -164,12 +164,11 @@ class CefWindowDelegate : public CefPanelDelegate { } /// - /// Return whether the titlebar height should be overridden, - /// and sets the height of the titlebar in |titlebar_height|. - /// On macOS, it can also be used to adjust the vertical position - /// of the traffic light buttons in frameless windows. - /// The buttons will be positioned halfway down the titlebar - /// at a height of |titlebar_height| / 2. + /// Return whether the titlebar height should be overridden, and sets the + /// height of the titlebar in |titlebar_height|. On macOS, it can also be used + /// to adjust the vertical position of the traffic light buttons in frameless + /// windows. The buttons will be positioned halfway down the titlebar at a + /// height of |titlebar_height| / 2. /// /*--cef()--*/ virtual bool GetTitlebarHeight(CefRefPtr window, @@ -222,6 +221,41 @@ class CefWindowDelegate : public CefPanelDelegate { const CefKeyEvent& event) { return false; } + + /// + /// Called after the native/OS or Chrome theme for |window| has changed. + /// |chrome_theme| will be true if the notification is for a Chrome theme. + /// + /// Native/OS theme colors are configured globally and do not need to be + /// customized for each Window individually. An example of a native/OS theme + /// change that triggers this callback is when the user switches between dark + /// and light mode during application lifespan. Native/OS theme changes can be + /// disabled by passing the `--force-dark-mode` or `--force-light-mode` + /// command-line flag. + /// + /// Chrome theme colors will be applied and this callback will be triggered + /// if/when a BrowserView is added to the Window's component hierarchy. Chrome + /// theme colors can be configured on a per-RequestContext basis using + /// CefRequestContext::SetChromeColorScheme or (Chrome runtime only) by + /// visiting chrome://settings/manageProfile. Any theme changes using those + /// mechanisms will also trigger this callback. Chrome theme colors will be + /// persisted and restored from disk cache with the Chrome runtime, and with + /// the Alloy runtime if persist_user_preferences is set to true via + /// CefSettings or CefRequestContextSettings. + /// + /// This callback is not triggered on Window creation so clients that wish to + /// customize the initial native/OS theme must call CefWindow::SetThemeColor + /// and CefWindow::ThemeChanged before showing the first Window. + /// + /// Theme colors will be reset to standard values before this callback is + /// called for the first affected Window. Call CefWindow::SetThemeColor from + /// inside this callback to override a standard color or add a custom color. + /// CefViewDelegate::OnThemeChanged will be called after this callback for the + /// complete |window| component hierarchy. + /// + /*--cef()--*/ + virtual void OnThemeColorsChanged(CefRefPtr window, + bool chrome_theme) {} }; #endif // CEF_INCLUDE_VIEWS_CEF_WINDOW_DELEGATE_H_ diff --git a/libcef/browser/alloy/alloy_browser_main.cc b/libcef/browser/alloy/alloy_browser_main.cc index 5992cdde2..790c9cd70 100644 --- a/libcef/browser/alloy/alloy_browser_main.cc +++ b/libcef/browser/alloy/alloy_browser_main.cc @@ -55,6 +55,9 @@ #if defined(USE_AURA) && BUILDFLAG(IS_OZONE_X11) #include "ui/events/devices/x11/touch_factory_x11.h" #endif +#if defined(USE_DBUS) +#include "chrome/browser/ui/views/dark_mode_manager_linux.h" +#endif #endif #if defined(USE_AURA) @@ -127,22 +130,6 @@ class LinuxUiGetterImpl : public ui::LinuxUiGetter { } }; -ui::LinuxUi* GetLinuxUI() { - // We can't use GtkUi in combination with multi-threaded-message-loop because - // Chromium's GTK implementation doesn't use GDK threads. - if (!!CefContext::Get()->settings().multi_threaded_message_loop) { - return nullptr; - } - - // If the ozone backend hasn't provided a LinuxUiDelegate, don't try to create - // a LinuxUi instance as this may result in a crash in toolkit initialization. - if (!ui::LinuxUiDelegate::GetInstance()) { - return nullptr; - } - - return ui::GetDefaultLinuxUi(); -} - #endif // BUILDFLAG(IS_LINUX) void ProcessSingletonNotificationCallbackImpl( @@ -220,7 +207,9 @@ void AlloyBrowserMainParts::ToolkitInitialized() { #if BUILDFLAG(IS_LINUX) // Based on chrome_browser_main_extra_parts_views_linux.cc - if (auto linux_ui = GetLinuxUI()) { + // |linux_ui| will be nullptr with multi-threaded-message-loop. See + // CefUiThread::InitializeBrowserRunner. + if (auto linux_ui = ui::GetDefaultLinuxUi()) { linux_ui_getter_ = std::make_unique(); ui::LinuxUi::SetInstance(linux_ui); @@ -229,6 +218,13 @@ void AlloyBrowserMainParts::ToolkitInitialized() { ui::CursorFactory::GetInstance()->ObserveThemeChanges(); } +#if defined(USE_DBUS) + if (!ui::NativeTheme::IsForcedDarkMode() && + !ui::NativeTheme::IsForcedLightMode()) { + dark_mode_manager_ = std::make_unique(); + } +#endif + auto printing_delegate = new CefPrintingContextLinuxDelegate(); auto default_delegate = ui::PrintingContextLinuxDelegate::SetInstance(printing_delegate); diff --git a/libcef/browser/alloy/alloy_browser_main.h b/libcef/browser/alloy/alloy_browser_main.h index 637af2062..0ddd4db5b 100644 --- a/libcef/browser/alloy/alloy_browser_main.h +++ b/libcef/browser/alloy/alloy_browser_main.h @@ -31,7 +31,10 @@ class LayoutProvider; #if BUILDFLAG(IS_LINUX) namespace ui { class LinuxUiGetter; -} +#if defined(USE_DBUS) +class DarkModeManagerLinux; +#endif +} // namespace ui #endif class CefDevToolsDelegate; @@ -99,6 +102,9 @@ class AlloyBrowserMainParts : public content::BrowserMainParts { #if BUILDFLAG(IS_LINUX) std::unique_ptr linux_ui_getter_; +#if defined(USE_DBUS) + std::unique_ptr dark_mode_manager_; +#endif #endif }; diff --git a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc index 25c24bf51..0361151e2 100644 --- a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc +++ b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc @@ -72,6 +72,12 @@ void CefBrowserPlatformDelegateChromeViews::WebContentsCreated( browser_view_->WebContentsCreated(web_contents); } +void CefBrowserPlatformDelegateChromeViews::WebContentsDestroyed( + content::WebContents* web_contents) { + CefBrowserPlatformDelegateChrome::WebContentsDestroyed(web_contents); + browser_view_->WebContentsDestroyed(web_contents); +} + void CefBrowserPlatformDelegateChromeViews::BrowserCreated( CefBrowserHostBase* browser) { CefBrowserPlatformDelegateChrome::BrowserCreated(browser); diff --git a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h index ffd4c58c4..f6aaea12a 100644 --- a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h +++ b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h @@ -21,6 +21,7 @@ class CefBrowserPlatformDelegateChromeViews // CefBrowserPlatformDelegate overrides. void WebContentsCreated(content::WebContents* web_contents, bool owned) override; + void WebContentsDestroyed(content::WebContents* web_contents) override; void BrowserCreated(CefBrowserHostBase* browser) override; void NotifyBrowserCreated() override; void NotifyBrowserDestroyed() override; diff --git a/libcef/browser/chrome/views/chrome_browser_frame.cc b/libcef/browser/chrome/views/chrome_browser_frame.cc index 99608541d..845389b5b 100644 --- a/libcef/browser/chrome/views/chrome_browser_frame.cc +++ b/libcef/browser/chrome/views/chrome_browser_frame.cc @@ -5,6 +5,7 @@ #include "libcef/browser/chrome/views/chrome_browser_frame.h" #include "libcef/browser/chrome/chrome_browser_host_impl.h" +#include "libcef/browser/views/window_view.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/ui/browser.h" @@ -17,6 +18,9 @@ #include "ui/views/widget/native_widget_private.h" #endif +ChromeBrowserFrame::ChromeBrowserFrame(CefWindowView* window_view) + : window_view_(window_view) {} + void ChromeBrowserFrame::Init(BrowserView* browser_view, std::unique_ptr browser) { DCHECK(browser_view); @@ -45,8 +49,54 @@ void ChromeBrowserFrame::Init(BrowserView* browser_view, #endif // BUILDFLAG(IS_MAC) } -void ChromeBrowserFrame::ToggleFullscreenMode() { - chrome::ToggleFullscreenMode(browser_view_->browser()); +void ChromeBrowserFrame::Initialized() { + initialized_ = true; + + // Based on BrowserFrame::InitBrowserFrame. + // This is the first call that will trigger theme-related client callbacks. +#if BUILDFLAG(IS_LINUX) + // Calls ThemeChanged() or OnNativeThemeUpdated(). + SelectNativeTheme(); +#else + // Calls ThemeChanged(). + SetNativeTheme(ui::NativeTheme::GetInstanceForNativeUi()); +#endif +} + +void ChromeBrowserFrame::AddAssociatedProfile(Profile* /*profile*/) { + // Calls ThemeChanged(). + UserChangedTheme(BrowserThemeChangeType::kBrowserTheme); +} + +void ChromeBrowserFrame::RemoveAssociatedProfile(Profile* /*profile*/) {} + +Profile* ChromeBrowserFrame::GetThemeProfile() const { + if (browser_view_) { + return browser_view_->GetProfile(); + } + return nullptr; +} + +bool ChromeBrowserFrame::ToggleFullscreenMode() { + if (browser_view_) { + // Toggle fullscreen mode via the Chrome command for consistent behavior. + chrome::ToggleFullscreenMode(browser_view_->browser()); + return true; + } + return false; +} + +void ChromeBrowserFrame::UserChangedTheme( + BrowserThemeChangeType theme_change_type) { + // Callback from Browser::OnThemeChanged() and OnNativeThemeUpdated(). + + // Calls ThemeChanged() and possibly SelectNativeTheme(). + BrowserFrame::UserChangedTheme(theme_change_type); + + if (window_view_) { + window_view_->OnThemeColorsChanged(/*chrome_theme=*/!native_theme_change_); + ThemeChanged(); + } } views::internal::RootView* ChromeBrowserFrame::CreateRootView() { @@ -80,3 +130,34 @@ void ChromeBrowserFrame::Activate() { // Proceed with default handling. BrowserFrame::Activate(); } + +void ChromeBrowserFrame::OnNativeWidgetDestroyed() { + window_view_ = nullptr; + BrowserFrame::OnNativeWidgetDestroyed(); +} + +void ChromeBrowserFrame::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) { + // TODO: Reduce the frequency of this callback on Windows/Linux. + // See https://issues.chromium.org/issues/40280130#comment7 + + color_provider_tracker_.OnNativeThemeUpdated(); + + native_theme_change_ = true; + + // Calls UserChangedTheme(). + BrowserFrame::OnNativeThemeUpdated(observed_theme); + + native_theme_change_ = false; +} + +void ChromeBrowserFrame::OnColorProviderCacheResetMissed() { + // Ignore calls during Widget::Init(). + if (!initialized_) { + return; + } + + if (window_view_) { + window_view_->OnThemeColorsChanged(/*chrome_theme=*/false); + ThemeChanged(); + } +} diff --git a/libcef/browser/chrome/views/chrome_browser_frame.h b/libcef/browser/chrome/views/chrome_browser_frame.h index fb44932d6..436e13edd 100644 --- a/libcef/browser/chrome/views/chrome_browser_frame.h +++ b/libcef/browser/chrome/views/chrome_browser_frame.h @@ -6,6 +6,9 @@ #define CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_BROWSER_FRAME_H_ #pragma once +#include "libcef/browser/views/color_provider_tracker.h" +#include "libcef/browser/views/widget.h" + #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/views/frame/browser_frame.h" @@ -86,18 +89,34 @@ // modifications. class BrowserView; +class CefWindowView; // Widget for a Views-hosted Chrome browser. Created in // CefWindowView::CreateWidget() when the Chrome runtime is enabled. -class ChromeBrowserFrame : public BrowserFrame { +class ChromeBrowserFrame : public BrowserFrame, + public CefWidget, + public CefColorProviderTracker::Observer { public: - ChromeBrowserFrame() = default; + explicit ChromeBrowserFrame(CefWindowView* window_view); + ChromeBrowserFrame(const ChromeBrowserFrame&) = delete; ChromeBrowserFrame& operator=(const ChromeBrowserFrame&) = delete; + // Called from ChromeBrowserView::InitBrowser after |browser| creation. void Init(BrowserView* browser_view, std::unique_ptr browser); - void ToggleFullscreenMode(); + // CefWidget methods: + views::Widget* GetWidget() override { return this; } + const views::Widget* GetWidget() const override { return this; } + void Initialized() override; + bool IsInitialized() const override { return initialized_; } + void AddAssociatedProfile(Profile* profile) override; + void RemoveAssociatedProfile(Profile* profile) override; + Profile* GetThemeProfile() const override; + bool ToggleFullscreenMode() override; + + // BrowserFrame methods: + void UserChangedTheme(BrowserThemeChangeType theme_change_type) override; // views::Widget methods: views::internal::RootView* CreateRootView() override; @@ -105,10 +124,25 @@ class ChromeBrowserFrame : public BrowserFrame { override; void Activate() override; + // NativeWidgetDelegate methods: + void OnNativeWidgetDestroyed() override; + + // ui::NativeThemeObserver methods: + void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override; + BrowserView* browser_view() const { return browser_view_; } private: + // CefColorProviderTracker::Observer methods: + void OnColorProviderCacheResetMissed() override; + + CefWindowView* window_view_; BrowserView* browser_view_ = nullptr; + + bool initialized_ = false; + bool native_theme_change_ = false; + + CefColorProviderTracker color_provider_tracker_{this}; }; #endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_BROWSER_FRAME_H_ diff --git a/libcef/browser/chrome/views/chrome_browser_view.cc b/libcef/browser/chrome/views/chrome_browser_view.cc index b6c6cbc0b..b72b706f2 100644 --- a/libcef/browser/chrome/views/chrome_browser_view.cc +++ b/libcef/browser/chrome/views/chrome_browser_view.cc @@ -52,8 +52,17 @@ void ChromeBrowserView::ViewHierarchyChanged( } void ChromeBrowserView::AddedToWidget() { + // Create the Browser and ChromeBrowserHostImpl. // Results in a call to InitBrowser which calls ParentClass::AddedToWidget. cef_browser_view_->OnBrowserViewAdded(); + + // Call after ChromeBrowserHostImpl creation. + cef_browser_view_->AddedToWidget(); +} + +void ChromeBrowserView::RemovedFromWidget() { + ParentClass::RemovedFromWidget(); + cef_browser_view_->RemovedFromWidget(); } void ChromeBrowserView::OnBoundsChanged(const gfx::Rect& previous_bounds) { diff --git a/libcef/browser/chrome/views/chrome_browser_view.h b/libcef/browser/chrome/views/chrome_browser_view.h index c7ae94afd..c41b572a2 100644 --- a/libcef/browser/chrome/views/chrome_browser_view.h +++ b/libcef/browser/chrome/views/chrome_browser_view.h @@ -42,6 +42,7 @@ class ChromeBrowserView void ViewHierarchyChanged( const views::ViewHierarchyChangedDetails& details) override; void AddedToWidget() override; + void RemovedFromWidget() override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void OnGestureEvent(ui::GestureEvent* event) override; diff --git a/libcef/browser/main_runner.cc b/libcef/browser/main_runner.cc index 26ab9b84a..a30a26a99 100644 --- a/libcef/browser/main_runner.cc +++ b/libcef/browser/main_runner.cc @@ -31,6 +31,13 @@ #include "content/public/common/content_switches.h" #include "third_party/crashpad/crashpad/handler/handler_main.h" +#if BUILDFLAG(IS_LINUX) +#include "ui/base/ozone_buildflags.h" +#if BUILDFLAG(IS_OZONE_X11) +#include "ui/ozone/platform/x11/ozone_platform_x11.h" +#endif +#endif + #if BUILDFLAG(IS_WIN) #include #include @@ -155,6 +162,17 @@ class CefUIThread : public base::PlatformThread::Delegate { void InitializeBrowserRunner( content::MainFunctionParams main_function_params) { +#if BUILDFLAG(IS_LINUX) +#if BUILDFLAG(IS_OZONE_X11) + // Disable creation of GtkUi (interface to GTK desktop features) and cause + // ui::GetDefaultLinuxUi() (and related functions) to return nullptr. We + // can't use GtkUi in combination with multi-threaded-message-loop because + // Chromium's GTK implementation doesn't use GDK threads. Light/dark theme + // changes will still be detected via DarkModeManagerLinux. + ui::SetMultiThreadedMessageLoopX11(); +#endif +#endif + // Use our own browser process runner. browser_runner_ = content::BrowserMainRunner::Create(); diff --git a/libcef/browser/prefs/browser_prefs.cc b/libcef/browser/prefs/browser_prefs.cc index 1e558aa07..f7a6cae7d 100644 --- a/libcef/browser/prefs/browser_prefs.cc +++ b/libcef/browser/prefs/browser_prefs.cc @@ -30,6 +30,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ssl/ssl_config_service_manager.h" #include "chrome/browser/themes/theme_service.h" +#include "chrome/browser/ui/browser_view_prefs.h" #include "chrome/browser/ui/webui/accessibility/accessibility_ui.h" #include "chrome/browser/ui/webui/print_preview/policy_settings.h" #include "chrome/common/buildflags.h" @@ -271,6 +272,7 @@ std::unique_ptr CreatePrefService(Profile* profile, prefetch::RegisterPredictionOptionsProfilePrefs(registry.get()); privacy_sandbox::RegisterProfilePrefs(registry.get()); ProfileNetworkContextService::RegisterProfilePrefs(registry.get()); + RegisterBrowserViewProfilePrefs(registry.get()); safe_browsing::RegisterProfilePrefs(registry.get()); unified_consent::UnifiedConsentService::RegisterPrefs(registry.get()); diff --git a/libcef/browser/prefs/renderer_prefs.cc b/libcef/browser/prefs/renderer_prefs.cc index bd40eff44..d3e7083c0 100644 --- a/libcef/browser/prefs/renderer_prefs.cc +++ b/libcef/browser/prefs/renderer_prefs.cc @@ -22,6 +22,8 @@ #include "chrome/browser/extensions/extension_webkit_preferences.h" #include "chrome/browser/font_family_cache.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/themes/theme_service.h" +#include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/ui/prefs/prefs_tab_helper.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" @@ -211,9 +213,25 @@ bool UpdatePreferredColorScheme(blink::web_pref::WebPreferences* web_prefs, const ui::NativeTheme* native_theme) { auto old_preferred_color_scheme = web_prefs->preferred_color_scheme; + auto preferred_color_scheme = native_theme->GetPreferredColorScheme(); + + // Based on https://issues.chromium.org/issues/332328864#comment3 + auto* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + const auto* theme_service = ThemeServiceFactory::GetForProfile(profile); + + const auto browser_color_scheme = theme_service->GetBrowserColorScheme(); + if (browser_color_scheme != ThemeService::BrowserColorScheme::kSystem) { + // Override the native theme. + preferred_color_scheme = + browser_color_scheme == ThemeService::BrowserColorScheme::kLight + ? ui::NativeTheme::PreferredColorScheme::kLight + : ui::NativeTheme::PreferredColorScheme::kDark; + } + // Update based on native theme scheme. web_prefs->preferred_color_scheme = - ToBlinkPreferredColorScheme(native_theme->GetPreferredColorScheme()); + ToBlinkPreferredColorScheme(preferred_color_scheme); if (url.SchemeIs(content::kChromeUIScheme)) { // WebUI should track the color mode of the ColorProvider associated with diff --git a/libcef/browser/request_context_impl.cc b/libcef/browser/request_context_impl.cc index c020f584d..d915bf611 100644 --- a/libcef/browser/request_context_impl.cc +++ b/libcef/browser/request_context_impl.cc @@ -10,12 +10,15 @@ #include "libcef/common/app_manager.h" #include "libcef/common/task_runner_impl.h" #include "libcef/common/values_impl.h" +#include "libcef/features/runtime.h" #include "base/atomic_sequence_num.h" #include "base/logging.h" #include "base/strings/stringprintf.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/themes/theme_service.h" +#include "chrome/browser/themes/theme_service_factory.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/prefs/pref_service.h" #include "content/public/browser/browser_task_traits.h" @@ -27,6 +30,7 @@ #include "services/network/public/cpp/resolve_host_client_base.h" #include "services/network/public/mojom/clear_data_filter.mojom.h" #include "services/network/public/mojom/network_context.mojom.h" +#include "ui/base/ui_base_features.h" using content::BrowserThread; @@ -631,6 +635,72 @@ void CefRequestContextImpl::SetContentSetting( requesting_url, top_level_url, content_type, value)); } +void CefRequestContextImpl::SetChromeColorScheme(cef_color_variant_t variant, + cef_color_t user_color) { + GetBrowserContext( + content::GetUIThreadTaskRunner({}), + base::BindOnce(&CefRequestContextImpl::SetChromeColorSchemeInternal, this, + variant, user_color)); +} + +cef_color_variant_t CefRequestContextImpl::GetChromeColorSchemeMode() { + if (!VerifyBrowserContext()) { + return CEF_COLOR_VARIANT_SYSTEM; + } + + const auto* theme_service = + ThemeServiceFactory::GetForProfile(browser_context()->AsProfile()); + switch (theme_service->GetBrowserColorScheme()) { + case ThemeService::BrowserColorScheme::kSystem: + return CEF_COLOR_VARIANT_SYSTEM; + case ThemeService::BrowserColorScheme::kLight: + return CEF_COLOR_VARIANT_LIGHT; + case ThemeService::BrowserColorScheme::kDark: + return CEF_COLOR_VARIANT_DARK; + } + + DCHECK(false); // Not reached. + return CEF_COLOR_VARIANT_SYSTEM; +} + +cef_color_t CefRequestContextImpl::GetChromeColorSchemeColor() { + if (!VerifyBrowserContext()) { + return 0; + } + + const auto* theme_service = + ThemeServiceFactory::GetForProfile(browser_context()->AsProfile()); + if (const auto& user_color = theme_service->GetUserColor()) { + return *user_color; + } + + return 0; +} + +cef_color_variant_t CefRequestContextImpl::GetChromeColorSchemeVariant() { + if (!VerifyBrowserContext()) { + return CEF_COLOR_VARIANT_SYSTEM; + } + + const auto* theme_service = + ThemeServiceFactory::GetForProfile(browser_context()->AsProfile()); + switch (theme_service->GetBrowserColorVariant()) { + case ui::mojom::BrowserColorVariant::kSystem: + return CEF_COLOR_VARIANT_SYSTEM; + case ui::mojom::BrowserColorVariant::kTonalSpot: + return CEF_COLOR_VARIANT_TONAL_SPOT; + case ui::mojom::BrowserColorVariant::kNeutral: + return CEF_COLOR_VARIANT_NEUTRAL; + case ui::mojom::BrowserColorVariant::kVibrant: + return CEF_COLOR_VARIANT_VIBRANT; + case ui::mojom::BrowserColorVariant::kExpressive: + return CEF_COLOR_VARIANT_EXPRESSIVE; + } + + DCHECK(false); // Not reached. + return CEF_COLOR_VARIANT_SYSTEM; +} + void CefRequestContextImpl::OnRenderFrameCreated( const content::GlobalRenderFrameHostId& global_id, bool is_main_frame, @@ -898,6 +968,90 @@ void CefRequestContextImpl::SetContentSettingInternal( } } +void CefRequestContextImpl::SetChromeColorSchemeInternal( + cef_color_variant_t variant, + cef_color_t user_color, + CefBrowserContext::Getter browser_context_getter) { + auto* browser_context = browser_context_getter.Run(); + if (!browser_context) { + return; + } + + auto* theme_service = + ThemeServiceFactory::GetForProfile(browser_context->AsProfile()); + + // Possibly set the color scheme. + std::optional color_scheme; + switch (variant) { + case CEF_COLOR_VARIANT_SYSTEM: + color_scheme = ThemeService::BrowserColorScheme::kSystem; + break; + case CEF_COLOR_VARIANT_LIGHT: + color_scheme = ThemeService::BrowserColorScheme::kLight; + break; + case CEF_COLOR_VARIANT_DARK: + color_scheme = ThemeService::BrowserColorScheme::kDark; + break; + default: + break; + } + + if (color_scheme && *color_scheme != theme_service->GetBrowserColorScheme()) { + // Color scheme has changed. + // Based on CustomizeColorSchemeModeHandler::SetColorSchemeMode. + theme_service->SetBrowserColorScheme(*color_scheme); + } + + // Returns nullopt if the current color is SK_ColorTRANSPARENT. + const auto& current_color = theme_service->GetUserColor(); + + // Possibly set the user color. + if (user_color == 0) { + if (current_color) { + // User color is not currently transparent. + // Based on ThemeColorPickerHandler::SetDefaultColor. + if (features::IsChromeWebuiRefresh2023()) { + theme_service->SetUserColor(SK_ColorTRANSPARENT); + theme_service->UseDeviceTheme(false); + } else { + theme_service->UseDefaultTheme(); + } + } + } else { + ui::mojom::BrowserColorVariant ui_variant; + switch (variant) { + case CEF_COLOR_VARIANT_NEUTRAL: + ui_variant = ui::mojom::BrowserColorVariant::kNeutral; + break; + case CEF_COLOR_VARIANT_VIBRANT: + ui_variant = ui::mojom::BrowserColorVariant::kVibrant; + break; + case CEF_COLOR_VARIANT_EXPRESSIVE: + ui_variant = ui::mojom::BrowserColorVariant::kExpressive; + break; + case CEF_COLOR_VARIANT_SYSTEM: + ui_variant = ui::mojom::BrowserColorVariant::kSystem; + break; + default: + ui_variant = ui::mojom::BrowserColorVariant::kTonalSpot; + break; + } + + if (!current_color || *current_color != user_color || + ui_variant != theme_service->GetBrowserColorVariant()) { + // User color and/or variant has changed. + // Based on ThemeColorPickerHandler::SetSeedColor. + if (features::IsChromeWebuiRefresh2023()) { + theme_service->SetUserColorAndBrowserColorVariant(user_color, + ui_variant); + theme_service->UseDeviceTheme(false); + } else { + theme_service->BuildAutogeneratedThemeFromColor(user_color); + } + } + } +} + void CefRequestContextImpl::InitializeCookieManagerInternal( CefRefPtr cookie_manager, CefRefPtr callback) { diff --git a/libcef/browser/request_context_impl.h b/libcef/browser/request_context_impl.h index e4652830a..804c1c843 100644 --- a/libcef/browser/request_context_impl.h +++ b/libcef/browser/request_context_impl.h @@ -131,6 +131,11 @@ class CefRequestContextImpl : public CefRequestContext { const CefString& top_level_url, cef_content_setting_types_t content_type, cef_content_setting_values_t value) override; + void SetChromeColorScheme(cef_color_variant_t variant, + cef_color_t user_color) override; + cef_color_variant_t GetChromeColorSchemeMode() override; + cef_color_t GetChromeColorSchemeColor() override; + cef_color_variant_t GetChromeColorSchemeVariant() override; const CefRequestContextSettings& settings() const { return config_.settings; } @@ -205,6 +210,10 @@ class CefRequestContextImpl : public CefRequestContext { cef_content_setting_types_t content_type, cef_content_setting_values_t value, CefBrowserContext::Getter browser_context_getter); + void SetChromeColorSchemeInternal( + cef_color_variant_t variant, + cef_color_t user_color, + CefBrowserContext::Getter browser_context_getter); void InitializeCookieManagerInternal( CefRefPtr cookie_manager, diff --git a/libcef/browser/views/browser_platform_delegate_views.cc b/libcef/browser/views/browser_platform_delegate_views.cc index fc5af6b82..9f4357a73 100644 --- a/libcef/browser/views/browser_platform_delegate_views.cc +++ b/libcef/browser/views/browser_platform_delegate_views.cc @@ -80,6 +80,7 @@ void CefBrowserPlatformDelegateViews::WebContentsCreated( void CefBrowserPlatformDelegateViews::WebContentsDestroyed( content::WebContents* web_contents) { CefBrowserPlatformDelegateAlloy::WebContentsDestroyed(web_contents); + browser_view_->WebContentsCreated(web_contents); native_delegate_->WebContentsDestroyed(web_contents); } diff --git a/libcef/browser/views/browser_view_impl.cc b/libcef/browser/views/browser_view_impl.cc index 42df08b46..abbfc7df2 100644 --- a/libcef/browser/views/browser_view_impl.cc +++ b/libcef/browser/views/browser_view_impl.cc @@ -13,8 +13,10 @@ #include "libcef/browser/context.h" #include "libcef/browser/request_context_impl.h" #include "libcef/browser/thread_util.h" +#include "libcef/browser/views/widget.h" #include "libcef/browser/views/window_impl.h" +#include "chrome/browser/profiles/profile.h" #include "content/public/common/input/native_web_keyboard_event.h" #include "ui/content_accelerators/accelerator_util.h" @@ -111,6 +113,16 @@ void CefBrowserViewImpl::WebContentsCreated( } } +void CefBrowserViewImpl::WebContentsDestroyed( + content::WebContents* web_contents) { + // This will always be called before BrowserDestroyed(). + DisassociateFromWidget(); + + if (web_view()) { + web_view()->SetWebContents(nullptr); + } +} + void CefBrowserViewImpl::BrowserCreated( CefBrowserHostBase* browser, base::RepeatingClosure on_bounds_changed) { @@ -122,9 +134,9 @@ void CefBrowserViewImpl::BrowserDestroyed(CefBrowserHostBase* browser) { DCHECK_EQ(browser, browser_); browser_ = nullptr; - if (web_view()) { - web_view()->SetWebContents(nullptr); - } + // If this BrowserView belonged to a Widget then we expect to have received a + // call to DisassociateFromWidget(). + DCHECK(!cef_widget_); } bool CefBrowserViewImpl::HandleKeyboardEvent( @@ -230,6 +242,28 @@ void CefBrowserViewImpl::OnBrowserViewAdded() { } } +void CefBrowserViewImpl::AddedToWidget() { + DCHECK(!cef_widget_); + DCHECK(browser_); + + views::Widget* widget = root_view()->GetWidget(); + DCHECK(widget); + cef_widget_ = CefWidget::GetForWidget(widget); + DCHECK(cef_widget_); + + profile_ = Profile::FromBrowserContext(browser_->GetBrowserContext()); + DCHECK(profile_); + + // May call Widget::ThemeChanged(). + cef_widget_->AddAssociatedProfile(profile_); +} + +void CefBrowserViewImpl::RemovedFromWidget() { + // With Chrome runtime this may be called after BrowserDestroyed(), in which + // case the following call will be a no-op. + DisassociateFromWidget(); +} + void CefBrowserViewImpl::OnBoundsChanged() { if (!on_bounds_changed_.is_null()) { on_bounds_changed_.Run(); @@ -369,3 +403,14 @@ bool CefBrowserViewImpl::HandleAccelerator( void CefBrowserViewImpl::RequestFocusInternal() { ParentClass::RequestFocus(); } + +void CefBrowserViewImpl::DisassociateFromWidget() { + if (!cef_widget_) { + return; + } + + // May call Widget::ThemeChanged(). + cef_widget_->RemoveAssociatedProfile(profile_); + cef_widget_ = nullptr; + profile_ = nullptr; +} diff --git a/libcef/browser/views/browser_view_impl.h b/libcef/browser/views/browser_view_impl.h index bada6bf90..a2714ff8e 100644 --- a/libcef/browser/views/browser_view_impl.h +++ b/libcef/browser/views/browser_view_impl.h @@ -18,8 +18,10 @@ #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h" class CefBrowserHostBase; +class CefWidget; class CefWindowImpl; class ChromeBrowserView; +class Profile; class CefBrowserViewImpl : public CefViewImpl, @@ -48,8 +50,9 @@ class CefBrowserViewImpl const CefBrowserSettings& settings, CefRefPtr delegate); - // Called from CefBrowserPlatformDelegateViews. + // Called from CefBrowserPlatformDelegate[Chrome]Views. void WebContentsCreated(content::WebContents* web_contents); + void WebContentsDestroyed(content::WebContents* web_contents); void BrowserCreated(CefBrowserHostBase* browser, base::RepeatingClosure on_bounds_changed); void BrowserDestroyed(CefBrowserHostBase* browser); @@ -75,6 +78,8 @@ class CefBrowserViewImpl // CefBrowserViewView::Delegate methods: void OnBrowserViewAdded() override; + void AddedToWidget() override; + void RemovedFromWidget() override; void OnBoundsChanged() override; bool OnGestureEvent(ui::GestureEvent* event) override; @@ -115,6 +120,8 @@ class CefBrowserViewImpl void RequestFocusInternal(); + void DisassociateFromWidget(); + std::unique_ptr pending_browser_create_params_; CefRefPtr browser_; @@ -124,6 +131,9 @@ class CefBrowserViewImpl base::RepeatingClosure on_bounds_changed_; + CefWidget* cef_widget_ = nullptr; + Profile* profile_ = nullptr; + base::WeakPtrFactory weak_ptr_factory_; IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefBrowserViewImpl); diff --git a/libcef/browser/views/browser_view_view.cc b/libcef/browser/views/browser_view_view.cc index 2de10aee2..7069f22d8 100644 --- a/libcef/browser/views/browser_view_view.cc +++ b/libcef/browser/views/browser_view_view.cc @@ -45,3 +45,13 @@ void CefBrowserViewView::OnGestureEvent(ui::GestureEvent* event) { } ParentClass::OnGestureEvent(event); } + +void CefBrowserViewView::AddedToWidget() { + ParentClass::AddedToWidget(); + browser_view_delegate_->AddedToWidget(); +} + +void CefBrowserViewView::RemovedFromWidget() { + ParentClass::RemovedFromWidget(); + browser_view_delegate_->RemovedFromWidget(); +} diff --git a/libcef/browser/views/browser_view_view.h b/libcef/browser/views/browser_view_view.h index 123da8f0d..b86c009a0 100644 --- a/libcef/browser/views/browser_view_view.h +++ b/libcef/browser/views/browser_view_view.h @@ -38,6 +38,10 @@ class CefBrowserViewView // Called when the BrowserView has been added to a parent view. virtual void OnBrowserViewAdded() = 0; + // Called when the BrowserView is added or removed from a Widget. + virtual void AddedToWidget() = 0; + virtual void RemovedFromWidget() = 0; + // Called when the BrowserView bounds have changed. virtual void OnBoundsChanged() = 0; @@ -59,6 +63,8 @@ class CefBrowserViewView const views::ViewHierarchyChangedDetails& details) override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void OnGestureEvent(ui::GestureEvent* event) override; + void AddedToWidget() override; + void RemovedFromWidget() override; private: // Not owned by this object. diff --git a/libcef/browser/views/button_impl.h b/libcef/browser/views/button_impl.h index 7a4c3385c..db6ab50cd 100644 --- a/libcef/browser/views/button_impl.h +++ b/libcef/browser/views/button_impl.h @@ -79,13 +79,14 @@ CEF_BUTTON_IMPL_T cef_button_state_t CEF_BUTTON_IMPL_D::GetState() { CEF_BUTTON_IMPL_T void CEF_BUTTON_IMPL_D::SetInkDropEnabled(bool enabled) { CEF_REQUIRE_VALID_RETURN_VOID(); - views::InkDrop::Get(ParentClass::root_view()) - ->SetMode(enabled ? views::InkDropHost::InkDropMode::ON - : views::InkDropHost::InkDropMode::OFF); + auto* inkdrop = views::InkDrop::Get(ParentClass::root_view()); + inkdrop->SetMode(enabled ? views::InkDropHost::InkDropMode::ON + : views::InkDropHost::InkDropMode::OFF); if (enabled) { - views::InkDrop::Get(ParentClass::root_view()) - ->SetBaseColor(color_utils::BlendTowardMaxContrast( - ParentClass::GetBackgroundColor(), 0x61)); + // Never returns an empty value. + const auto& color = view_util::GetBackgroundColor( + ParentClass::root_view(), /*allow_transparent=*/false); + inkdrop->SetBaseColor(color_utils::BlendTowardMaxContrast(*color, 0x61)); } } diff --git a/libcef/browser/views/button_view.h b/libcef/browser/views/button_view.h index 04441ccb6..1504860ce 100644 --- a/libcef/browser/views/button_view.h +++ b/libcef/browser/views/button_view.h @@ -12,6 +12,7 @@ #include "libcef/browser/views/view_view.h" #include "base/logging.h" +#include "ui/gfx/color_utils.h" #include "ui/views/animation/ink_drop.h" #include "ui/views/controls/button/button.h" @@ -41,6 +42,9 @@ CEF_BUTTON_VIEW_T class CefButtonView : public CEF_VIEW_VIEW_D { return button; } + // views::View methods: + void OnThemeChanged() override; + // views::Button methods: void StateChanged(views::Button::ButtonState old_state) override; @@ -48,6 +52,18 @@ CEF_BUTTON_VIEW_T class CefButtonView : public CEF_VIEW_VIEW_D { void ButtonPressed(const ui::Event& event) override; }; +CEF_BUTTON_VIEW_T void CEF_BUTTON_VIEW_D::OnThemeChanged() { + ParentClass::OnThemeChanged(); + + auto* inkdrop = views::InkDrop::Get(this); + if (inkdrop->ink_drop_mode() != views::InkDropHost::InkDropMode::OFF) { + // Never returns an empty value. + const auto& color = + view_util::GetBackgroundColor(this, /*allow_transparent=*/false); + inkdrop->SetBaseColor(color_utils::BlendTowardMaxContrast(*color, 0x61)); + } +} + CEF_BUTTON_VIEW_T void CEF_BUTTON_VIEW_D::StateChanged( views::Button::ButtonState old_state) { ParentClass::StateChanged(old_state); diff --git a/libcef/browser/views/color_provider_tracker.cc b/libcef/browser/views/color_provider_tracker.cc new file mode 100644 index 000000000..720e379ef --- /dev/null +++ b/libcef/browser/views/color_provider_tracker.cc @@ -0,0 +1,28 @@ +// Copyright 2024 The Chromium Embedded Framework Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +#include "libcef/browser/views/color_provider_tracker.h" + +#include "base/check.h" + +CefColorProviderTracker::CefColorProviderTracker(Observer* observer) + : observer_(observer) { + DCHECK(observer_); + color_provider_observation_.Observe(&ui::ColorProviderManager::Get()); +} + +void CefColorProviderTracker::OnNativeThemeUpdated() { + got_theme_updated_ = true; +} + +void CefColorProviderTracker::OnColorProviderCacheReset() { + // May be followed by a call to OnNativeThemeUpdated. + got_theme_updated_ = false; +} + +void CefColorProviderTracker::OnAfterNativeThemeUpdated() { + if (!got_theme_updated_) { + observer_->OnColorProviderCacheResetMissed(); + } +} diff --git a/libcef/browser/views/color_provider_tracker.h b/libcef/browser/views/color_provider_tracker.h new file mode 100644 index 000000000..692656987 --- /dev/null +++ b/libcef/browser/views/color_provider_tracker.h @@ -0,0 +1,63 @@ +// Copyright 2024 The Chromium Embedded Framework Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +#ifndef CEF_LIBCEF_BROWSER_VIEWS_COLOR_PROVIDER_TRACKER_H_ +#define CEF_LIBCEF_BROWSER_VIEWS_COLOR_PROVIDER_TRACKER_H_ +#pragma once + +#include "base/scoped_observation.h" +#include "ui/color/color_provider_manager.h" + +// Color registrations are managed by the global ColorProviderManager object. +// When the system theme changes (e.g. NativeThemeWin::UpdateDarkModeStatus or +// NativeThemeWin::OnSysColorChange is called) all existing platform NativeTheme +// objects (NativeTheme[Win|Mac|Gtk]) are notified. They then call +// NativeTheme::NotifyOnNativeThemeUpdated which calls +// ColorProviderManager::ResetColorProviderCache, followed by +// OnNativeThemeUpdated for each registered Widget, followed by +// ColorProviderManager::AfterNativeThemeUpdated. The problem is that Chromium +// creates multiple NativeTheme objects but each Widget only registers as an +// Observer for the one returned via Widget::GetNativeTheme. If a different +// NativeTheme is the last caller of ResetColorProviderCache then we don't get +// an opportunity to reapply global color overrides in the Widget's +// OnNativeThemeChanged callback. To work around this problem each Widget owns a +// Tracker object. The Tracker explicitly registers as an Observer on the +// ColorProviderManager to get callbacks from ResetColorProviderCache and +// AfterNativeThemeUpdated. If OnNativeThemeUpdated is not called for the Widget +// (which otherwise forwards the call to the Tracker) then the Tracker will call +// OnColorProviderCacheResetMissed from OnAfterNativeThemeUpdated. +class CefColorProviderTracker : public ui::ColorProviderManagerObserver { + public: + class Observer { + public: + // Called when the color provider cache is reset without a follow-up call to + // OnNativeThemeUpdated. + virtual void OnColorProviderCacheResetMissed() {} + + protected: + virtual ~Observer() = default; + }; + + explicit CefColorProviderTracker(Observer* observer); + + CefColorProviderTracker(const CefColorProviderTracker&) = delete; + CefColorProviderTracker& operator=(const CefColorProviderTracker&) = delete; + + // Notify us when OnNativeThemeUpdated is called. + void OnNativeThemeUpdated(); + + private: + // ui::ColorProviderManagerObserver methods: + void OnColorProviderCacheReset() override; + void OnAfterNativeThemeUpdated() override; + + Observer* const observer_; + + bool got_theme_updated_ = false; + base::ScopedObservation + color_provider_observation_{this}; +}; + +#endif // CEF_LIBCEF_BROWSER_VIEWS_COLOR_PROVIDER_TRACKER_H_ diff --git a/libcef/browser/views/view_impl.h b/libcef/browser/views/view_impl.h index 2162bca57..78b5e5fd3 100644 --- a/libcef/browser/views/view_impl.h +++ b/libcef/browser/views/view_impl.h @@ -298,6 +298,7 @@ #include "base/json/json_writer.h" #include "base/logging.h" #include "base/values.h" +#include "ui/gfx/color_palette.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/view.h" @@ -403,6 +404,7 @@ CEF_VIEW_IMPL_T class CefViewImpl : public CefViewAdapter, public CefViewClass { void RequestFocus() override; void SetBackgroundColor(cef_color_t color) override; cef_color_t GetBackgroundColor() override; + cef_color_t GetThemeColor(int color_id) override; bool ConvertPointToScreen(CefPoint& point) override; bool ConvertPointFromScreen(CefPoint& point) override; bool ConvertPointToWindow(CefPoint& point) override; @@ -679,11 +681,19 @@ CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetBackgroundColor(cef_color_t color) { } CEF_VIEW_IMPL_T cef_color_t CEF_VIEW_IMPL_D::GetBackgroundColor() { - CEF_REQUIRE_VALID_RETURN(0U); - if (root_view()->background()) { - return root_view()->background()->get_color(); + CEF_REQUIRE_VALID_RETURN(gfx::kPlaceholderColor); + // May return an empty value. + const auto& color = + view_util::GetBackgroundColor(root_view(), /*allow_transparency=*/true); + if (color) { + return *color; } - return view_util::GetColor(root_view(), ui::kColorPrimaryBackground); + return SK_ColorTRANSPARENT; +} + +CEF_VIEW_IMPL_T cef_color_t CEF_VIEW_IMPL_D::GetThemeColor(int color_id) { + CEF_REQUIRE_VALID_RETURN(gfx::kPlaceholderColor); + return view_util::GetColor(root_view(), color_id); } CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::ConvertPointToScreen(CefPoint& point) { diff --git a/libcef/browser/views/view_util.cc b/libcef/browser/views/view_util.cc index f4438c6f3..bdf543e38 100644 --- a/libcef/browser/views/view_util.cc +++ b/libcef/browser/views/view_util.cc @@ -8,7 +8,10 @@ #include "include/cef_color_ids.h" #include "libcef/browser/views/view_adapter.h" +#include "libcef/browser/views/widget.h" +#include "chrome/browser/themes/theme_service.h" +#include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/ui/color/chrome_color_id.h" #include "ui/color/color_provider.h" #include "ui/color/color_provider_manager.h" @@ -17,6 +20,7 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_conversions.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/background.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/window/non_client_view.h" @@ -343,7 +347,7 @@ bool ConvertPointFromWindow(views::View* view, gfx::Point* point) { return true; } -SkColor GetColor(views::View* view, ui::ColorId id) { +SkColor GetColor(const views::View* view, ui::ColorId id) { // Verify that our enum matches Chromium's values. static_assert(static_cast(CEF_ChromeColorsEnd) == static_cast(kChromeColorsEnd), @@ -351,11 +355,64 @@ SkColor GetColor(views::View* view, ui::ColorId id) { // |color_provider| will be nullptr if |view| has not yet been added to a // Widget. - if (auto color_provider = view->GetColorProvider()) { + if (const auto* color_provider = view->GetColorProvider()) { return color_provider->GetColor(id); } return GetDefaultColorProvider()->GetColor(id); } +void SetColor(views::View* view, ui::ColorId id, SkColor color) { + auto* color_provider = view->GetColorProvider(); + if (!color_provider) { + color_provider = GetDefaultColorProvider(); + } + + if (color_provider) { + color_provider->SetColorForTesting(id, color); + } +} + +std::optional GetBackgroundColor(const views::View* view, + bool allow_transparent) { + // Return the configured background color, if any. + if (view->background()) { + return view->background()->get_color(); + } + + // If the containing Widget is an overlay then it has a transparent background + // by default. + if (allow_transparent) { + const bool is_overlay_hosted = + view->GetWidget() && GetHostView(view->GetWidget()) != nullptr; + if (is_overlay_hosted) { + return std::nullopt; + } + } + + // Return the default background color. + return GetColor(view, ui::kColorPrimaryBackground); +} + +bool ShouldUseDarkTheme(views::Widget* widget) { + DCHECK(widget); + + Profile* profile = nullptr; + if (auto* cef_widget = CefWidget::GetForWidget(widget)) { + profile = cef_widget->GetThemeProfile(); + } + + if (profile) { + const auto* theme_service = ThemeServiceFactory::GetForProfile(profile); + const auto browser_color_scheme = theme_service->GetBrowserColorScheme(); + if (browser_color_scheme != ThemeService::BrowserColorScheme::kSystem) { + // Override the native theme value. + return browser_color_scheme == ThemeService::BrowserColorScheme::kDark; + } + } + + // Use the native theme value. + return widget->GetNativeTheme()->ShouldUseDarkColors(); +} + } // namespace view_util diff --git a/libcef/browser/views/view_util.h b/libcef/browser/views/view_util.h index e08e6f79d..0985070db 100644 --- a/libcef/browser/views/view_util.h +++ b/libcef/browser/views/view_util.h @@ -6,6 +6,8 @@ #define CEF_LIBCEF_BROWSER_VIEWS_VIEW_UTIL_H_ #pragma once +#include + #include "include/views/cef_view.h" #include "include/views/cef_window.h" @@ -159,16 +161,33 @@ views::NativeWidget* CreateNativeWidget( // whose position in the view hierarchy determines the z-order of the widget // relative to views with layers and views with associated NativeViews. void SetHostView(views::Widget* widget, views::View* host_view); -views::View* GetHostView(views::Widget* widget); +views::View* GetHostView(const views::Widget* widget); #if BUILDFLAG(IS_MAC) float GetNSWindowTitleBarHeight(views::Widget* widget); #endif // Returns the mixer color for |id|. If |view| has been added to a Widget it -// will use the Widget's ColorProvider, otherwise it will use the default theme +// will use the Widget's ColorProvider, otherwise it will use the global theme // ColorProvider. Returns gfx::kPlaceholderColor if |id| cannot be constructed. -SkColor GetColor(views::View* view, ui::ColorId id); +SkColor GetColor(const views::View* view, ui::ColorId id); + +// Sets the color associated with |id|. If |view| has been added to a Widget it +// will use the Widget's ColorProvider, otherwise it will use the global theme +// ColorProvider. +void SetColor(views::View* view, ui::ColorId id, SkColor color); + +// Returns the currently configured background color for |view|. If +// |allow_transparent| is true then it may return an empty value to indicate +// transparency. +std::optional GetBackgroundColor(const views::View* view, + bool allow_transparent); + +// Returns true if dark theme should be used for |widget|. +bool ShouldUseDarkTheme(views::Widget* widget); + +// Updates the titlebar light/dark theme for |widget|. +void UpdateTitlebarTheme(views::Widget* widget); } // namespace view_util diff --git a/libcef/browser/views/view_util_aura.cc b/libcef/browser/views/view_util_aura.cc index 24be3311b..d5b7baa52 100644 --- a/libcef/browser/views/view_util_aura.cc +++ b/libcef/browser/views/view_util_aura.cc @@ -11,6 +11,13 @@ #include "ui/views/widget/native_widget_delegate.h" #include "ui/views/widget/widget.h" +#if BUILDFLAG(IS_WIN) +#include + +#include "base/win/windows_version.h" +#include "ui/views/win/hwnd_util.h" +#endif + namespace view_util { gfx::NativeWindow GetNativeWindow(views::Widget* widget) { @@ -54,8 +61,79 @@ void SetHostView(views::Widget* widget, views::View* host_view) { widget->GetNativeView()->SetProperty(views::kHostViewKey, host_view); } -views::View* GetHostView(views::Widget* widget) { +views::View* GetHostView(const views::Widget* widget) { return widget->GetNativeView()->GetProperty(views::kHostViewKey); } +void UpdateTitlebarTheme(views::Widget* widget) { +#if BUILDFLAG(IS_WIN) + // Value was 19 prior to Windows 10 20H1, according to + // https://stackoverflow.com/a/70693198 + const DWORD dwAttribute = + base::win::GetVersion() >= base::win::Version::WIN10_20H1 + ? DWMWA_USE_IMMERSIVE_DARK_MODE + : 19; + + const HWND widget_hwnd = views::HWNDForWidget(widget); + + BOOL has_dark_titlebar = FALSE; + DwmGetWindowAttribute(widget_hwnd, dwAttribute, &has_dark_titlebar, + sizeof(has_dark_titlebar)); + + const BOOL dark_titlebar_enabled = ShouldUseDarkTheme(widget); + if (has_dark_titlebar == dark_titlebar_enabled) { + // No change required. + return; + } + + // From BrowserFrameViewWin::SetSystemMicaTitlebarAttributes. + DwmSetWindowAttribute(widget_hwnd, dwAttribute, &dark_titlebar_enabled, + sizeof(dark_titlebar_enabled)); + + // Repaint the titlebar if the Widget is visible. None of the usual NC + // repaint techniques work with DwmSetWindowAttribute so use a workaround + // that nudges the window width. + // See https://stackoverflow.com/a/78269906/23991994 + if (IsWindowVisible(widget_hwnd) && !IsIconic(widget_hwnd)) { + RECT rect = {}; + ::GetWindowRect(widget_hwnd, &rect); + + if (IsZoomed(widget_hwnd)) { + // Window is currently maximized. Restore and then re-maximize the + // window. The restore position is changed temporarily to make the + // update less noticeable. + WINDOWPLACEMENT placement = {}; + GetWindowPlacement(widget_hwnd, &placement); + + const RECT oldrect = placement.rcNormalPosition; + + placement.rcNormalPosition = rect; + placement.rcNormalPosition.right -= 1; + SetWindowPlacement(widget_hwnd, &placement); + + LockWindowUpdate(widget_hwnd); + ShowWindow(widget_hwnd, SW_SHOWNORMAL); + ShowWindow(widget_hwnd, SW_SHOWMAXIMIZED); + LockWindowUpdate(nullptr); + + placement.rcNormalPosition = oldrect; + SetWindowPlacement(widget_hwnd, &placement); + } else { + // Window is currently normal. Change and then restore the window width. + // Use Defer functions to make the update less noticeable. + HDWP defer = BeginDeferWindowPos(2); + DeferWindowPos(defer, widget_hwnd, NULL, 0, 0, rect.right - rect.left - 1, + rect.bottom - rect.top, + SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + DeferWindowPos(defer, widget_hwnd, NULL, 0, 0, rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + LockWindowUpdate(widget_hwnd); + EndDeferWindowPos(defer); + LockWindowUpdate(nullptr); + } + } +#endif // BUILDFLAG(IS_WIN) +} + } // namespace view_util diff --git a/libcef/browser/views/view_util_mac.mm b/libcef/browser/views/view_util_mac.mm index 903505df1..cedadeb63 100644 --- a/libcef/browser/views/view_util_mac.mm +++ b/libcef/browser/views/view_util_mac.mm @@ -20,6 +20,13 @@ constexpr char kNativeHostViewKey[] = "CefNativeHostViewKey"; // For Venura 13.3.1. constexpr float kDefaultTitleBarHeight = 30; +NSWindow* GetNSWindow(views::Widget* widget) { + if (const auto& window = GetNativeWindow(widget)) { + return window.GetNativeNSWindow(); + } + return nil; +} + } // namespace gfx::NativeWindow GetNativeWindow(views::Widget* widget) { @@ -65,18 +72,33 @@ void SetHostView(views::Widget* widget, views::View* host_view) { widget->SetNativeWindowProperty(kNativeHostViewKey, host_view); } -views::View* GetHostView(views::Widget* widget) { +views::View* GetHostView(const views::Widget* widget) { return static_cast( widget->GetNativeWindowProperty(kNativeHostViewKey)); } float GetNSWindowTitleBarHeight(views::Widget* widget) { - if (auto window = GetNativeWindow(widget)) { - NSWindow* nswindow = window.GetNativeNSWindow(); - return nswindow.frame.size.height - - [nswindow contentRectForFrameRect:nswindow.frame].size.height; + if (NSWindow* window = GetNSWindow(widget)) { + return window.frame.size.height - + [window contentRectForFrameRect:window.frame].size.height; } return kDefaultTitleBarHeight; } +void UpdateTitlebarTheme(views::Widget* widget) { + NSWindow* window = GetNSWindow(widget); + if (!window) { + return; + } + + auto* light = [NSAppearance appearanceNamed:NSAppearanceNameAqua]; + auto* dark = [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]; + + const bool should_use_dark = ShouldUseDarkTheme(widget); + auto* desired = should_use_dark ? dark : light; + if (window.appearance != desired) { + window.appearance = desired; + } +} + } // namespace view_util diff --git a/libcef/browser/views/view_view.h b/libcef/browser/views/view_view.h index 6a07e2582..c51a41a6d 100644 --- a/libcef/browser/views/view_view.h +++ b/libcef/browser/views/view_view.h @@ -225,17 +225,13 @@ CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::OnThemeChanged() { cef_delegate()->OnThemeChanged(GetCefView()); } - // If the background is still unset, and the containing Widget is not an - // overlay (which has transparent background), then set the background based - // on the current theme. + // If the background is still unset then possibly set it to the desired value. if (!ParentClass::background()) { - const bool is_overlay_hosted = - ParentClass::GetWidget() && - view_util::GetHostView(ParentClass::GetWidget()) != nullptr; - if (!is_overlay_hosted) { - const SkColor color = - view_util::GetColor(this, ui::kColorPrimaryBackground); - ParentClass::SetBackground(views::CreateSolidBackground(color)); + // May return an empty value. + const auto& color = + view_util::GetBackgroundColor(this, /*allow_transparent=*/true); + if (color) { + ParentClass::SetBackground(views::CreateSolidBackground(*color)); } } } diff --git a/libcef/browser/views/widget.cc b/libcef/browser/views/widget.cc new file mode 100644 index 000000000..ebd2b1fa2 --- /dev/null +++ b/libcef/browser/views/widget.cc @@ -0,0 +1,24 @@ +// Copyright 2024 The Chromium Embedded Framework Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +#include "libcef/browser/views/widget.h" + +#include "libcef/browser/chrome/views/chrome_browser_frame.h" +#include "libcef/browser/views/widget_impl.h" + +// static +CefWidget* CefWidget::Create(CefWindowView* window_view) { + if (cef::IsChromeRuntimeEnabled()) { + return new ChromeBrowserFrame(window_view); + } + return new CefWidgetImpl(window_view); +} + +// static +CefWidget* CefWidget::GetForWidget(views::Widget* widget) { + if (cef::IsChromeRuntimeEnabled()) { + return static_cast(widget); + } + return static_cast(widget); +} diff --git a/libcef/browser/views/widget.h b/libcef/browser/views/widget.h new file mode 100644 index 000000000..647aceffd --- /dev/null +++ b/libcef/browser/views/widget.h @@ -0,0 +1,60 @@ +// Copyright 2024 The Chromium Embedded Framework Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +#ifndef CEF_LIBCEF_BROWSER_VIEWS_WIDGET_H_ +#define CEF_LIBCEF_BROWSER_VIEWS_WIDGET_H_ +#pragma once + +class CefWindowView; +class Profile; + +namespace views { +class Widget; +} + +// Interface that provides access to common CEF-specific Widget functionality. +// Alloy and Chrome runtimes use different views::Widget inheritance so we can't +// cast types directly. Implemented by CefWidgetImpl for the Alloy runtime and +// ChromeBrowserFrame for the Chrome runtime. +class CefWidget { + public: + // Called from CefWindowView::CreateWidget. + static CefWidget* Create(CefWindowView* window_view); + + // Returns the CefWidget for |widget|, which must be Views-hosted. + static CefWidget* GetForWidget(views::Widget* widget); + + // Returns the Widget associated with this object. + virtual views::Widget* GetWidget() = 0; + virtual const views::Widget* GetWidget() const = 0; + + // Called from CefWindowView::CreateWidget after Widget::Init. There will be + // no theme-related callbacks prior to this method being called. + virtual void Initialized() = 0; + + // Returns true if Initialize() has been called. + virtual bool IsInitialized() const = 0; + + // Track all Profiles associated with this Widget. Called from + // CefBrowserViewImpl::AddedToWidget and DisassociateFromWidget. + // |profile| is only used with the Alloy runtime. + virtual void AddAssociatedProfile(Profile* profile) = 0; + virtual void RemoveAssociatedProfile(Profile* profile) = 0; + + // Returns the Profile that will be used for Chrome theme purposes. Chrome + // runtime supports a single BrowserView in a single Widget. Alloy runtime + // supports multiple BrowserViews in a single Widget, and those BrowserViews + // may have different Profiles. If there are multiple Profiles we return an + // arbitrary one. The returned Profile will remain consistent until the set of + // associated Profiles changes. + virtual Profile* GetThemeProfile() const = 0; + + // Optional special handling to toggle full-screen mode. + virtual bool ToggleFullscreenMode() { return false; } + + protected: + virtual ~CefWidget() = default; +}; + +#endif // CEF_LIBCEF_BROWSER_VIEWS_WIDGET_H_ diff --git a/libcef/browser/views/widget_impl.cc b/libcef/browser/views/widget_impl.cc new file mode 100644 index 000000000..404f9bf98 --- /dev/null +++ b/libcef/browser/views/widget_impl.cc @@ -0,0 +1,261 @@ +// Copyright 2024 The Chromium Embedded Framework Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +#include "libcef/browser/views/widget_impl.h" + +#include "libcef/browser/views/window_view.h" +#include "libcef/features/runtime.h" + +#include "chrome/browser/themes/custom_theme_supplier.h" +#include "chrome/browser/themes/theme_service.h" +#include "chrome/browser/themes/theme_service_factory.h" + +#if BUILDFLAG(IS_LINUX) +#include "ui/linux/linux_ui.h" +#endif + +namespace { + +ui::ColorProviderKey::SchemeVariant GetSchemeVariant( + ui::mojom::BrowserColorVariant color_variant) { + using BCV = ui::mojom::BrowserColorVariant; + using SV = ui::ColorProviderKey::SchemeVariant; + static constexpr auto kSchemeVariantMap = base::MakeFixedFlatMap({ + {BCV::kTonalSpot, SV::kTonalSpot}, + {BCV::kNeutral, SV::kNeutral}, + {BCV::kVibrant, SV::kVibrant}, + {BCV::kExpressive, SV::kExpressive}, + }); + return kSchemeVariantMap.at(color_variant); +} + +} // namespace + +CefWidgetImpl::CefWidgetImpl(CefWindowView* window_view) + : window_view_(window_view) {} + +CefWidgetImpl::~CefWidgetImpl() { + DCHECK(associated_profiles_.empty()); +} + +void CefWidgetImpl::Initialized() { + initialized_ = true; + + // Based on BrowserFrame::InitBrowserFrame. + // This is the first call that will trigger theme-related client callbacks. +#if BUILDFLAG(IS_LINUX) + // Calls ThemeChanged() or OnNativeThemeUpdated(). + SelectNativeTheme(); +#else + // Calls ThemeChanged(). + SetNativeTheme(ui::NativeTheme::GetInstanceForNativeUi()); +#endif +} + +void CefWidgetImpl::AddAssociatedProfile(Profile* profile) { + DCHECK(profile); + ProfileMap::iterator it = associated_profiles_.find(profile); + if (it != associated_profiles_.end()) { + // Another instance of a known Profile. + (it->second)++; + return; + } + + auto* current_profile = GetThemeProfile(); + + associated_profiles_.insert(std::make_pair(profile, 1)); + + if (auto* theme_service = ThemeServiceFactory::GetForProfile(profile)) { + theme_service->AddObserver(this); + } + + auto* new_profile = GetThemeProfile(); + if (new_profile != current_profile) { + // Switching to a different theme. + NotifyThemeColorsChanged(/*chrome_theme=*/!!new_profile, + /*call_theme_changed=*/true); + } +} + +void CefWidgetImpl::RemoveAssociatedProfile(Profile* profile) { + DCHECK(profile); + ProfileMap::iterator it = associated_profiles_.find(profile); + if (it == associated_profiles_.end()) { + DCHECK(false); // Not reached. + return; + } + if (--(it->second) > 0) { + // More instances of the Profile exist. + return; + } + + auto* current_profile = GetThemeProfile(); + + associated_profiles_.erase(it); + + if (auto* theme_service = ThemeServiceFactory::GetForProfile(profile)) { + theme_service->RemoveObserver(this); + } + + auto* new_profile = GetThemeProfile(); + if (new_profile != current_profile) { + // Switching to a different theme. + NotifyThemeColorsChanged(/*chrome_theme=*/!!new_profile, + /*call_theme_changed=*/true); + } +} + +Profile* CefWidgetImpl::GetThemeProfile() const { + if (!associated_profiles_.empty()) { + return associated_profiles_.begin()->first; + } + return nullptr; +} + +const ui::ThemeProvider* CefWidgetImpl::GetThemeProvider() const { + auto* profile = GetThemeProfile(); + if (!profile) { + return Widget::GetThemeProvider(); + } + + // Based on BrowserFrame::GetThemeProvider. + return &ThemeService::GetThemeProviderForProfile(profile); +} + +ui::ColorProviderKey::ThemeInitializerSupplier* CefWidgetImpl::GetCustomTheme() + const { + auto* profile = GetThemeProfile(); + if (!profile) { + return Widget::GetCustomTheme(); + } + + // Based on BrowserFrame::GetCustomTheme. + auto* theme_service = ThemeServiceFactory::GetForProfile(profile); + return theme_service->UsingDeviceTheme() ? nullptr + : theme_service->GetThemeSupplier(); +} + +void CefWidgetImpl::OnNativeWidgetDestroyed() { + window_view_ = nullptr; + views::Widget::OnNativeWidgetDestroyed(); +} + +void CefWidgetImpl::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) { + // TODO: Reduce the frequency of this callback on Windows/Linux. + // See https://issues.chromium.org/issues/40280130#comment7 + + color_provider_tracker_.OnNativeThemeUpdated(); + + // Native/OS theme changed. + NotifyThemeColorsChanged(/*chrome_theme=*/false, + /*call_theme_changed=*/false); + + // Calls ThemeChanged(). + Widget::OnNativeThemeUpdated(observed_theme); +} + +ui::ColorProviderKey CefWidgetImpl::GetColorProviderKey() const { + auto* profile = GetThemeProfile(); + if (!profile) { + return Widget::GetColorProviderKey(); + } + + // Based on BrowserFrame::GetColorProviderKey. + auto key = Widget::GetColorProviderKey(); + + const auto* theme_service = ThemeServiceFactory::GetForProfile(profile); + CHECK(theme_service); + + // color_mode. + [&key, theme_service]() { + const auto browser_color_scheme = theme_service->GetBrowserColorScheme(); + if (browser_color_scheme != ThemeService::BrowserColorScheme::kSystem) { + key.color_mode = + browser_color_scheme == ThemeService::BrowserColorScheme::kLight + ? ui::ColorProviderKey::ColorMode::kLight + : ui::ColorProviderKey::ColorMode::kDark; + } + }(); + + // user_color. + // Device theme retains the user_color from `Widget`. + if (!theme_service->UsingDeviceTheme()) { + if (theme_service->UsingAutogeneratedTheme()) { + key.user_color = theme_service->GetAutogeneratedThemeColor(); + } else if (auto user_color = theme_service->GetUserColor()) { + key.user_color = user_color; + } + } + + // user_color_source. + if (theme_service->UsingDeviceTheme()) { + key.user_color_source = ui::ColorProviderKey::UserColorSource::kAccent; + } else if (theme_service->GetIsGrayscale()) { + key.user_color_source = ui::ColorProviderKey::UserColorSource::kGrayscale; + } else if (theme_service->GetIsBaseline()) { + key.user_color_source = ui::ColorProviderKey::UserColorSource::kBaseline; + } else { + CHECK(key.user_color.has_value()); + key.user_color_source = ui::ColorProviderKey::UserColorSource::kAccent; + } + + // scheme_variant. + ui::mojom::BrowserColorVariant color_variant = + theme_service->GetBrowserColorVariant(); + if (!theme_service->UsingDeviceTheme() && + color_variant != ui::mojom::BrowserColorVariant::kSystem) { + key.scheme_variant = GetSchemeVariant(color_variant); + } + + // frame_type. + key.frame_type = ui::ColorProviderKey::FrameType::kNative; + + return key; +} + +void CefWidgetImpl::OnThemeChanged() { + // When the Chrome theme changes, the NativeTheme may also change. + SelectNativeTheme(); + + NotifyThemeColorsChanged(/*chrome_theme=*/true, /*call_theme_changed=*/true); +} + +void CefWidgetImpl::NotifyThemeColorsChanged(bool chrome_theme, + bool call_theme_changed) { + if (window_view_) { + window_view_->OnThemeColorsChanged(chrome_theme); + if (call_theme_changed) { + ThemeChanged(); + } + } +} + +void CefWidgetImpl::SelectNativeTheme() { + // Based on BrowserFrame::SelectNativeTheme. +#if BUILDFLAG(IS_LINUX) + ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi(); + + // Always use the NativeTheme for forced color modes. + if (ui::NativeTheme::IsForcedDarkMode() || + ui::NativeTheme::IsForcedLightMode()) { + SetNativeTheme(native_theme); + return; + } + + const auto* linux_ui_theme = + ui::LinuxUiTheme::GetForWindow(GetNativeWindow()); + SetNativeTheme(linux_ui_theme ? linux_ui_theme->GetNativeTheme() + : native_theme); +#endif +} + +void CefWidgetImpl::OnColorProviderCacheResetMissed() { + // Ignore calls during Widget::Init(). + if (!initialized_) { + return; + } + + NotifyThemeColorsChanged(/*chrome_theme=*/false, + /*call_theme_changed=*/true); +} diff --git a/libcef/browser/views/widget_impl.h b/libcef/browser/views/widget_impl.h new file mode 100644 index 000000000..82b83cec4 --- /dev/null +++ b/libcef/browser/views/widget_impl.h @@ -0,0 +1,96 @@ +// Copyright 2024 The Chromium Embedded Framework Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +#ifndef CEF_LIBCEF_BROWSER_VIEWS_WIDGET_IMPL_H_ +#define CEF_LIBCEF_BROWSER_VIEWS_WIDGET_IMPL_H_ +#pragma once + +#include + +#include "libcef/browser/views/color_provider_tracker.h" +#include "libcef/browser/views/widget.h" + +#include "chrome/browser/themes/theme_service_observer.h" +#include "ui/views/widget/widget.h" + +class CefWindowView; +class Profile; + +// Widget specialization to implement theme support for the Alloy runtime. The +// global NativeTheme (native/OS theme) will be used unless this Widget contains +// a BrowserView, in which case a Chrome theme associated with the BrowserView's +// Profile will be used. +// +// Theme support works as follows: +// - OnNativeThemeUpdated is called when the NativeTheme associated with this +// Widget changes. For example, when switching the OS appearance between light +// and dark mode. +// - OnColorProviderCacheResetMissed is called if some other NativeTheme not +// associated with this Widget changes and we need to reapply global color +// overrides (see CefColorProviderTracker for details). +// - OnThemeChanged is called when the client changes the Chrome theme +// explicitly by calling CefRequestContext::SetChromeColorScheme. +// - GetThemeProvider, GetCustomTheme and GetColorProviderKey return objects +// that are used internally to apply the current theme. +// +// Callers should use view_util methods (e.g. GetColor, ShouldUseDarkTheme, etc) +// instead of calling theme-related Widget methods directly. +class CefWidgetImpl : public views::Widget, + public CefWidget, + public CefColorProviderTracker::Observer, + public ThemeServiceObserver { + public: + explicit CefWidgetImpl(CefWindowView* window_view); + ~CefWidgetImpl() override; + + CefWidgetImpl(const CefWidgetImpl&) = delete; + CefWidgetImpl& operator=(const CefWidgetImpl&) = delete; + + // CefWidget methods: + views::Widget* GetWidget() override { return this; } + const views::Widget* GetWidget() const override { return this; } + void Initialized() override; + bool IsInitialized() const override { return initialized_; } + void AddAssociatedProfile(Profile* profile) override; + void RemoveAssociatedProfile(Profile* profile) override; + Profile* GetThemeProfile() const override; + + // views::Widget methods: + const ui::ThemeProvider* GetThemeProvider() const override; + ui::ColorProviderKey::ThemeInitializerSupplier* GetCustomTheme() + const override; + + // NativeWidgetDelegate methods: + void OnNativeWidgetDestroyed() override; + + // ui::NativeThemeObserver methods: + void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override; + ui::ColorProviderKey GetColorProviderKey() const override; + + // ThemeServiceObserver methods: + void OnThemeChanged() override; + + private: + void NotifyThemeColorsChanged(bool chrome_theme, bool call_theme_changed); + + // Select a native theme that is appropriate for the current context. This is + // currently only needed for Linux to switch between the regular NativeTheme + // and the GTK NativeTheme instance. + void SelectNativeTheme(); + + // CefColorProviderTracker::Observer methods: + void OnColorProviderCacheResetMissed() override; + + CefWindowView* window_view_; + + bool initialized_ = false; + + // Map of Profile* to count. + using ProfileMap = std::map; + ProfileMap associated_profiles_; + + CefColorProviderTracker color_provider_tracker_{this}; +}; + +#endif // CEF_LIBCEF_BROWSER_VIEWS_WIDGET_IMPL_H_ diff --git a/libcef/browser/views/window_impl.cc b/libcef/browser/views/window_impl.cc index e7da97228..318234538 100644 --- a/libcef/browser/views/window_impl.cc +++ b/libcef/browser/views/window_impl.cc @@ -7,15 +7,14 @@ #include #include "libcef/browser/browser_util.h" -#include "libcef/browser/chrome/views/chrome_browser_frame.h" #include "libcef/browser/thread_util.h" #include "libcef/browser/views/browser_view_impl.h" #include "libcef/browser/views/display_impl.h" #include "libcef/browser/views/fill_layout_impl.h" #include "libcef/browser/views/layout_util.h" #include "libcef/browser/views/view_util.h" +#include "libcef/browser/views/widget.h" #include "libcef/browser/views/window_view.h" -#include "libcef/features/runtime.h" #include "base/i18n/rtl.h" #include "components/constrained_window/constrained_window_views.h" @@ -254,14 +253,9 @@ void CefWindowImpl::Restore() { void CefWindowImpl::SetFullscreen(bool fullscreen) { CEF_REQUIRE_VALID_RETURN_VOID(); if (widget_ && fullscreen != widget_->IsFullscreen()) { - if (cef::IsChromeRuntimeEnabled()) { - // If a BrowserView exists, toggle fullscreen mode via the Chrome command - // for consistent behavior. - auto* browser_frame = static_cast(widget_); - if (browser_frame->browser_view()) { - browser_frame->ToggleFullscreenMode(); - return; - } + if (CefWidget::GetForWidget(widget_)->ToggleFullscreenMode()) { + // Received special handling. + return; } // Call the Widget method directly with Alloy runtime, or Chrome runtime @@ -741,6 +735,20 @@ void CefWindowImpl::RemoveAllAccelerators() { focus_manager->UnregisterAccelerators(this); } +void CefWindowImpl::SetThemeColor(int color_id, cef_color_t color) { + CEF_REQUIRE_VALID_RETURN_VOID(); + if (root_view()) { + view_util::SetColor(root_view(), color_id, color); + } +} + +void CefWindowImpl::ThemeChanged() { + CEF_REQUIRE_VALID_RETURN_VOID(); + if (widget_) { + widget_->ThemeChanged(); + } +} + CefWindowView* CefWindowImpl::cef_window_view() const { return static_cast(root_view()); } diff --git a/libcef/browser/views/window_impl.h b/libcef/browser/views/window_impl.h index 4129fb021..09566dad9 100644 --- a/libcef/browser/views/window_impl.h +++ b/libcef/browser/views/window_impl.h @@ -91,6 +91,8 @@ class CefWindowImpl bool high_priority) override; void RemoveAccelerator(int command_id) override; void RemoveAllAccelerators() override; + void SetThemeColor(int color_id, cef_color_t color) override; + void ThemeChanged() override; // CefViewAdapter methods: void Detach() override; diff --git a/libcef/browser/views/window_view.cc b/libcef/browser/views/window_view.cc index b66328cd1..83ff6514e 100644 --- a/libcef/browser/views/window_view.cc +++ b/libcef/browser/views/window_view.cc @@ -14,11 +14,10 @@ #endif #endif -#include "libcef/browser/chrome/views/chrome_browser_frame.h" #include "libcef/browser/geometry_util.h" #include "libcef/browser/image_impl.h" +#include "libcef/browser/views/widget.h" #include "libcef/browser/views/window_impl.h" -#include "libcef/features/runtime.h" #include "ui/base/hit_test.h" #include "ui/display/screen.h" @@ -37,9 +36,6 @@ #endif #if BUILDFLAG(IS_WIN) -#include - -#include "base/win/windows_version.h" #include "ui/display/win/screen_win.h" #include "ui/views/win/hwnd_util.h" #endif @@ -147,24 +143,10 @@ class NativeFrameViewEx : public views::NativeFrameView { return views::NativeFrameView::NonClientHitTest(point); } -#if BUILDFLAG(IS_WIN) void OnThemeChanged() override { views::NativeFrameView::OnThemeChanged(); - - // Value was 19 prior to Windows 10 20H1, according to - // https://stackoverflow.com/a/70693198 - const DWORD dwAttribute = - base::win::GetVersion() >= base::win::Version::WIN10_20H1 - ? DWMWA_USE_IMMERSIVE_DARK_MODE - : 19; - - // From BrowserFrameViewWin::SetSystemMicaTitlebarAttributes: - const BOOL dark_titlebar_enabled = GetNativeTheme()->ShouldUseDarkColors(); - DwmSetWindowAttribute(views::HWNDForWidget(widget_), dwAttribute, - &dark_titlebar_enabled, - sizeof(dark_titlebar_enabled)); + view_util::UpdateTitlebarTheme(widget_); } -#endif private: // Not owned by this object. @@ -384,8 +366,8 @@ void CefWindowView::CreateWidget(gfx::AcceleratedWidget parent_widget) { // |widget| is owned by the NativeWidget and will be destroyed in response to // a native destruction message. - views::Widget* widget = cef::IsChromeRuntimeEnabled() ? new ChromeBrowserFrame - : new views::Widget; + CefWidget* cef_widget = CefWidget::Create(this); + views::Widget* widget = cef_widget->GetWidget(); views::Widget::InitParams params; params.delegate = this; @@ -542,6 +524,8 @@ void CefWindowView::CreateWidget(gfx::AcceleratedWidget parent_widget) { DCHECK(widget->widget_delegate()->CanActivate()); } + cef_widget->Initialized(); + #if BUILDFLAG(IS_LINUX) #if BUILDFLAG(IS_OZONE_X11) auto x11window = static_cast(view_util::GetWindowHandle(widget)); @@ -747,6 +731,20 @@ void CefWindowView::ViewHierarchyChanged( ParentClass::ViewHierarchyChanged(details); } +void CefWindowView::OnThemeChanged() { + bool initialized = false; + if (auto* cef_widget = CefWidget::GetForWidget(GetWidget())) { + initialized = cef_widget->IsInitialized(); + } + + if (!initialized) { + // Skip the CefViewView logic. + views::WidgetDelegateView::OnThemeChanged(); + } else { + ParentClass::OnThemeChanged(); + } +} + void CefWindowView::OnWidgetActivationChanged(views::Widget* widget, bool active) { if (cef_delegate()) { @@ -986,3 +984,9 @@ std::optional CefWindowView::GetTitlebarHeight(bool required) const { return std::nullopt; } + +void CefWindowView::OnThemeColorsChanged(bool chrome_theme) { + if (cef_delegate()) { + cef_delegate()->OnThemeColorsChanged(GetCefWindow(), chrome_theme); + } +} diff --git a/libcef/browser/views/window_view.h b/libcef/browser/views/window_view.h index 14d27c46f..bd22cf35c 100644 --- a/libcef/browser/views/window_view.h +++ b/libcef/browser/views/window_view.h @@ -79,6 +79,7 @@ class CefWindowView // views::View methods: void ViewHierarchyChanged( const views::ViewHierarchyChangedDetails& details) override; + void OnThemeChanged() override; // views::WidgetObserver methods: void OnWidgetActivationChanged(views::Widget* widget, bool active) override; @@ -128,6 +129,9 @@ class CefWindowView std::optional GetTitlebarHeight(bool required) const; bool IsFrameless() const { return is_frameless_; } + // Called before ThemeChanged() for native or Chrome theme changes. + void OnThemeColorsChanged(bool chrome_theme); + // The Widget that hosts us, if we're a modal dialog. May return nullptr // during initialization and destruction. views::Widget* host_widget() const; diff --git a/libcef_dll/cpptoc/request_context_cpptoc.cc b/libcef_dll/cpptoc/request_context_cpptoc.cc index c7a6c9d2f..cd6a84cf2 100644 --- a/libcef_dll/cpptoc/request_context_cpptoc.cc +++ b/libcef_dll/cpptoc/request_context_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=713287303ab9bbb6db24d8aabb340766f5e69461$ +// $hash=48bce7be945d4e74682ffa41e8b45eb46a4f7589$ // #include "libcef_dll/cpptoc/request_context_cpptoc.h" @@ -553,6 +553,73 @@ request_context_set_content_setting(struct _cef_request_context_t* self, CefString(requesting_url), CefString(top_level_url), content_type, value); } +void CEF_CALLBACK +request_context_set_chrome_color_scheme(struct _cef_request_context_t* self, + cef_color_variant_t variant, + cef_color_t user_color) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return; + } + + // Execute + CefRequestContextCppToC::Get(self)->SetChromeColorScheme(variant, user_color); +} + +cef_color_variant_t CEF_CALLBACK request_context_get_chrome_color_scheme_mode( + struct _cef_request_context_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return CEF_COLOR_VARIANT_SYSTEM; + } + + // Execute + cef_color_variant_t _retval = + CefRequestContextCppToC::Get(self)->GetChromeColorSchemeMode(); + + // Return type: simple + return _retval; +} + +cef_color_t CEF_CALLBACK request_context_get_chrome_color_scheme_color( + struct _cef_request_context_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return 0; + } + + // Execute + cef_color_t _retval = + CefRequestContextCppToC::Get(self)->GetChromeColorSchemeColor(); + + // Return type: simple + return _retval; +} + +cef_color_variant_t CEF_CALLBACK +request_context_get_chrome_color_scheme_variant( + struct _cef_request_context_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return CEF_COLOR_VARIANT_SYSTEM; + } + + // Execute + cef_color_variant_t _retval = + CefRequestContextCppToC::Get(self)->GetChromeColorSchemeVariant(); + + // Return type: simple + return _retval; +} + int CEF_CALLBACK request_context_has_preference(struct _cef_preference_manager_t* self, const cef_string_t* name) { @@ -713,6 +780,14 @@ CefRequestContextCppToC::CefRequestContextCppToC() { GetStruct()->set_website_setting = request_context_set_website_setting; GetStruct()->get_content_setting = request_context_get_content_setting; GetStruct()->set_content_setting = request_context_set_content_setting; + GetStruct()->set_chrome_color_scheme = + request_context_set_chrome_color_scheme; + GetStruct()->get_chrome_color_scheme_mode = + request_context_get_chrome_color_scheme_mode; + GetStruct()->get_chrome_color_scheme_color = + request_context_get_chrome_color_scheme_color; + GetStruct()->get_chrome_color_scheme_variant = + request_context_get_chrome_color_scheme_variant; GetStruct()->base.has_preference = request_context_has_preference; GetStruct()->base.get_preference = request_context_get_preference; GetStruct()->base.get_all_preferences = request_context_get_all_preferences; diff --git a/libcef_dll/cpptoc/views/browser_view_cpptoc.cc b/libcef_dll/cpptoc/views/browser_view_cpptoc.cc index bf7fa8abd..030d6249d 100644 --- a/libcef_dll/cpptoc/views/browser_view_cpptoc.cc +++ b/libcef_dll/cpptoc/views/browser_view_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=f0759e132185f8e6f0ee9e947f7e5ece3dddd5e7$ +// $hash=07903b210017d0e545a381bb700088c689187b0e$ // #include "libcef_dll/cpptoc/views/browser_view_cpptoc.h" @@ -995,6 +995,26 @@ browser_view_get_background_color(struct _cef_view_t* self) { return _retval; } +cef_color_t CEF_CALLBACK browser_view_get_theme_color(struct _cef_view_t* self, + int color_id) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return 0; + } + + // Execute + cef_color_t _retval = + CefBrowserViewCppToC::Get(reinterpret_cast(self)) + ->GetThemeColor(color_id); + + // Return type: simple + return _retval; +} + int CEF_CALLBACK browser_view_convert_point_to_screen(struct _cef_view_t* self, cef_point_t* point) { shutdown_checker::AssertNotShutdown(); @@ -1261,6 +1281,7 @@ CefBrowserViewCppToC::CefBrowserViewCppToC() { GetStruct()->base.request_focus = browser_view_request_focus; GetStruct()->base.set_background_color = browser_view_set_background_color; GetStruct()->base.get_background_color = browser_view_get_background_color; + GetStruct()->base.get_theme_color = browser_view_get_theme_color; GetStruct()->base.convert_point_to_screen = browser_view_convert_point_to_screen; GetStruct()->base.convert_point_from_screen = diff --git a/libcef_dll/cpptoc/views/button_cpptoc.cc b/libcef_dll/cpptoc/views/button_cpptoc.cc index 6fce948ae..bde1d2bb7 100644 --- a/libcef_dll/cpptoc/views/button_cpptoc.cc +++ b/libcef_dll/cpptoc/views/button_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=3c4cb278397e9a07c8e5754650fe6944dd2a20ed$ +// $hash=4e2f75d68d804ad2414eb34b9f273b8f558c3dab$ // #include "libcef_dll/cpptoc/views/button_cpptoc.h" @@ -950,6 +950,26 @@ cef_color_t CEF_CALLBACK button_get_background_color(struct _cef_view_t* self) { return _retval; } +cef_color_t CEF_CALLBACK button_get_theme_color(struct _cef_view_t* self, + int color_id) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return 0; + } + + // Execute + cef_color_t _retval = + CefButtonCppToC::Get(reinterpret_cast(self)) + ->GetThemeColor(color_id); + + // Return type: simple + return _retval; +} + int CEF_CALLBACK button_convert_point_to_screen(struct _cef_view_t* self, cef_point_t* point) { shutdown_checker::AssertNotShutdown(); @@ -1212,6 +1232,7 @@ CefButtonCppToC::CefButtonCppToC() { GetStruct()->base.request_focus = button_request_focus; GetStruct()->base.set_background_color = button_set_background_color; GetStruct()->base.get_background_color = button_get_background_color; + GetStruct()->base.get_theme_color = button_get_theme_color; GetStruct()->base.convert_point_to_screen = button_convert_point_to_screen; GetStruct()->base.convert_point_from_screen = button_convert_point_from_screen; diff --git a/libcef_dll/cpptoc/views/label_button_cpptoc.cc b/libcef_dll/cpptoc/views/label_button_cpptoc.cc index 18f67a92e..efd956e4e 100644 --- a/libcef_dll/cpptoc/views/label_button_cpptoc.cc +++ b/libcef_dll/cpptoc/views/label_button_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=cc05a9116adf2a98d4b6169a86052a14e299cfeb$ +// $hash=51a06f8ad654129497df44179105e8523e1234af$ // #include "libcef_dll/cpptoc/views/label_button_cpptoc.h" @@ -1228,6 +1228,26 @@ label_button_get_background_color(struct _cef_view_t* self) { return _retval; } +cef_color_t CEF_CALLBACK label_button_get_theme_color(struct _cef_view_t* self, + int color_id) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return 0; + } + + // Execute + cef_color_t _retval = + CefLabelButtonCppToC::Get(reinterpret_cast(self)) + ->GetThemeColor(color_id); + + // Return type: simple + return _retval; +} + int CEF_CALLBACK label_button_convert_point_to_screen(struct _cef_view_t* self, cef_point_t* point) { shutdown_checker::AssertNotShutdown(); @@ -1512,6 +1532,7 @@ CefLabelButtonCppToC::CefLabelButtonCppToC() { label_button_set_background_color; GetStruct()->base.base.get_background_color = label_button_get_background_color; + GetStruct()->base.base.get_theme_color = label_button_get_theme_color; GetStruct()->base.base.convert_point_to_screen = label_button_convert_point_to_screen; GetStruct()->base.base.convert_point_from_screen = diff --git a/libcef_dll/cpptoc/views/menu_button_cpptoc.cc b/libcef_dll/cpptoc/views/menu_button_cpptoc.cc index 3e284474c..eb98eadd1 100644 --- a/libcef_dll/cpptoc/views/menu_button_cpptoc.cc +++ b/libcef_dll/cpptoc/views/menu_button_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=82aaa681d0ed57446e54a2c04a62adf18c284677$ +// $hash=02040c0851514ead9307d3901c117d94d4fffb41$ // #include "libcef_dll/cpptoc/views/menu_button_cpptoc.h" @@ -1281,6 +1281,26 @@ menu_button_get_background_color(struct _cef_view_t* self) { return _retval; } +cef_color_t CEF_CALLBACK menu_button_get_theme_color(struct _cef_view_t* self, + int color_id) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return 0; + } + + // Execute + cef_color_t _retval = + CefMenuButtonCppToC::Get(reinterpret_cast(self)) + ->GetThemeColor(color_id); + + // Return type: simple + return _retval; +} + int CEF_CALLBACK menu_button_convert_point_to_screen(struct _cef_view_t* self, cef_point_t* point) { shutdown_checker::AssertNotShutdown(); @@ -1569,6 +1589,7 @@ CefMenuButtonCppToC::CefMenuButtonCppToC() { menu_button_set_background_color; GetStruct()->base.base.base.get_background_color = menu_button_get_background_color; + GetStruct()->base.base.base.get_theme_color = menu_button_get_theme_color; GetStruct()->base.base.base.convert_point_to_screen = menu_button_convert_point_to_screen; GetStruct()->base.base.base.convert_point_from_screen = diff --git a/libcef_dll/cpptoc/views/panel_cpptoc.cc b/libcef_dll/cpptoc/views/panel_cpptoc.cc index 6e044d9db..b33066264 100644 --- a/libcef_dll/cpptoc/views/panel_cpptoc.cc +++ b/libcef_dll/cpptoc/views/panel_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=9ec8f43a509317ec1eead47556f83ce953f041b8$ +// $hash=4c768c4065540d40bfcc8da63dfa1916ca09f6f7$ // #include "libcef_dll/cpptoc/views/panel_cpptoc.h" @@ -1088,6 +1088,26 @@ cef_color_t CEF_CALLBACK panel_get_background_color(struct _cef_view_t* self) { return _retval; } +cef_color_t CEF_CALLBACK panel_get_theme_color(struct _cef_view_t* self, + int color_id) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return 0; + } + + // Execute + cef_color_t _retval = + CefPanelCppToC::Get(reinterpret_cast(self)) + ->GetThemeColor(color_id); + + // Return type: simple + return _retval; +} + int CEF_CALLBACK panel_convert_point_to_screen(struct _cef_view_t* self, cef_point_t* point) { shutdown_checker::AssertNotShutdown(); @@ -1356,6 +1376,7 @@ CefPanelCppToC::CefPanelCppToC() { GetStruct()->base.request_focus = panel_request_focus; GetStruct()->base.set_background_color = panel_set_background_color; GetStruct()->base.get_background_color = panel_get_background_color; + GetStruct()->base.get_theme_color = panel_get_theme_color; GetStruct()->base.convert_point_to_screen = panel_convert_point_to_screen; GetStruct()->base.convert_point_from_screen = panel_convert_point_from_screen; GetStruct()->base.convert_point_to_window = panel_convert_point_to_window; diff --git a/libcef_dll/cpptoc/views/scroll_view_cpptoc.cc b/libcef_dll/cpptoc/views/scroll_view_cpptoc.cc index b24d2b0ce..b1a2cc8ea 100644 --- a/libcef_dll/cpptoc/views/scroll_view_cpptoc.cc +++ b/libcef_dll/cpptoc/views/scroll_view_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=2ac2ff6e231398755ea6f2748985d21c0b4b1510$ +// $hash=9c4a2548745464359046f080fa2a07d1438c208b$ // #include "libcef_dll/cpptoc/views/scroll_view_cpptoc.h" @@ -1017,6 +1017,26 @@ scroll_view_get_background_color(struct _cef_view_t* self) { return _retval; } +cef_color_t CEF_CALLBACK scroll_view_get_theme_color(struct _cef_view_t* self, + int color_id) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return 0; + } + + // Execute + cef_color_t _retval = + CefScrollViewCppToC::Get(reinterpret_cast(self)) + ->GetThemeColor(color_id); + + // Return type: simple + return _retval; +} + int CEF_CALLBACK scroll_view_convert_point_to_screen(struct _cef_view_t* self, cef_point_t* point) { shutdown_checker::AssertNotShutdown(); @@ -1286,6 +1306,7 @@ CefScrollViewCppToC::CefScrollViewCppToC() { GetStruct()->base.request_focus = scroll_view_request_focus; GetStruct()->base.set_background_color = scroll_view_set_background_color; GetStruct()->base.get_background_color = scroll_view_get_background_color; + GetStruct()->base.get_theme_color = scroll_view_get_theme_color; GetStruct()->base.convert_point_to_screen = scroll_view_convert_point_to_screen; GetStruct()->base.convert_point_from_screen = diff --git a/libcef_dll/cpptoc/views/textfield_cpptoc.cc b/libcef_dll/cpptoc/views/textfield_cpptoc.cc index 34588e1d8..8b2e6e4aa 100644 --- a/libcef_dll/cpptoc/views/textfield_cpptoc.cc +++ b/libcef_dll/cpptoc/views/textfield_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=f8d63e2a2ba174b0f7ffb1ae66052288c28b6c43$ +// $hash=5407c7f442b7787de087a85d5613fffb384288c8$ // #include "libcef_dll/cpptoc/views/textfield_cpptoc.h" @@ -1447,6 +1447,26 @@ textfield_get_background_color(struct _cef_view_t* self) { return _retval; } +cef_color_t CEF_CALLBACK textfield_get_theme_color(struct _cef_view_t* self, + int color_id) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return 0; + } + + // Execute + cef_color_t _retval = + CefTextfieldCppToC::Get(reinterpret_cast(self)) + ->GetThemeColor(color_id); + + // Return type: simple + return _retval; +} + int CEF_CALLBACK textfield_convert_point_to_screen(struct _cef_view_t* self, cef_point_t* point) { shutdown_checker::AssertNotShutdown(); @@ -1741,6 +1761,7 @@ CefTextfieldCppToC::CefTextfieldCppToC() { GetStruct()->base.request_focus = textfield_request_focus; GetStruct()->base.set_background_color = textfield_set_background_color; GetStruct()->base.get_background_color = textfield_get_background_color; + GetStruct()->base.get_theme_color = textfield_get_theme_color; GetStruct()->base.convert_point_to_screen = textfield_convert_point_to_screen; GetStruct()->base.convert_point_from_screen = textfield_convert_point_from_screen; diff --git a/libcef_dll/cpptoc/views/view_cpptoc.cc b/libcef_dll/cpptoc/views/view_cpptoc.cc index cb304e420..702262e69 100644 --- a/libcef_dll/cpptoc/views/view_cpptoc.cc +++ b/libcef_dll/cpptoc/views/view_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=a543a7ac4053e15e97e84a87f4275c23e9a35477$ +// $hash=ae22b240b761b1bd2e9f168de2859ae0085191f6$ // #include "libcef_dll/cpptoc/views/view_cpptoc.h" @@ -788,6 +788,24 @@ cef_color_t CEF_CALLBACK view_get_background_color(struct _cef_view_t* self) { return _retval; } +cef_color_t CEF_CALLBACK view_get_theme_color(struct _cef_view_t* self, + int color_id) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return 0; + } + + // Execute + cef_color_t _retval = CefViewCppToC::Get(self)->GetThemeColor(color_id); + + // Return type: simple + return _retval; +} + int CEF_CALLBACK view_convert_point_to_screen(struct _cef_view_t* self, cef_point_t* point) { shutdown_checker::AssertNotShutdown(); @@ -1037,6 +1055,7 @@ CefViewCppToC::CefViewCppToC() { GetStruct()->request_focus = view_request_focus; GetStruct()->set_background_color = view_set_background_color; GetStruct()->get_background_color = view_get_background_color; + GetStruct()->get_theme_color = view_get_theme_color; GetStruct()->convert_point_to_screen = view_convert_point_to_screen; GetStruct()->convert_point_from_screen = view_convert_point_from_screen; GetStruct()->convert_point_to_window = view_convert_point_to_window; diff --git a/libcef_dll/cpptoc/views/window_cpptoc.cc b/libcef_dll/cpptoc/views/window_cpptoc.cc index d920d1675..973f5195b 100644 --- a/libcef_dll/cpptoc/views/window_cpptoc.cc +++ b/libcef_dll/cpptoc/views/window_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=a5f9a7de12728e82f8dee6d8dde3b9275a3e4ee4$ +// $hash=b9df5830c3e1b042aeced2a2b5fd97d00e702869$ // #include "libcef_dll/cpptoc/views/window_cpptoc.h" @@ -721,6 +721,36 @@ void CEF_CALLBACK window_remove_all_accelerators(struct _cef_window_t* self) { CefWindowCppToC::Get(self)->RemoveAllAccelerators(); } +void CEF_CALLBACK window_set_theme_color(struct _cef_window_t* self, + int color_id, + cef_color_t color) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return; + } + + // Execute + CefWindowCppToC::Get(self)->SetThemeColor(color_id, color); +} + +void CEF_CALLBACK window_theme_changed(struct _cef_window_t* self) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return; + } + + // Execute + CefWindowCppToC::Get(self)->ThemeChanged(); +} + struct _cef_window_t* CEF_CALLBACK window_as_window(struct _cef_panel_t* self) { shutdown_checker::AssertNotShutdown(); @@ -1784,6 +1814,26 @@ cef_color_t CEF_CALLBACK window_get_background_color(struct _cef_view_t* self) { return _retval; } +cef_color_t CEF_CALLBACK window_get_theme_color(struct _cef_view_t* self, + int color_id) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return 0; + } + + // Execute + cef_color_t _retval = + CefWindowCppToC::Get(reinterpret_cast(self)) + ->GetThemeColor(color_id); + + // Return type: simple + return _retval; +} + int CEF_CALLBACK window_convert_point_to_screen(struct _cef_view_t* self, cef_point_t* point) { shutdown_checker::AssertNotShutdown(); @@ -2035,6 +2085,8 @@ CefWindowCppToC::CefWindowCppToC() { GetStruct()->set_accelerator = window_set_accelerator; GetStruct()->remove_accelerator = window_remove_accelerator; GetStruct()->remove_all_accelerators = window_remove_all_accelerators; + GetStruct()->set_theme_color = window_set_theme_color; + GetStruct()->theme_changed = window_theme_changed; GetStruct()->base.as_window = window_as_window; GetStruct()->base.set_to_fill_layout = window_set_to_fill_layout; GetStruct()->base.set_to_box_layout = window_set_to_box_layout; @@ -2092,6 +2144,7 @@ CefWindowCppToC::CefWindowCppToC() { GetStruct()->base.base.request_focus = window_request_focus; GetStruct()->base.base.set_background_color = window_set_background_color; GetStruct()->base.base.get_background_color = window_get_background_color; + GetStruct()->base.base.get_theme_color = window_get_theme_color; GetStruct()->base.base.convert_point_to_screen = window_convert_point_to_screen; GetStruct()->base.base.convert_point_from_screen = diff --git a/libcef_dll/cpptoc/views/window_delegate_cpptoc.cc b/libcef_dll/cpptoc/views/window_delegate_cpptoc.cc index 685db20d3..8a63d1f88 100644 --- a/libcef_dll/cpptoc/views/window_delegate_cpptoc.cc +++ b/libcef_dll/cpptoc/views/window_delegate_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=1829e6ed7282ca9a0b34e825a11c229ddd48590d$ +// $hash=4350cb3f26c9b2a56bac5a0368eab19dff8659ae$ // #include "libcef_dll/cpptoc/views/window_delegate_cpptoc.h" @@ -532,6 +532,29 @@ window_delegate_on_key_event(struct _cef_window_delegate_t* self, return _retval; } +void CEF_CALLBACK +window_delegate_on_theme_colors_changed(struct _cef_window_delegate_t* self, + cef_window_t* window, + int chrome_theme) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return; + } + // Verify param: window; type: refptr_diff + DCHECK(window); + if (!window) { + return; + } + + // Execute + CefWindowDelegateCppToC::Get(self)->OnThemeColorsChanged( + CefWindowCToCpp::Wrap(window), chrome_theme ? true : false); +} + cef_size_t CEF_CALLBACK window_delegate_get_preferred_size(struct _cef_view_delegate_t* self, cef_view_t* view) { @@ -843,6 +866,8 @@ CefWindowDelegateCppToC::CefWindowDelegateCppToC() { GetStruct()->can_close = window_delegate_can_close; GetStruct()->on_accelerator = window_delegate_on_accelerator; GetStruct()->on_key_event = window_delegate_on_key_event; + GetStruct()->on_theme_colors_changed = + window_delegate_on_theme_colors_changed; GetStruct()->base.base.get_preferred_size = window_delegate_get_preferred_size; GetStruct()->base.base.get_minimum_size = window_delegate_get_minimum_size; diff --git a/libcef_dll/ctocpp/request_context_ctocpp.cc b/libcef_dll/ctocpp/request_context_ctocpp.cc index 4622e5d37..fc1244ff1 100644 --- a/libcef_dll/ctocpp/request_context_ctocpp.cc +++ b/libcef_dll/ctocpp/request_context_ctocpp.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=64a3528952ccef311d43064975e3447e7806ec25$ +// $hash=fadeb722e5e853c5747bb18b1508e4e0221c7019$ // #include "libcef_dll/ctocpp/request_context_ctocpp.h" @@ -546,6 +546,69 @@ void CefRequestContextCToCpp::SetContentSetting( top_level_url.GetStruct(), content_type, value); } +NO_SANITIZE("cfi-icall") +void CefRequestContextCToCpp::SetChromeColorScheme(cef_color_variant_t variant, + cef_color_t user_color) { + cef_request_context_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, set_chrome_color_scheme)) { + return; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + _struct->set_chrome_color_scheme(_struct, variant, user_color); +} + +NO_SANITIZE("cfi-icall") +cef_color_variant_t CefRequestContextCToCpp::GetChromeColorSchemeMode() { + cef_request_context_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, get_chrome_color_scheme_mode)) { + return CEF_COLOR_VARIANT_SYSTEM; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_color_variant_t _retval = _struct->get_chrome_color_scheme_mode(_struct); + + // Return type: simple + return _retval; +} + +NO_SANITIZE("cfi-icall") +cef_color_t CefRequestContextCToCpp::GetChromeColorSchemeColor() { + cef_request_context_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, get_chrome_color_scheme_color)) { + return 0; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_color_t _retval = _struct->get_chrome_color_scheme_color(_struct); + + // Return type: simple + return _retval; +} + +NO_SANITIZE("cfi-icall") +cef_color_variant_t CefRequestContextCToCpp::GetChromeColorSchemeVariant() { + cef_request_context_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, get_chrome_color_scheme_variant)) { + return CEF_COLOR_VARIANT_SYSTEM; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_color_variant_t _retval = + _struct->get_chrome_color_scheme_variant(_struct); + + // Return type: simple + return _retval; +} + NO_SANITIZE("cfi-icall") bool CefRequestContextCToCpp::HasPreference(const CefString& name) { cef_preference_manager_t* _struct = diff --git a/libcef_dll/ctocpp/request_context_ctocpp.h b/libcef_dll/ctocpp/request_context_ctocpp.h index a8294d47d..0ad040342 100644 --- a/libcef_dll/ctocpp/request_context_ctocpp.h +++ b/libcef_dll/ctocpp/request_context_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=34b4d674c378da826baafd00b0ed352441d17482$ +// $hash=daa5d7e0fa0e6b882ca98d9b4be5e6f5c81ddbde$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_REQUEST_CONTEXT_CTOCPP_H_ @@ -84,6 +84,11 @@ class CefRequestContextCToCpp const CefString& top_level_url, cef_content_setting_types_t content_type, cef_content_setting_values_t value) override; + void SetChromeColorScheme(cef_color_variant_t variant, + cef_color_t user_color) override; + cef_color_variant_t GetChromeColorSchemeMode() override; + cef_color_t GetChromeColorSchemeColor() override; + cef_color_variant_t GetChromeColorSchemeVariant() override; // CefPreferenceManager methods. bool HasPreference(const CefString& name) override; diff --git a/libcef_dll/ctocpp/views/browser_view_ctocpp.cc b/libcef_dll/ctocpp/views/browser_view_ctocpp.cc index 3469563e7..c6742becc 100644 --- a/libcef_dll/ctocpp/views/browser_view_ctocpp.cc +++ b/libcef_dll/ctocpp/views/browser_view_ctocpp.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=f5c482db02b530d627e487b8ba71019577910637$ +// $hash=fce37150f543768b0e9df8c5b8163d0ac4829a52$ // #include "libcef_dll/ctocpp/views/browser_view_ctocpp.h" @@ -864,6 +864,24 @@ cef_color_t CefBrowserViewCToCpp::GetBackgroundColor() { return _retval; } +NO_SANITIZE("cfi-icall") +cef_color_t CefBrowserViewCToCpp::GetThemeColor(int color_id) { + shutdown_checker::AssertNotShutdown(); + + cef_view_t* _struct = reinterpret_cast(GetStruct()); + if (CEF_MEMBER_MISSING(_struct, get_theme_color)) { + return 0; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_color_t _retval = _struct->get_theme_color(_struct, color_id); + + // Return type: simple + return _retval; +} + NO_SANITIZE("cfi-icall") bool CefBrowserViewCToCpp::ConvertPointToScreen(CefPoint& point) { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/views/browser_view_ctocpp.h b/libcef_dll/ctocpp/views/browser_view_ctocpp.h index b3d836d36..1be3507b5 100644 --- a/libcef_dll/ctocpp/views/browser_view_ctocpp.h +++ b/libcef_dll/ctocpp/views/browser_view_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=47b5f2dd231632b2ed2ca843ff1925cabac6d2a8$ +// $hash=d407851a21f82fc67289bd6314f31f46e07870df$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_BROWSER_VIEW_CTOCPP_H_ @@ -83,6 +83,7 @@ class CefBrowserViewCToCpp : public CefCToCppRefCounted(GetStruct()); + if (CEF_MEMBER_MISSING(_struct, get_theme_color)) { + return 0; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_color_t _retval = _struct->get_theme_color(_struct, color_id); + + // Return type: simple + return _retval; +} + NO_SANITIZE("cfi-icall") bool CefButtonCToCpp::ConvertPointToScreen(CefPoint& point) { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/views/button_ctocpp.h b/libcef_dll/ctocpp/views/button_ctocpp.h index e07d64263..b2b6dd4be 100644 --- a/libcef_dll/ctocpp/views/button_ctocpp.h +++ b/libcef_dll/ctocpp/views/button_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=fc28306db14011294cbb7e7ef277ddd35d5667f0$ +// $hash=c8c1e03aa10a0ea469774ccd59640fcec2487513$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_BUTTON_CTOCPP_H_ @@ -87,6 +87,7 @@ class CefButtonCToCpp void RequestFocus() override; void SetBackgroundColor(cef_color_t color) override; cef_color_t GetBackgroundColor() override; + cef_color_t GetThemeColor(int color_id) override; bool ConvertPointToScreen(CefPoint& point) override; bool ConvertPointFromScreen(CefPoint& point) override; bool ConvertPointToWindow(CefPoint& point) override; diff --git a/libcef_dll/ctocpp/views/label_button_ctocpp.cc b/libcef_dll/ctocpp/views/label_button_ctocpp.cc index 175ba50fc..8af7409f6 100644 --- a/libcef_dll/ctocpp/views/label_button_ctocpp.cc +++ b/libcef_dll/ctocpp/views/label_button_ctocpp.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=e4d98e5ef3ec602b76f42fa4c4d4f5436a8ff53a$ +// $hash=771ab2674e580450d8a0478435305bccc2440cae$ // #include "libcef_dll/ctocpp/views/label_button_ctocpp.h" @@ -1089,6 +1089,24 @@ cef_color_t CefLabelButtonCToCpp::GetBackgroundColor() { return _retval; } +NO_SANITIZE("cfi-icall") +cef_color_t CefLabelButtonCToCpp::GetThemeColor(int color_id) { + shutdown_checker::AssertNotShutdown(); + + cef_view_t* _struct = reinterpret_cast(GetStruct()); + if (CEF_MEMBER_MISSING(_struct, get_theme_color)) { + return 0; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_color_t _retval = _struct->get_theme_color(_struct, color_id); + + // Return type: simple + return _retval; +} + NO_SANITIZE("cfi-icall") bool CefLabelButtonCToCpp::ConvertPointToScreen(CefPoint& point) { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/views/label_button_ctocpp.h b/libcef_dll/ctocpp/views/label_button_ctocpp.h index 5a5f9d44c..67f3f36a2 100644 --- a/libcef_dll/ctocpp/views/label_button_ctocpp.h +++ b/libcef_dll/ctocpp/views/label_button_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=a22e6b723998dcbfc9c9ff8fd52dd1dfdd3ce772$ +// $hash=3ba705772b9bd57b5abac5f7128bc5afe148c83a$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_LABEL_BUTTON_CTOCPP_H_ @@ -102,6 +102,7 @@ class CefLabelButtonCToCpp : public CefCToCppRefCounted(GetStruct()); + if (CEF_MEMBER_MISSING(_struct, get_theme_color)) { + return 0; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_color_t _retval = _struct->get_theme_color(_struct, color_id); + + // Return type: simple + return _retval; +} + NO_SANITIZE("cfi-icall") bool CefMenuButtonCToCpp::ConvertPointToScreen(CefPoint& point) { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/views/menu_button_ctocpp.h b/libcef_dll/ctocpp/views/menu_button_ctocpp.h index cd1de8230..04434ee3e 100644 --- a/libcef_dll/ctocpp/views/menu_button_ctocpp.h +++ b/libcef_dll/ctocpp/views/menu_button_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=4a9ae17508040a9f987bb8a939f99ace0df00c6f$ +// $hash=fbe53f51eb991aeebc5d66da40a894880374e248$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_MENU_BUTTON_CTOCPP_H_ @@ -106,6 +106,7 @@ class CefMenuButtonCToCpp : public CefCToCppRefCounted(GetStruct()); + if (CEF_MEMBER_MISSING(_struct, get_theme_color)) { + return 0; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_color_t _retval = _struct->get_theme_color(_struct, color_id); + + // Return type: simple + return _retval; +} + NO_SANITIZE("cfi-icall") bool CefPanelCToCpp::ConvertPointToScreen(CefPoint& point) { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/views/panel_ctocpp.h b/libcef_dll/ctocpp/views/panel_ctocpp.h index e31c3ded2..1a2f68c24 100644 --- a/libcef_dll/ctocpp/views/panel_ctocpp.h +++ b/libcef_dll/ctocpp/views/panel_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=a870337ef265d9234c4113580db3518f271345dd$ +// $hash=3ab4fe06360d8ad1837683efb6ae5229b4c01f91$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_PANEL_CTOCPP_H_ @@ -100,6 +100,7 @@ class CefPanelCToCpp void RequestFocus() override; void SetBackgroundColor(cef_color_t color) override; cef_color_t GetBackgroundColor() override; + cef_color_t GetThemeColor(int color_id) override; bool ConvertPointToScreen(CefPoint& point) override; bool ConvertPointFromScreen(CefPoint& point) override; bool ConvertPointToWindow(CefPoint& point) override; diff --git a/libcef_dll/ctocpp/views/scroll_view_ctocpp.cc b/libcef_dll/ctocpp/views/scroll_view_ctocpp.cc index 6100c26fe..79304b116 100644 --- a/libcef_dll/ctocpp/views/scroll_view_ctocpp.cc +++ b/libcef_dll/ctocpp/views/scroll_view_ctocpp.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=b01419d1bf9c7742defc9102ff524d95e524bcc1$ +// $hash=f74bed30da72caaf40fb59b2e34b1c99aa647105$ // #include "libcef_dll/ctocpp/views/scroll_view_ctocpp.h" @@ -901,6 +901,24 @@ NO_SANITIZE("cfi-icall") cef_color_t CefScrollViewCToCpp::GetBackgroundColor() { return _retval; } +NO_SANITIZE("cfi-icall") +cef_color_t CefScrollViewCToCpp::GetThemeColor(int color_id) { + shutdown_checker::AssertNotShutdown(); + + cef_view_t* _struct = reinterpret_cast(GetStruct()); + if (CEF_MEMBER_MISSING(_struct, get_theme_color)) { + return 0; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_color_t _retval = _struct->get_theme_color(_struct, color_id); + + // Return type: simple + return _retval; +} + NO_SANITIZE("cfi-icall") bool CefScrollViewCToCpp::ConvertPointToScreen(CefPoint& point) { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/views/scroll_view_ctocpp.h b/libcef_dll/ctocpp/views/scroll_view_ctocpp.h index 50264263e..42c8d4c09 100644 --- a/libcef_dll/ctocpp/views/scroll_view_ctocpp.h +++ b/libcef_dll/ctocpp/views/scroll_view_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=43a676c3ad82948c81c726d976f915984c116e6f$ +// $hash=1b896bea52b0d62490a5b78a86dee729a4236cda$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_SCROLL_VIEW_CTOCPP_H_ @@ -87,6 +87,7 @@ class CefScrollViewCToCpp : public CefCToCppRefCounted(GetStruct()); + if (CEF_MEMBER_MISSING(_struct, get_theme_color)) { + return 0; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_color_t _retval = _struct->get_theme_color(_struct, color_id); + + // Return type: simple + return _retval; +} + NO_SANITIZE("cfi-icall") bool CefTextfieldCToCpp::ConvertPointToScreen(CefPoint& point) { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/views/textfield_ctocpp.h b/libcef_dll/ctocpp/views/textfield_ctocpp.h index e8b31335f..0b2f3daa7 100644 --- a/libcef_dll/ctocpp/views/textfield_ctocpp.h +++ b/libcef_dll/ctocpp/views/textfield_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=047586c07d3c46008ca902cad02a958a2393b1ab$ +// $hash=70c79d683dbcf742579a22c2543d6ed1b40453ea$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_TEXTFIELD_CTOCPP_H_ @@ -113,6 +113,7 @@ class CefTextfieldCToCpp : public CefCToCppRefCountedget_theme_color(_struct, color_id); + + // Return type: simple + return _retval; +} + NO_SANITIZE("cfi-icall") bool CefViewCToCpp::ConvertPointToScreen(CefPoint& point) { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/views/view_ctocpp.h b/libcef_dll/ctocpp/views/view_ctocpp.h index 209597ef1..02cec7468 100644 --- a/libcef_dll/ctocpp/views/view_ctocpp.h +++ b/libcef_dll/ctocpp/views/view_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=195039e245037c5efe9c17b85cab2395d34ece27$ +// $hash=e9c4f3a121d3ab9a2d9d8a8ea8b51bddfd4845db$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_VIEW_CTOCPP_H_ @@ -89,6 +89,7 @@ class CefViewCToCpp void RequestFocus() override; void SetBackgroundColor(cef_color_t color) override; cef_color_t GetBackgroundColor() override; + cef_color_t GetThemeColor(int color_id) override; bool ConvertPointToScreen(CefPoint& point) override; bool ConvertPointFromScreen(CefPoint& point) override; bool ConvertPointToWindow(CefPoint& point) override; diff --git a/libcef_dll/ctocpp/views/window_ctocpp.cc b/libcef_dll/ctocpp/views/window_ctocpp.cc index c02123f88..7f8747428 100644 --- a/libcef_dll/ctocpp/views/window_ctocpp.cc +++ b/libcef_dll/ctocpp/views/window_ctocpp.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=a49624e0b20c4a50ff719c492d7101099646000f$ +// $hash=8b955eda81961599ffef6767305992dbbcd5b12c$ // #include "libcef_dll/ctocpp/views/window_ctocpp.h" @@ -709,6 +709,35 @@ NO_SANITIZE("cfi-icall") void CefWindowCToCpp::RemoveAllAccelerators() { _struct->remove_all_accelerators(_struct); } +NO_SANITIZE("cfi-icall") +void CefWindowCToCpp::SetThemeColor(int color_id, cef_color_t color) { + shutdown_checker::AssertNotShutdown(); + + cef_window_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, set_theme_color)) { + return; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + _struct->set_theme_color(_struct, color_id, color); +} + +NO_SANITIZE("cfi-icall") void CefWindowCToCpp::ThemeChanged() { + shutdown_checker::AssertNotShutdown(); + + cef_window_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, theme_changed)) { + return; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + _struct->theme_changed(_struct); +} + NO_SANITIZE("cfi-icall") CefRefPtr CefWindowCToCpp::AsWindow() { shutdown_checker::AssertNotShutdown(); @@ -1667,6 +1696,24 @@ NO_SANITIZE("cfi-icall") cef_color_t CefWindowCToCpp::GetBackgroundColor() { return _retval; } +NO_SANITIZE("cfi-icall") +cef_color_t CefWindowCToCpp::GetThemeColor(int color_id) { + shutdown_checker::AssertNotShutdown(); + + cef_view_t* _struct = reinterpret_cast(GetStruct()); + if (CEF_MEMBER_MISSING(_struct, get_theme_color)) { + return 0; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_color_t _retval = _struct->get_theme_color(_struct, color_id); + + // Return type: simple + return _retval; +} + NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::ConvertPointToScreen(CefPoint& point) { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/views/window_ctocpp.h b/libcef_dll/ctocpp/views/window_ctocpp.h index cc346a219..d63d792d8 100644 --- a/libcef_dll/ctocpp/views/window_ctocpp.h +++ b/libcef_dll/ctocpp/views/window_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=5b562d0924fd4a825f43ae7735c1fc98c474de6a$ +// $hash=3998ef7a4585ef19268482df51611d0283daf275$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_WINDOW_CTOCPP_H_ @@ -88,6 +88,8 @@ class CefWindowCToCpp bool high_priority) override; void RemoveAccelerator(int command_id) override; void RemoveAllAccelerators() override; + void SetThemeColor(int color_id, cef_color_t color) override; + void ThemeChanged() override; // CefPanel methods. CefRefPtr AsWindow() override; @@ -149,6 +151,7 @@ class CefWindowCToCpp void RequestFocus() override; void SetBackgroundColor(cef_color_t color) override; cef_color_t GetBackgroundColor() override; + cef_color_t GetThemeColor(int color_id) override; bool ConvertPointToScreen(CefPoint& point) override; bool ConvertPointFromScreen(CefPoint& point) override; bool ConvertPointToWindow(CefPoint& point) override; diff --git a/libcef_dll/ctocpp/views/window_delegate_ctocpp.cc b/libcef_dll/ctocpp/views/window_delegate_ctocpp.cc index 04c8e2a66..45a35e8b0 100644 --- a/libcef_dll/ctocpp/views/window_delegate_ctocpp.cc +++ b/libcef_dll/ctocpp/views/window_delegate_ctocpp.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=1d798c20b6e7325b2e769185739288682b037960$ +// $hash=18fd259f012c67956bda267a62d0e30971c696ca$ // #include "libcef_dll/ctocpp/views/window_delegate_ctocpp.h" @@ -511,6 +511,29 @@ bool CefWindowDelegateCToCpp::OnKeyEvent(CefRefPtr window, return _retval ? true : false; } +NO_SANITIZE("cfi-icall") +void CefWindowDelegateCToCpp::OnThemeColorsChanged(CefRefPtr window, + bool chrome_theme) { + shutdown_checker::AssertNotShutdown(); + + cef_window_delegate_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, on_theme_colors_changed)) { + return; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: window; type: refptr_diff + DCHECK(window.get()); + if (!window.get()) { + return; + } + + // Execute + _struct->on_theme_colors_changed(_struct, CefWindowCppToC::Wrap(window), + chrome_theme); +} + NO_SANITIZE("cfi-icall") CefSize CefWindowDelegateCToCpp::GetPreferredSize(CefRefPtr view) { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/views/window_delegate_ctocpp.h b/libcef_dll/ctocpp/views/window_delegate_ctocpp.h index fa21232ad..b538cf7b1 100644 --- a/libcef_dll/ctocpp/views/window_delegate_ctocpp.h +++ b/libcef_dll/ctocpp/views/window_delegate_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=80e6d33af9304311baec72c039930dc22d38bd53$ +// $hash=a67a7b010e34bdda6ad0ecdf8da9bd6402689a6b$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_WINDOW_DELEGATE_CTOCPP_H_ @@ -63,6 +63,8 @@ class CefWindowDelegateCToCpp bool OnAccelerator(CefRefPtr window, int command_id) override; bool OnKeyEvent(CefRefPtr window, const CefKeyEvent& event) override; + void OnThemeColorsChanged(CefRefPtr window, + bool chrome_theme) override; // CefPanelDelegate methods. diff --git a/patch/patch.cfg b/patch/patch.cfg index 2dfc559db..844c939c8 100644 --- a/patch/patch.cfg +++ b/patch/patch.cfg @@ -211,6 +211,9 @@ patches = [ { # Changes to support the Chrome runtime in CEF. # https://github.com/chromiumembedded/cef/issues/2969 + # + # Apply dynamic light/dark theme changes to web content. + # https://issues.chromium.org/issues/332328864#comment3 'name': 'chrome_runtime', }, { @@ -737,5 +740,17 @@ patches = [ # views: Update textfield colors when enabled state changes # https://chromium-review.googlesource.com/c/chromium/src/+/5399416 'name': 'views_textfield_5399416' + }, + { + # views: Add ColorProviderManagerObserver. + # https://github.com/chromiumembedded/cef/issues/3610 + 'name': 'color_provider_manager_3610' + }, + { + # linux: Disable GtkUi with multi-threaded-message-loop to avoid crashes. + # linux: Disable GTK theme change notifications due to performance issues. + # https://github.com/chromiumembedded/cef/issues/3610 + # https://issues.chromium.org/issues/40280130#comment7 + 'name': 'linux_gtk_theme_3610' } ] diff --git a/patch/patches/chrome_runtime.patch b/patch/patches/chrome_runtime.patch index 1396a5505..7e6c5c6e4 100644 --- a/patch/patches/chrome_runtime.patch +++ b/patch/patches/chrome_runtime.patch @@ -384,7 +384,7 @@ index 2f0fe9d22667c..f50fe7bf75df3 100644 +#endif } diff --git chrome/browser/chrome_content_browser_client.cc chrome/browser/chrome_content_browser_client.cc -index 66b50cf0fd99b..f2e2cc47a513e 100644 +index 66b50cf0fd99b..4b868cdf4c3ee 100644 --- chrome/browser/chrome_content_browser_client.cc +++ chrome/browser/chrome_content_browser_client.cc @@ -47,6 +47,7 @@ @@ -416,7 +416,33 @@ index 66b50cf0fd99b..f2e2cc47a513e 100644 // static void ChromeContentBrowserClient::RegisterLocalStatePrefs( PrefRegistrySimple* registry) { -@@ -4375,9 +4383,11 @@ void ChromeContentBrowserClient::BrowserURLHandlerCreated( +@@ -3627,9 +3635,24 @@ bool UpdatePreferredColorScheme(WebPreferences* web_prefs, + : blink::mojom::PreferredColorScheme::kLight; + } + #else ++ auto preferred_color_scheme = native_theme->GetPreferredColorScheme(); ++ ++ auto* profile = Profile::FromBrowserContext( ++ web_contents->GetBrowserContext()); ++ const auto* theme_service = ThemeServiceFactory::GetForProfile(profile); ++ ++ const auto browser_color_scheme = theme_service->GetBrowserColorScheme(); ++ if (browser_color_scheme != ThemeService::BrowserColorScheme::kSystem) { ++ // Override the native theme. ++ preferred_color_scheme = ++ browser_color_scheme == ThemeService::BrowserColorScheme::kLight ++ ? ui::NativeTheme::PreferredColorScheme::kLight ++ : ui::NativeTheme::PreferredColorScheme::kDark; ++ } ++ + // Update based on native theme scheme. + web_prefs->preferred_color_scheme = +- ToBlinkPreferredColorScheme(native_theme->GetPreferredColorScheme()); ++ ToBlinkPreferredColorScheme(preferred_color_scheme); + #endif // BUILDFLAG(IS_ANDROID) + + // Reauth WebUI doesn't support dark mode yet because it shares the dialog +@@ -4375,9 +4398,11 @@ void ChromeContentBrowserClient::BrowserURLHandlerCreated( &search::HandleNewTabURLReverseRewrite); #endif // BUILDFLAG(IS_ANDROID) @@ -428,7 +454,7 @@ index 66b50cf0fd99b..f2e2cc47a513e 100644 } base::FilePath ChromeContentBrowserClient::GetDefaultDownloadDirectory() { -@@ -6484,7 +6494,7 @@ void ChromeContentBrowserClient::OnNetworkServiceCreated( +@@ -6484,7 +6509,7 @@ void ChromeContentBrowserClient::OnNetworkServiceCreated( #endif } @@ -437,7 +463,7 @@ index 66b50cf0fd99b..f2e2cc47a513e 100644 content::BrowserContext* context, bool in_memory, const base::FilePath& relative_partition_path, -@@ -6502,6 +6512,8 @@ void ChromeContentBrowserClient::ConfigureNetworkContextParams( +@@ -6502,6 +6527,8 @@ void ChromeContentBrowserClient::ConfigureNetworkContextParams( network_context_params->user_agent = GetUserAgentBasedOnPolicy(context); network_context_params->accept_language = GetApplicationLocale(); } @@ -446,7 +472,7 @@ index 66b50cf0fd99b..f2e2cc47a513e 100644 } std::vector -@@ -7627,10 +7639,10 @@ void ChromeContentBrowserClient::OnKeepaliveRequestStarted( +@@ -7627,10 +7654,10 @@ void ChromeContentBrowserClient::OnKeepaliveRequestStarted( const auto now = base::TimeTicks::Now(); const auto timeout = GetKeepaliveTimerTimeout(context); keepalive_deadline_ = std::max(keepalive_deadline_, now + timeout); @@ -459,7 +485,7 @@ index 66b50cf0fd99b..f2e2cc47a513e 100644 FROM_HERE, keepalive_deadline_ - now, base::BindOnce( &ChromeContentBrowserClient::OnKeepaliveTimerFired, -@@ -7649,7 +7661,8 @@ void ChromeContentBrowserClient::OnKeepaliveRequestFinished() { +@@ -7649,7 +7676,8 @@ void ChromeContentBrowserClient::OnKeepaliveRequestFinished() { --num_keepalive_requests_; if (num_keepalive_requests_ == 0) { DVLOG(1) << "Stopping the keepalive timer"; @@ -469,7 +495,7 @@ index 66b50cf0fd99b..f2e2cc47a513e 100644 // This deletes the keep alive handle attached to the timer function and // unblock the shutdown sequence. } -@@ -7789,7 +7802,7 @@ void ChromeContentBrowserClient::OnKeepaliveTimerFired( +@@ -7789,7 +7817,7 @@ void ChromeContentBrowserClient::OnKeepaliveTimerFired( const auto now = base::TimeTicks::Now(); const auto then = keepalive_deadline_; if (now < then) { diff --git a/patch/patches/chrome_runtime_views.patch b/patch/patches/chrome_runtime_views.patch index 968559f32..b32251fee 100644 --- a/patch/patches/chrome_runtime_views.patch +++ b/patch/patches/chrome_runtime_views.patch @@ -233,7 +233,7 @@ index 0ccfe39eb5696..c9424316b6d14 100644 return gfx::Rect(); } diff --git chrome/browser/ui/views/frame/browser_frame.cc chrome/browser/ui/views/frame/browser_frame.cc -index cce1835d35be3..5ac27ca62876a 100644 +index cce1835d35be3..75f8aae063ada 100644 --- chrome/browser/ui/views/frame/browser_frame.cc +++ chrome/browser/ui/views/frame/browser_frame.cc @@ -114,15 +114,23 @@ ui::ColorProviderKey::SchemeVariant GetSchemeVariant( @@ -341,7 +341,21 @@ index cce1835d35be3..5ac27ca62876a 100644 key.app_controller = browser_view_->browser()->app_controller(); -@@ -637,5 +671,8 @@ bool BrowserFrame::RegenerateFrameOnThemeChange( +@@ -572,6 +606,13 @@ void BrowserFrame::SelectNativeTheme() { + return; + } + ++ // Always use the NativeTheme for forced color modes. ++ if (ui::NativeTheme::IsForcedDarkMode() || ++ ui::NativeTheme::IsForcedLightMode()) { ++ SetNativeTheme(native_theme); ++ return; ++ } ++ + // Ignore the system theme for web apps with window-controls-overlay as the + // display_override so the web contents can blend with the overlay by using + // the developer-provided theme color for a better experience. Context: +@@ -637,5 +678,8 @@ bool BrowserFrame::RegenerateFrameOnThemeChange( } bool BrowserFrame::IsIncognitoBrowser() const { @@ -351,7 +365,7 @@ index cce1835d35be3..5ac27ca62876a 100644 return browser_view_->browser()->profile()->IsIncognitoProfile(); } diff --git chrome/browser/ui/views/frame/browser_frame.h chrome/browser/ui/views/frame/browser_frame.h -index 2e973c9e279b0..12b62efb8071f 100644 +index 2e973c9e279b0..8662f9cf14b17 100644 --- chrome/browser/ui/views/frame/browser_frame.h +++ chrome/browser/ui/views/frame/browser_frame.h @@ -58,7 +58,9 @@ enum class TabDragKind { @@ -364,6 +378,38 @@ index 2e973c9e279b0..12b62efb8071f 100644 BrowserFrame(const BrowserFrame&) = delete; BrowserFrame& operator=(const BrowserFrame&) = delete; +@@ -137,7 +139,7 @@ class BrowserFrame : public views::Widget, public views::ContextMenuController { + + // ThemeService calls this when a user has changed their theme, indicating + // that it's time to redraw everything. +- void UserChangedTheme(BrowserThemeChangeType theme_change_type); ++ virtual void UserChangedTheme(BrowserThemeChangeType theme_change_type); + + // views::Widget: + views::internal::RootView* CreateRootView() override; +@@ -175,17 +177,17 @@ class BrowserFrame : public views::Widget, public views::ContextMenuController { + void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override; + ui::ColorProviderKey GetColorProviderKey() const override; + ++ // Select a native theme that is appropriate for the current context. This is ++ // currently only needed for Linux to switch between the regular NativeTheme ++ // and the GTK NativeTheme instance. ++ void SelectNativeTheme(); ++ + private: + void OnTouchUiChanged(); + + // Callback for MenuRunner. + void OnMenuClosed(); + +- // Select a native theme that is appropriate for the current context. This is +- // currently only needed for Linux to switch between the regular NativeTheme +- // and the GTK NativeTheme instance. +- void SelectNativeTheme(); +- + // Regenerate the frame on theme change if necessary. Returns true if + // regenerated. + bool RegenerateFrameOnThemeChange(BrowserThemeChangeType theme_change_type); diff --git chrome/browser/ui/views/frame/browser_view.cc chrome/browser/ui/views/frame/browser_view.cc index f764d5edc704c..b7d5ee188736e 100644 --- chrome/browser/ui/views/frame/browser_view.cc diff --git a/patch/patches/color_provider_manager_3610.patch b/patch/patches/color_provider_manager_3610.patch new file mode 100644 index 000000000..1b00599af --- /dev/null +++ b/patch/patches/color_provider_manager_3610.patch @@ -0,0 +1,105 @@ +diff --git ui/color/color_provider_manager.cc ui/color/color_provider_manager.cc +index a0933fab35037..7a381e24a8816 100644 +--- ui/color/color_provider_manager.cc ++++ ui/color/color_provider_manager.cc +@@ -46,6 +46,15 @@ std::optional& GetGlobalManager() { + + } // namespace + ++void ColorProviderManager::AddObserver(ColorProviderManagerObserver* observer) { ++ observers_.AddObserver(observer); ++} ++ ++void ColorProviderManager::RemoveObserver( ++ ColorProviderManagerObserver* observer) { ++ observers_.RemoveObserver(observer); ++} ++ + ColorProviderManager::ColorProviderManager() { + ResetColorProviderInitializerList(); + } +@@ -86,8 +95,19 @@ void ColorProviderManager::ResetColorProviderInitializerList() { + } + + void ColorProviderManager::ResetColorProviderCache() { +- if (!color_providers_.empty()) ++ if (!color_providers_.empty()) { + color_providers_.clear(); ++ ++ for (ColorProviderManagerObserver& observer : observers_) { ++ observer.OnColorProviderCacheReset(); ++ } ++ } ++} ++ ++void ColorProviderManager::AfterNativeThemeUpdated() { ++ for (ColorProviderManagerObserver& observer : observers_) { ++ observer.OnAfterNativeThemeUpdated(); ++ } + } + + void ColorProviderManager::AppendColorProviderInitializer( +diff --git ui/color/color_provider_manager.h ui/color/color_provider_manager.h +index 67341dd5fc3d6..ee70de7f7fd44 100644 +--- ui/color/color_provider_manager.h ++++ ui/color/color_provider_manager.h +@@ -15,6 +15,7 @@ + #include "base/containers/flat_map.h" + #include "base/functional/callback.h" + #include "base/memory/weak_ptr.h" ++#include "base/observer_list.h" + #include "third_party/skia/include/core/SkColor.h" + #include "ui/color/color_provider_key.h" + #include "ui/color/system_theme.h" +@@ -24,6 +25,19 @@ namespace ui { + + class ColorProvider; + ++// Observers which are notified when the color provider manager changes. ++class COMPONENT_EXPORT(COLOR) ColorProviderManagerObserver { ++ public: ++ // Called when the color provider cache is reset. ++ virtual void OnColorProviderCacheReset() {} ++ ++ // Called after NativeTheme sends OnNativeThemeUpdated notifications. ++ virtual void OnAfterNativeThemeUpdated() {} ++ ++ protected: ++ virtual ~ColorProviderManagerObserver() = default; ++}; ++ + // Manages and provides color providers. + // + // In most cases, use ColorProviderManager::Get() to obtain an instance to the +@@ -48,6 +62,9 @@ class COMPONENT_EXPORT(COLOR) ColorProviderManager { + // Clears the ColorProviders stored in `color_providers_`. + void ResetColorProviderCache(); + ++ // Called after NativeTheme sends OnNativeThemeUpdated notifications. ++ void AfterNativeThemeUpdated(); ++ + // Appends `initializer` to the end of the current `initializer_list_`. + void AppendColorProviderInitializer( + ColorProviderInitializerList::CallbackType Initializer); +@@ -59,6 +76,10 @@ class COMPONENT_EXPORT(COLOR) ColorProviderManager { + return num_providers_initialized_; + } + ++ // Add or remove observers. ++ void AddObserver(ColorProviderManagerObserver* observer); ++ void RemoveObserver(ColorProviderManagerObserver* observer); ++ + protected: + ColorProviderManager(); + virtual ~ColorProviderManager(); +@@ -76,6 +97,9 @@ class COMPONENT_EXPORT(COLOR) ColorProviderManager { + // Tracks the number of ColorProviders constructed and initialized by the + // manager for metrics purposes. + size_t num_providers_initialized_ = 0; ++ ++ base::ObserverList::UncheckedAndDanglingUntriaged ++ observers_; + }; + + } // namespace ui + diff --git a/patch/patches/light_mode_3534.patch b/patch/patches/light_mode_3534.patch index ec0c1afe0..0b444d1f9 100644 --- a/patch/patches/light_mode_3534.patch +++ b/patch/patches/light_mode_3534.patch @@ -31,25 +31,86 @@ index 73d6ad5e9bb36..6c450e79c0f94 100644 auto& dark_mode_support = GetDarkModeSupport(); return (dark_mode_support.allow_dark_mode_for_app || dark_mode_support.set_preferred_app_mode) && -diff --git ui/native_theme/native_theme_mac.mm ui/native_theme/native_theme_mac.mm -index d8ff86972911d..0fbafdef0fc26 100644 ---- ui/native_theme/native_theme_mac.mm -+++ ui/native_theme/native_theme_mac.mm -@@ -51,6 +51,13 @@ bool InvertedColors() { - return NSWorkspace.sharedWorkspace.accessibilityDisplayShouldInvertColors; +diff --git chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc +index 23d0611fdb2b5..81fd1055e926e 100644 +--- chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc ++++ chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc +@@ -61,7 +61,10 @@ void ChromeBrowserMainExtraPartsViewsLinux::ToolkitInitialized() { + linux_ui_theme->GetNativeTheme()->system_theme()); + } + #if defined(USE_DBUS) +- dark_mode_manager_ = std::make_unique(); ++ if (!ui::NativeTheme::IsForcedDarkMode() && ++ !ui::NativeTheme::IsForcedLightMode()) { ++ dark_mode_manager_ = std::make_unique(); ++ } + #endif } -+bool IsForcedLightMode() { +diff --git ui/gtk/native_theme_gtk.cc ui/gtk/native_theme_gtk.cc +index d69b17b004120..5175ea3a785a3 100644 +--- ui/gtk/native_theme_gtk.cc ++++ ui/gtk/native_theme_gtk.cc +@@ -164,9 +164,11 @@ void NativeThemeGtk::OnThemeChanged(GtkSettings* settings, + // have a light variant and aren't affected by the setting. Because of this, + // experimentally check if the theme is dark by checking if the window + // background color is dark. +- const SkColor window_bg_color = GetBgColor(""); +- set_use_dark_colors(IsForcedDarkMode() || +- color_utils::IsDark(window_bg_color)); ++ if (!IsForcedLightMode()) { ++ const SkColor window_bg_color = GetBgColor(""); ++ set_use_dark_colors(IsForcedDarkMode() || ++ color_utils::IsDark(window_bg_color)); ++ } + set_preferred_color_scheme(CalculatePreferredColorScheme()); + + // GTK doesn't have a native high contrast setting. Rather, it's implied by +diff --git ui/native_theme/native_theme.cc ui/native_theme/native_theme.cc +index d466e72df7e2c..d0a58289ca291 100644 +--- ui/native_theme/native_theme.cc ++++ ui/native_theme/native_theme.cc +@@ -143,6 +143,7 @@ void NativeTheme::NotifyOnNativeThemeUpdated() { + color_provider_manager.ResetColorProviderCache(); + for (NativeThemeObserver& observer : native_theme_observers_) + observer.OnNativeThemeUpdated(this); ++ color_provider_manager.AfterNativeThemeUpdated(); + + RecordNumColorProvidersInitializedDuringOnNativeThemeUpdated( + color_provider_manager.num_providers_initialized() - +@@ -276,6 +277,13 @@ bool NativeTheme::IsForcedDarkMode() { + return kIsForcedDarkMode; + } + ++bool NativeTheme::IsForcedLightMode() { + static bool kIsForcedLightMode = + base::CommandLine::ForCurrentProcess()->HasSwitch( + "force-light-mode"); + return kIsForcedLightMode; +} + - } // namespace + bool NativeTheme::IsForcedHighContrast() { + static bool kIsForcedHighContrast = + base::CommandLine::ForCurrentProcess()->HasSwitch( +diff --git ui/native_theme/native_theme.h ui/native_theme/native_theme.h +index 3385e9e9d5690..54b69691383bf 100644 +--- ui/native_theme/native_theme.h ++++ ui/native_theme/native_theme.h +@@ -603,6 +603,9 @@ class NATIVE_THEME_EXPORT NativeTheme { + // Whether dark mode is forced via command-line flag. + static bool IsForcedDarkMode(); - // Helper object to respond to light mode/dark mode changeovers. -@@ -585,11 +592,15 @@ void NativeThemeMac::PaintSelectedMenuItem( ++ // Whether light mode is forced via command-line flag. ++ static bool IsForcedLightMode(); ++ + protected: + explicit NativeTheme( + bool should_only_use_dark_colors, +diff --git ui/native_theme/native_theme_mac.mm ui/native_theme/native_theme_mac.mm +index d8ff86972911d..c6cc9c70741c9 100644 +--- ui/native_theme/native_theme_mac.mm ++++ ui/native_theme/native_theme_mac.mm +@@ -585,11 +585,15 @@ void NativeThemeMac::PaintSelectedMenuItem( void NativeThemeMac::InitializeDarkModeStateAndObserver() { __block auto theme = this; diff --git a/patch/patches/linux_gtk_theme_3610.patch b/patch/patches/linux_gtk_theme_3610.patch new file mode 100644 index 000000000..86e269942 --- /dev/null +++ b/patch/patches/linux_gtk_theme_3610.patch @@ -0,0 +1,90 @@ +diff --git ui/gtk/gtk_ui.cc ui/gtk/gtk_ui.cc +index ab8f0d6b545b2..c4bd035f1cec4 100644 +--- ui/gtk/gtk_ui.cc ++++ ui/gtk/gtk_ui.cc +@@ -26,6 +26,7 @@ + #include "base/numerics/safe_conversions.h" + #include "base/observer_list.h" + #include "base/strings/string_split.h" ++#include "cef/libcef/features/features.h" + #include "chrome/browser/themes/theme_properties.h" // nogncheck + #include "third_party/skia/include/core/SkBitmap.h" + #include "third_party/skia/include/core/SkColor.h" +@@ -238,10 +239,15 @@ bool GtkUi::Initialize() { + }; + + GtkSettings* settings = gtk_settings_get_default(); ++ // Disable GTK theme change notifications because they are extremely slow. ++ // Light/dark theme changes will still be detected via DarkModeManagerLinux. ++ // See https://issues.chromium.org/issues/40280130#comment7 ++#if !BUILDFLAG(ENABLE_CEF) + connect(settings, "notify::gtk-theme-name", &GtkUi::OnThemeChanged); + connect(settings, "notify::gtk-icon-theme-name", &GtkUi::OnThemeChanged); + connect(settings, "notify::gtk-application-prefer-dark-theme", + &GtkUi::OnThemeChanged); ++#endif + connect(settings, "notify::gtk-cursor-theme-name", + &GtkUi::OnCursorThemeNameChanged); + connect(settings, "notify::gtk-cursor-theme-size", +diff --git ui/ozone/platform/x11/ozone_platform_x11.cc ui/ozone/platform/x11/ozone_platform_x11.cc +index 94012aae5f38d..852d736136faf 100644 +--- ui/ozone/platform/x11/ozone_platform_x11.cc ++++ ui/ozone/platform/x11/ozone_platform_x11.cc +@@ -64,6 +64,8 @@ namespace ui { + + namespace { + ++bool g_multi_threaded_message_loop = false; ++ + // Singleton OzonePlatform implementation for X11 platform. + class OzonePlatformX11 : public OzonePlatform, + public OSExchangeDataProviderFactoryOzone { +@@ -260,7 +262,15 @@ class OzonePlatformX11 : public OzonePlatform, + TouchFactory::SetTouchDeviceListFromCommandLine(); + + #if BUILDFLAG(USE_GTK) +- linux_ui_delegate_ = std::make_unique(); ++ // Not creating the LinuxUiDelegateX11 will disable creation of GtkUi ++ // (interface to GTK desktop features) and cause ui::GetDefaultLinuxUi() ++ // (and related functions) to return nullptr. We can't use GtkUi in ++ // combination with multi-threaded-message-loop because Chromium's GTK ++ // implementation doesn't use GDK threads. Light/dark theme changes will ++ // still be detected via DarkModeManagerLinux. ++ if (!g_multi_threaded_message_loop) { ++ linux_ui_delegate_ = std::make_unique(); ++ } + #endif + + menu_utils_ = std::make_unique(); +@@ -355,4 +365,8 @@ OzonePlatform* CreateOzonePlatformX11() { + return new OzonePlatformX11; + } + ++void SetMultiThreadedMessageLoopX11() { ++ g_multi_threaded_message_loop = true; ++} ++ + } // namespace ui +diff --git ui/ozone/platform/x11/ozone_platform_x11.h ui/ozone/platform/x11/ozone_platform_x11.h +index fd71ca6c81b7a..f1b7464b71e9d 100644 +--- ui/ozone/platform/x11/ozone_platform_x11.h ++++ ui/ozone/platform/x11/ozone_platform_x11.h +@@ -5,6 +5,8 @@ + #ifndef UI_OZONE_PLATFORM_X11_OZONE_PLATFORM_X11_H_ + #define UI_OZONE_PLATFORM_X11_OZONE_PLATFORM_X11_H_ + ++#include "base/component_export.h" ++ + namespace ui { + + class OzonePlatform; +@@ -12,6 +14,9 @@ class OzonePlatform; + // Constructor hook for use in ozone_platform_list.cc + OzonePlatform* CreateOzonePlatformX11(); + ++// Indicate that CEF is using multi-threaded-message-loop. ++COMPONENT_EXPORT(OZONE) void SetMultiThreadedMessageLoopX11(); ++ + } // namespace ui + + #endif // UI_OZONE_PLATFORM_X11_OZONE_PLATFORM_X11_H_ diff --git a/tests/cefclient/browser/client_handler.cc b/tests/cefclient/browser/client_handler.cc index a0c9cd89f..e1774f18f 100644 --- a/tests/cefclient/browser/client_handler.cc +++ b/tests/cefclient/browser/client_handler.cc @@ -52,8 +52,29 @@ enum client_menu_ids { CLIENT_ID_TESTMENU_RADIOITEM1, CLIENT_ID_TESTMENU_RADIOITEM2, CLIENT_ID_TESTMENU_RADIOITEM3, + + // Chrome theme selection. + CLIENT_ID_TESTMENU_THEME, + CLIENT_ID_TESTMENU_THEME_MODE_SYSTEM, + CLIENT_ID_TESTMENU_THEME_MODE_LIGHT, + CLIENT_ID_TESTMENU_THEME_MODE_DARK, + CLIENT_ID_TESTMENU_THEME_MODE_FIRST = CLIENT_ID_TESTMENU_THEME_MODE_SYSTEM, + CLIENT_ID_TESTMENU_THEME_MODE_LAST = CLIENT_ID_TESTMENU_THEME_MODE_DARK, + CLIENT_ID_TESTMENU_THEME_COLOR_DEFAULT, + CLIENT_ID_TESTMENU_THEME_COLOR_RED, + CLIENT_ID_TESTMENU_THEME_COLOR_GREEN, + CLIENT_ID_TESTMENU_THEME_COLOR_BLUE, + CLIENT_ID_TESTMENU_THEME_COLOR_FIRST = CLIENT_ID_TESTMENU_THEME_COLOR_DEFAULT, + CLIENT_ID_TESTMENU_THEME_COLOR_LAST = CLIENT_ID_TESTMENU_THEME_COLOR_BLUE, + CLIENT_ID_TESTMENU_THEME_CUSTOM, }; +// Constants for Chrome theme colors. +constexpr cef_color_t kColorTransparent = 0; +constexpr cef_color_t kColorRed = CefColorSetARGB(255, 255, 0, 0); +constexpr cef_color_t kColorGreen = CefColorSetARGB(255, 0, 255, 0); +constexpr cef_color_t kColorBlue = CefColorSetARGB(255, 0, 0, 255); + // Must match the value in client_renderer.cc. const char kFocusedNodeChangedMessage[] = "ClientRenderer.FocusedNodeChanged"; @@ -683,7 +704,7 @@ void ClientHandler::OnBeforeContextMenu(CefRefPtr browser, } // Test context menu features. - BuildTestMenu(model); + BuildTestMenu(browser, model); } if (delegate_) { @@ -722,7 +743,7 @@ bool ClientHandler::OnContextMenuCommand(CefRefPtr browser, SetOfflineState(browser, offline_); return true; default: // Allow default handling, if any. - return ExecuteTestMenu(command_id); + return ExecuteTestMenu(browser, command_id); } } @@ -1503,7 +1524,8 @@ void ClientHandler::NotifyTakeFocus(bool next) { } } -void ClientHandler::BuildTestMenu(CefRefPtr model) { +void ClientHandler::BuildTestMenu(CefRefPtr browser, + CefRefPtr model) { if (model->GetCount() > 0) { model->AddSeparator(); } @@ -1524,9 +1546,74 @@ void ClientHandler::BuildTestMenu(CefRefPtr model) { // Check the selected radio item. submenu->SetChecked( CLIENT_ID_TESTMENU_RADIOITEM1 + test_menu_state_.radio_item, true); + + // Build the theme sub menu. + CefRefPtr theme_menu = + model->AddSubMenu(CLIENT_ID_TESTMENU_THEME, "Theme"); + theme_menu->AddRadioItem(CLIENT_ID_TESTMENU_THEME_MODE_SYSTEM, "System", 1); + theme_menu->AddRadioItem(CLIENT_ID_TESTMENU_THEME_MODE_LIGHT, "Light", 1); + theme_menu->AddRadioItem(CLIENT_ID_TESTMENU_THEME_MODE_DARK, "Dark", 1); + theme_menu->AddSeparator(); + theme_menu->AddRadioItem(CLIENT_ID_TESTMENU_THEME_COLOR_DEFAULT, "Default", + 2); + theme_menu->AddRadioItem(CLIENT_ID_TESTMENU_THEME_COLOR_RED, "Red", 2); + theme_menu->AddRadioItem(CLIENT_ID_TESTMENU_THEME_COLOR_GREEN, "Green", 2); + theme_menu->AddRadioItem(CLIENT_ID_TESTMENU_THEME_COLOR_BLUE, "Blue", 2); + + if (MainContext::Get()->UseChromeRuntime()) { + theme_menu->AddSeparator(); + theme_menu->AddItem(CLIENT_ID_TESTMENU_THEME_CUSTOM, "Custom..."); + } + + auto request_context = browser->GetHost()->GetRequestContext(); + + int checked_mode_item = -1; + switch (request_context->GetChromeColorSchemeMode()) { + case CEF_COLOR_VARIANT_SYSTEM: + checked_mode_item = CLIENT_ID_TESTMENU_THEME_MODE_SYSTEM; + break; + case CEF_COLOR_VARIANT_LIGHT: + checked_mode_item = CLIENT_ID_TESTMENU_THEME_MODE_LIGHT; + break; + case CEF_COLOR_VARIANT_DARK: + checked_mode_item = CLIENT_ID_TESTMENU_THEME_MODE_DARK; + break; + default: + NOTREACHED(); + break; + } + + int checked_color_item = -1; + const cef_color_t color = request_context->GetChromeColorSchemeColor(); + if (color == kColorTransparent) { + checked_color_item = CLIENT_ID_TESTMENU_THEME_COLOR_DEFAULT; + } else if (color == kColorRed) { + checked_color_item = CLIENT_ID_TESTMENU_THEME_COLOR_RED; + } else if (color == kColorGreen) { + checked_color_item = CLIENT_ID_TESTMENU_THEME_COLOR_GREEN; + } else if (color == kColorBlue) { + checked_color_item = CLIENT_ID_TESTMENU_THEME_COLOR_BLUE; + } + + // Check the selected radio item, if any. + if (checked_mode_item != -1) { + theme_menu->SetChecked(checked_mode_item, true); + + // Update the selected item. + test_menu_state_.chrome_theme_mode_item = + checked_mode_item - CLIENT_ID_TESTMENU_THEME_MODE_FIRST; + } + if (checked_color_item != -1) { + theme_menu->SetChecked(checked_color_item, true); + + // Update the selected item. + test_menu_state_.chrome_theme_color_item = + checked_color_item - CLIENT_ID_TESTMENU_THEME_COLOR_FIRST; + } } -bool ClientHandler::ExecuteTestMenu(int command_id) { +bool ClientHandler::ExecuteTestMenu(CefRefPtr browser, + int command_id) { if (command_id == CLIENT_ID_TESTMENU_CHECKITEM) { // Toggle the check item. test_menu_state_.check_item ^= 1; @@ -1536,6 +1623,70 @@ bool ClientHandler::ExecuteTestMenu(int command_id) { // Store the selected radio item. test_menu_state_.radio_item = (command_id - CLIENT_ID_TESTMENU_RADIOITEM1); return true; + } else if (command_id >= CLIENT_ID_TESTMENU_THEME_MODE_FIRST && + command_id <= CLIENT_ID_TESTMENU_THEME_COLOR_LAST) { + int selected_mode_item = test_menu_state_.chrome_theme_mode_item; + if (command_id >= CLIENT_ID_TESTMENU_THEME_MODE_FIRST && + command_id <= CLIENT_ID_TESTMENU_THEME_MODE_LAST) { + selected_mode_item = command_id - CLIENT_ID_TESTMENU_THEME_MODE_FIRST; + if (selected_mode_item != test_menu_state_.chrome_theme_mode_item) { + // Update the selected item. + test_menu_state_.chrome_theme_mode_item = selected_mode_item; + } + } + + int selected_color_item = test_menu_state_.chrome_theme_color_item; + if (command_id >= CLIENT_ID_TESTMENU_THEME_COLOR_FIRST && + command_id <= CLIENT_ID_TESTMENU_THEME_COLOR_LAST) { + selected_color_item = command_id - CLIENT_ID_TESTMENU_THEME_COLOR_FIRST; + if (selected_color_item != test_menu_state_.chrome_theme_color_item) { + // Udpate the selected item. + test_menu_state_.chrome_theme_color_item = selected_color_item; + } + } + + // Don't change the color mode unless a selection has been made. + cef_color_variant_t variant = CEF_COLOR_VARIANT_TONAL_SPOT; + if (selected_mode_item != -1) { + switch (CLIENT_ID_TESTMENU_THEME_MODE_FIRST + selected_mode_item) { + case CLIENT_ID_TESTMENU_THEME_MODE_SYSTEM: + variant = CEF_COLOR_VARIANT_SYSTEM; + break; + case CLIENT_ID_TESTMENU_THEME_MODE_LIGHT: + variant = CEF_COLOR_VARIANT_LIGHT; + break; + case CLIENT_ID_TESTMENU_THEME_MODE_DARK: + variant = CEF_COLOR_VARIANT_DARK; + break; + default: + break; + } + } + + // Don't change the user color unless a selection has been made. + cef_color_t color = kColorTransparent; + if (selected_color_item != -1) { + switch (CLIENT_ID_TESTMENU_THEME_COLOR_FIRST + selected_color_item) { + case CLIENT_ID_TESTMENU_THEME_COLOR_RED: + color = kColorRed; + break; + case CLIENT_ID_TESTMENU_THEME_COLOR_GREEN: + color = kColorGreen; + break; + case CLIENT_ID_TESTMENU_THEME_COLOR_BLUE: + color = kColorBlue; + break; + default: + break; + } + } + + browser->GetHost()->GetRequestContext()->SetChromeColorScheme(variant, + color); + return true; + } else if (command_id == CLIENT_ID_TESTMENU_THEME_CUSTOM) { + browser->GetMainFrame()->LoadURL("chrome://settings/manageProfile"); + return true; } // Allow default handling to proceed. diff --git a/tests/cefclient/browser/client_handler.h b/tests/cefclient/browser/client_handler.h index 94389858e..398965400 100644 --- a/tests/cefclient/browser/client_handler.h +++ b/tests/cefclient/browser/client_handler.h @@ -345,8 +345,9 @@ class ClientHandler : public BaseClientHandler, void NotifyTakeFocus(bool next); // Test context menu creation. - void BuildTestMenu(CefRefPtr model); - bool ExecuteTestMenu(int command_id); + void BuildTestMenu(CefRefPtr browser, + CefRefPtr model); + bool ExecuteTestMenu(CefRefPtr browser, int command_id); void SetOfflineState(CefRefPtr browser, bool offline); @@ -394,11 +395,13 @@ class ClientHandler : public BaseClientHandler, // UI THREAD MEMBERS // The following members will only be accessed on the CEF UI thread. - // Track state information for the text context menu. + // Track state information for the test context menu. struct TestMenuState { TestMenuState() = default; bool check_item = true; int radio_item = 0; + int chrome_theme_mode_item = -1; + int chrome_theme_color_item = -1; } test_menu_state_; // Console logging state. diff --git a/tests/cefclient/browser/views_menu_bar.cc b/tests/cefclient/browser/views_menu_bar.cc index 14632b672..7bcbcb071 100644 --- a/tests/cefclient/browser/views_menu_bar.cc +++ b/tests/cefclient/browser/views_menu_bar.cc @@ -284,7 +284,7 @@ void ViewsMenuBar::MenuClosed(CefRefPtr menu_model) { void ViewsMenuBar::OnThemeChanged(CefRefPtr view) { // Apply colors when the theme changes. - views_style::ApplyTo(view); + views_style::OnThemeChanged(view); } void ViewsMenuBar::EnsureMenuPanel() { diff --git a/tests/cefclient/browser/views_overlay_controls.cc b/tests/cefclient/browser/views_overlay_controls.cc index 2840a8590..c9f9e7427 100644 --- a/tests/cefclient/browser/views_overlay_controls.cc +++ b/tests/cefclient/browser/views_overlay_controls.cc @@ -227,7 +227,7 @@ void ViewsOverlayControls::OnButtonPressed(CefRefPtr button) { void ViewsOverlayControls::OnThemeChanged(CefRefPtr view) { // Apply colors when the theme changes. - views_style::ApplyTo(view); + views_style::OnThemeChanged(view); } CefRefPtr ViewsOverlayControls::CreateButton(Command command) { diff --git a/tests/cefclient/browser/views_style.cc b/tests/cefclient/browser/views_style.cc index 4bbff7eb6..858a68585 100644 --- a/tests/cefclient/browser/views_style.cc +++ b/tests/cefclient/browser/views_style.cc @@ -4,6 +4,8 @@ #include "tests/cefclient/browser/views_style.h" +#include "include/cef_color_ids.h" +#include "include/views/cef_window.h" #include "tests/cefclient/browser/main_context.h" namespace client::views_style { @@ -73,7 +75,41 @@ void ApplyTo(CefRefPtr menu_model) { } } -void ApplyTo(CefRefPtr view) { +void ApplyTo(CefRefPtr window) { + if (!IsSet()) { + return; + } + + // Customize default background color. + window->SetThemeColor(CEF_ColorPrimaryBackground, g_background_color); + + // Customize default menu colors. + window->SetThemeColor(CEF_ColorMenuBackground, g_background_color); + window->SetThemeColor(CEF_ColorMenuItemBackgroundHighlighted, + g_background_hover_color); + window->SetThemeColor(CEF_ColorMenuItemBackgroundSelected, + g_background_hover_color); + window->SetThemeColor(CEF_ColorMenuSeparator, g_text_color); + window->SetThemeColor(CEF_ColorMenuItemForeground, g_text_color); + window->SetThemeColor(CEF_ColorMenuItemForegroundHighlighted, g_text_color); + window->SetThemeColor(CEF_ColorMenuItemForegroundSelected, g_text_color); + + // Customize default textfield colors. + window->SetThemeColor(CEF_ColorTextfieldBackground, g_background_color); + window->SetThemeColor(CEF_ColorTextfieldOutline, g_text_color); + + // Customize default Chrome toolbar colors. + window->SetThemeColor(CEF_ColorToolbar, g_background_color); + window->SetThemeColor(CEF_ColorToolbarText, g_text_color); + window->SetThemeColor(CEF_ColorToolbarButtonIcon, g_text_color); + window->SetThemeColor(CEF_ColorToolbarButtonText, g_text_color); + window->SetThemeColor(CEF_ColorLocationBarBackground, g_background_color); + window->SetThemeColor(CEF_ColorLocationBarBackgroundHovered, + g_background_hover_color); + window->SetThemeColor(CEF_ColorOmniboxText, g_text_color); +} + +void OnThemeChanged(CefRefPtr view) { if (!IsSet()) { return; } @@ -88,8 +124,6 @@ void ApplyTo(CefRefPtr view) { } else if (auto textfield = view->AsTextfield()) { textfield->SetTextColor(g_text_color); } - - view->SetBackgroundColor(g_background_color); } } // namespace client::views_style diff --git a/tests/cefclient/browser/views_style.h b/tests/cefclient/browser/views_style.h index 362f720c1..234186220 100644 --- a/tests/cefclient/browser/views_style.h +++ b/tests/cefclient/browser/views_style.h @@ -18,7 +18,8 @@ bool IsSet(); // Apply style to views objects. void ApplyTo(CefRefPtr menu_model); -void ApplyTo(CefRefPtr view); +void ApplyTo(CefRefPtr window); +void OnThemeChanged(CefRefPtr view); } // namespace client::views_style diff --git a/tests/cefclient/browser/views_window.cc b/tests/cefclient/browser/views_window.cc index 22c013a9e..90c4c8812 100644 --- a/tests/cefclient/browser/views_window.cc +++ b/tests/cefclient/browser/views_window.cc @@ -701,6 +701,12 @@ void ViewsWindow::OnWindowFullscreenTransition(CefRefPtr window, #endif } +void ViewsWindow::OnThemeColorsChanged(CefRefPtr window, + bool chrome_theme) { + // Apply color overrides to the current theme. + views_style::ApplyTo(window); +} + void ViewsWindow::OnWindowCreated(CefRefPtr window) { CEF_REQUIRE_UI_THREAD(); DCHECK(browser_view_); @@ -710,6 +716,13 @@ void ViewsWindow::OnWindowCreated(CefRefPtr window) { window_ = window; window_->SetID(ID_WINDOW); + // Apply color overrides to the current native/OS theme. This is only + // necessary until the CefBrowserView is added to the CefWindow, at which time + // the Chrome theme will be applied (triggering a call to OnThemeColorsChanged + // with |chrome_theme=true|). + views_style::ApplyTo(window_); + window_->ThemeChanged(); + delegate_->OnViewsWindowCreated(this); if (type_ == WindowType::NORMAL || type_ == WindowType::DEVTOOLS) { @@ -724,9 +737,6 @@ void ViewsWindow::OnWindowCreated(CefRefPtr window) { } } - // Set the background color for regions that are not obscured by other Views. - views_style::ApplyTo(window_.get()); - if (with_controls_ || with_overlay_controls_) { // Create the MenuModel that will be displayed via the menu button. CreateMenuModel(); @@ -1070,7 +1080,7 @@ void ViewsWindow::OnLayoutChanged(CefRefPtr view, void ViewsWindow::OnThemeChanged(CefRefPtr view) { // Apply colors when the theme changes. - views_style::ApplyTo(view); + views_style::OnThemeChanged(view); } void ViewsWindow::MenuBarExecuteCommand(CefRefPtr menu_model, @@ -1253,7 +1263,7 @@ void ViewsWindow::AddControls() { CreateMenuButton(); // Create the toolbar panel. - CefRefPtr panel = CefPanel::CreatePanel(nullptr); + CefRefPtr panel = CefPanel::CreatePanel(this); // Use a horizontal box layout for |panel|. CefBoxLayoutSettings panel_layout_settings; @@ -1387,7 +1397,7 @@ void ViewsWindow::UpdateExtensionControls() { } if (!extensions_panel_) { - extensions_panel_ = CefPanel::CreatePanel(nullptr); + extensions_panel_ = CefPanel::CreatePanel(this); // Use a horizontal box layout for |panel|. CefBoxLayoutSettings panel_layout_settings; diff --git a/tests/cefclient/browser/views_window.h b/tests/cefclient/browser/views_window.h index 155c2591d..5e1e0601d 100644 --- a/tests/cefclient/browser/views_window.h +++ b/tests/cefclient/browser/views_window.h @@ -193,6 +193,8 @@ class ViewsWindow : public CefBrowserViewDelegate, const CefKeyEvent& event) override; void OnWindowFullscreenTransition(CefRefPtr window, bool is_completed) override; + void OnThemeColorsChanged(CefRefPtr window, + bool chrome_theme) override; // CefViewDelegate methods: CefSize GetPreferredSize(CefRefPtr view) override; diff --git a/tests/ceftests/views/panel_unittest.cc b/tests/ceftests/views/panel_unittest.cc index 84e680d51..8f2bf66ad 100644 --- a/tests/ceftests/views/panel_unittest.cc +++ b/tests/ceftests/views/panel_unittest.cc @@ -2,6 +2,9 @@ // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. +#include + +#include "include/cef_color_ids.h" #include "include/views/cef_box_layout.h" #include "include/views/cef_fill_layout.h" #include "include/views/cef_layout.h" @@ -57,6 +60,15 @@ void CreatePanel(CefRefPtr delegate) { EXPECT_FALSE(panel->IsFocusable()); EXPECT_FALSE(panel->IsAccessibilityFocusable()); + // Background color can be configured without a Window. + const cef_color_t default_color = + panel->GetThemeColor(CEF_ColorPrimaryBackground); + const cef_color_t new_color = CefColorSetARGB(255, 0, 0, 255); + EXPECT_NE(default_color, new_color); + EXPECT_EQ(default_color, panel->GetBackgroundColor()); + panel->SetBackgroundColor(new_color); + EXPECT_EQ(new_color, panel->GetBackgroundColor()); + // Verify default Panel state. EXPECT_TRUE(panel->GetLayout().get()); EXPECT_EQ(0U, panel->GetChildViewCount()); @@ -578,6 +590,175 @@ void ChildDrawnImpl() { window->Close(); } +class ThemePanelDelegate : public CefPanelDelegate { + public: + ThemePanelDelegate() = default; + + void OnThemeChanged(CefRefPtr view) override { + theme_changed_ct_++; + + if (override_color_) { + view->SetBackgroundColor(*override_color_); + } + } + + size_t theme_changed_ct_ = 0; + std::optional override_color_; + + private: + IMPLEMENT_REFCOUNTING(ThemePanelDelegate); + DISALLOW_COPY_AND_ASSIGN(ThemePanelDelegate); +}; + +class ThemeWindowDelegate : public CefWindowDelegate { + public: + ThemeWindowDelegate() = default; + + void OnThemeChanged(CefRefPtr view) override { theme_changed_ct_++; } + + void OnThemeColorsChanged(CefRefPtr window, + bool chrome_theme) override { + native_theme_changed_ct_++; + } + + size_t theme_changed_ct_ = 0; + size_t native_theme_changed_ct_ = 0; + + private: + IMPLEMENT_REFCOUNTING(ThemeWindowDelegate); + DISALLOW_COPY_AND_ASSIGN(ThemeWindowDelegate); +}; + +void ChildThemeImpl() { + CefRefPtr parent_panel_delegate = + new ThemePanelDelegate(); + CefRefPtr parent_panel = + CefPanel::CreatePanel(parent_panel_delegate.get()); + + CefRefPtr child_panel_delegate = new ThemePanelDelegate(); + CefRefPtr child_panel = + CefPanel::CreatePanel(child_panel_delegate.get()); + + // No calls to OnThemeChanged (no Window yet). + EXPECT_EQ(0U, parent_panel_delegate->theme_changed_ct_); + EXPECT_EQ(0U, child_panel_delegate->theme_changed_ct_); + + parent_panel->AddChildView(child_panel); + + // No calls to OnThemeChanged (no Window yet). + EXPECT_EQ(0U, parent_panel_delegate->theme_changed_ct_); + EXPECT_EQ(0U, child_panel_delegate->theme_changed_ct_); + + // Create a Window. Triggers OnThemeChanged for the Window because it's also + // a View in the initial Window component hierarchy. + CefRefPtr window_delegate = new ThemeWindowDelegate(); + CefRefPtr window = + CefWindow::CreateTopLevelWindow(window_delegate.get()); + + // OnThemeChanged called for |window_delegate|. No calls to + // OnThemeColorsChanged. + EXPECT_EQ(0U, parent_panel_delegate->theme_changed_ct_); + EXPECT_EQ(0U, child_panel_delegate->theme_changed_ct_); + EXPECT_EQ(1U, window_delegate->theme_changed_ct_); + EXPECT_EQ(0U, window_delegate->native_theme_changed_ct_); + window_delegate->theme_changed_ct_ = 0; + + // Add |parent_panel| to the Window. Triggers OnThemeChanged for the component + // hierarchy starting with |parent_panel|. + window->AddChildView(parent_panel); + + // OnThemeChanged called for |parent_panel| and |child_panel|. No calls to + // OnThemeColorsChanged. + EXPECT_EQ(1U, parent_panel_delegate->theme_changed_ct_); + EXPECT_EQ(1U, child_panel_delegate->theme_changed_ct_); + EXPECT_EQ(0U, window_delegate->theme_changed_ct_); + EXPECT_EQ(0U, window_delegate->native_theme_changed_ct_); + parent_panel_delegate->theme_changed_ct_ = 0; + child_panel_delegate->theme_changed_ct_ = 0; + + // Verify that all components have the default background color. + const cef_color_t default_color = + window->GetThemeColor(CEF_ColorPrimaryBackground); + EXPECT_EQ(default_color, window->GetBackgroundColor()); + EXPECT_EQ(default_color, parent_panel->GetBackgroundColor()); + EXPECT_EQ(default_color, + parent_panel->GetThemeColor(CEF_ColorPrimaryBackground)); + EXPECT_EQ(default_color, child_panel->GetBackgroundColor()); + EXPECT_EQ(default_color, + child_panel->GetThemeColor(CEF_ColorPrimaryBackground)); + + // Change the default background color for the global theme. + const cef_color_t new_color = CefColorSetARGB(255, 0, 0, 255); + EXPECT_NE(default_color, new_color); + window->SetThemeColor(CEF_ColorPrimaryBackground, new_color); + EXPECT_EQ(new_color, window->GetThemeColor(CEF_ColorPrimaryBackground)); + + // Components don't get the change immediately. + EXPECT_EQ(default_color, window->GetBackgroundColor()); + EXPECT_EQ(default_color, parent_panel->GetBackgroundColor()); + EXPECT_EQ(default_color, child_panel->GetBackgroundColor()); + + // No calls to OnThemeChanged or OnThemeColorsChanged (pending ThemeChanged + // call). + EXPECT_EQ(0U, parent_panel_delegate->theme_changed_ct_); + EXPECT_EQ(0U, child_panel_delegate->theme_changed_ct_); + EXPECT_EQ(0U, window_delegate->theme_changed_ct_); + EXPECT_EQ(0U, window_delegate->native_theme_changed_ct_); + + // Trigger OnThemeChanged calls. + window->ThemeChanged(); + + // OnThemeChanged called for the complete component hierarchy. No calls to + // OnThemeColorsChanged. + EXPECT_EQ(1U, parent_panel_delegate->theme_changed_ct_); + EXPECT_EQ(1U, child_panel_delegate->theme_changed_ct_); + EXPECT_EQ(1U, window_delegate->theme_changed_ct_); + EXPECT_EQ(0U, window_delegate->native_theme_changed_ct_); + parent_panel_delegate->theme_changed_ct_ = 0; + child_panel_delegate->theme_changed_ct_ = 0; + window_delegate->theme_changed_ct_ = 0; + + // Verify that all components have the new background color. + EXPECT_EQ(new_color, window->GetBackgroundColor()); + EXPECT_EQ(new_color, parent_panel->GetBackgroundColor()); + EXPECT_EQ(new_color, parent_panel->GetThemeColor(CEF_ColorPrimaryBackground)); + EXPECT_EQ(new_color, child_panel->GetBackgroundColor()); + EXPECT_EQ(new_color, child_panel->GetThemeColor(CEF_ColorPrimaryBackground)); + + // Customize the background color for |child_panel| when OnThemeChanged is + // called next. + const cef_color_t child_color = CefColorSetARGB(255, 0, 255, 0); + child_panel_delegate->override_color_ = child_color; + + // Trigger OnThemeChanged calls. + window->ThemeChanged(); + + // OnThemeChanged called for the complete component hierarchy. No calls to + // OnThemeColorsChanged. + EXPECT_EQ(1U, parent_panel_delegate->theme_changed_ct_); + EXPECT_EQ(1U, child_panel_delegate->theme_changed_ct_); + EXPECT_EQ(1U, window_delegate->theme_changed_ct_); + EXPECT_EQ(0U, window_delegate->native_theme_changed_ct_); + parent_panel_delegate->theme_changed_ct_ = 0; + child_panel_delegate->theme_changed_ct_ = 0; + window_delegate->theme_changed_ct_ = 0; + + // Verify that all components have the expected background color. + EXPECT_EQ(new_color, window->GetBackgroundColor()); + EXPECT_EQ(new_color, parent_panel->GetBackgroundColor()); + EXPECT_EQ(new_color, parent_panel->GetThemeColor(CEF_ColorPrimaryBackground)); + EXPECT_EQ(child_color, child_panel->GetBackgroundColor()); + EXPECT_EQ(new_color, child_panel->GetThemeColor(CEF_ColorPrimaryBackground)); + + // New Window gets the same (new) background color. + CefRefPtr new_window = CefWindow::CreateTopLevelWindow(nullptr); + EXPECT_EQ(new_color, new_window->GetBackgroundColor()); + + // Restore the default background color for the global theme. + window->SetThemeColor(CEF_ColorPrimaryBackground, default_color); + EXPECT_EQ(default_color, window->GetThemeColor(CEF_ColorPrimaryBackground)); +} + } // namespace // Test child behaviors. @@ -586,6 +767,7 @@ PANEL_TEST(ChildAddRemoveMultiple) PANEL_TEST(ChildOrder) PANEL_TEST(ChildVisible) PANEL_TEST(ChildDrawn) +PANEL_TEST(ChildTheme) namespace {