| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/views/frame/browser_widget.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/command_line.h" |
| #include "base/containers/fixed_flat_map.h" |
| #include "base/debug/leak_annotations.h" |
| #include "base/functional/bind.h" |
| #include "base/i18n/rtl.h" |
| #include "base/metrics/user_metrics.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/app_mode/app_mode_utils.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/themes/custom_theme_supplier.h" |
| #include "chrome/browser/themes/theme_service.h" |
| #include "chrome/browser/themes/theme_service_factory.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_window/public/browser_window_features.h" |
| #include "chrome/browser/ui/browser_window_state.h" |
| #include "chrome/browser/ui/views/frame/browser_frame_view.h" |
| #include "chrome/browser/ui/views/frame/browser_native_widget.h" |
| #include "chrome/browser/ui/views/frame/browser_native_widget_factory.h" |
| #include "chrome/browser/ui/views/frame/browser_root_view.h" |
| #include "chrome/browser/ui/views/frame/browser_view.h" |
| #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" |
| #include "chrome/browser/ui/views/frame/system_menu_model_builder.h" |
| #include "chrome/browser/ui/views/frame/top_container_view.h" |
| #include "chrome/browser/ui/web_applications/app_browser_controller.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "ui/base/hit_test.h" |
| #include "ui/base/mojom/menu_source_type.mojom-forward.h" |
| #include "ui/base/mojom/themes.mojom.h" |
| #include "ui/base/mojom/window_show_state.mojom.h" |
| #include "ui/color/color_provider_key.h" |
| #include "ui/events/event_handler.h" |
| #include "ui/views/controls/menu/menu_runner.h" |
| #include "ui/views/widget/native_widget.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h" |
| #include "chromeos/ui/base/window_properties.h" |
| #include "chromeos/ui/base/window_state_type.h" |
| #include "chromeos/ui/wm/desks/desks_helper.h" |
| #include "components/user_manager/user_manager.h" |
| #include "ui/aura/window.h" |
| #endif |
| |
| #if BUILDFLAG(IS_LINUX) |
| #include "ui/display/screen.h" |
| #include "ui/linux/linux_ui.h" |
| #endif |
| |
| #if BUILDFLAG(IS_WIN) |
| #include "chrome/browser/win/mica_titlebar.h" |
| #endif |
| |
| namespace { |
| |
| // Helper to track whether a ThemeChange event has been received by the widget. |
| class ThemeChangedObserver : public views::WidgetObserver { |
| public: |
| explicit ThemeChangedObserver(views::Widget* widget) { |
| widget_observation.Observe(widget); |
| } |
| ThemeChangedObserver(const ThemeChangedObserver&) = delete; |
| ThemeChangedObserver& operator=(const ThemeChangedObserver&) = delete; |
| ~ThemeChangedObserver() override = default; |
| |
| // views::WidgetObserver: |
| void OnWidgetThemeChanged(views::Widget* widget) override { |
| theme_changed_ = true; |
| } |
| |
| bool theme_changed() const { return theme_changed_; } |
| |
| private: |
| bool theme_changed_ = false; |
| base::ScopedObservation<views::Widget, views::WidgetObserver> |
| widget_observation{this}; |
| }; |
| |
| bool IsUsingLinuxSystemTheme(Profile* profile) { |
| #if BUILDFLAG(IS_LINUX) |
| return ThemeServiceFactory::GetForProfile(profile)->UsingSystemTheme(); |
| #else |
| return false; |
| #endif |
| } |
| |
| 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, SV>({ |
| {BCV::kTonalSpot, SV::kTonalSpot}, |
| {BCV::kNeutral, SV::kNeutral}, |
| {BCV::kVibrant, SV::kVibrant}, |
| {BCV::kExpressive, SV::kExpressive}, |
| }); |
| return kSchemeVariantMap.at(color_variant); |
| } |
| |
| } // namespace |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // BrowserWidget, public: |
| |
| BrowserWidget::BrowserWidget(BrowserView* browser_view) |
| : browser_native_widget_(nullptr), |
| root_view_(nullptr), |
| browser_frame_view_(nullptr), |
| browser_view_(browser_view) { |
| set_is_secondary_widget(false); |
| // Don't focus anything on creation, selecting a tab will set the focus. |
| set_focus_on_creation(false); |
| } |
| |
| BrowserWidget::~BrowserWidget() { |
| set_widget_closed(); |
| |
| // Synchronously destroy owned Widgets, which are typically owned by the |
| // BrowserWidget's NativeWidget, to mitigate the risk of dangling pointers to |
| // Browser and related objects during destruction. |
| views::Widget::ForEachOwnedWidget(GetNativeView(), |
| [this](views::Widget* widget) { |
| if (widget != this) { |
| widget->CloseNow(); |
| } |
| }); |
| |
| // Invoke the pre-window-destruction lifecycle hook before the owned |
| // BrowserView is destroyed. |
| // Do this here and not in ~BrowserView() as BrowserWindowFeatures may attempt |
| // to read state on the BrowserWidget as they undergo destruction, and |
| // BrowserWidget state is destroyed at the end of this scope. |
| browser_view_->browser()->GetFeatures().TearDownPreBrowserWindowDestruction(); |
| } |
| |
| void BrowserWidget::InitBrowserWidget() { |
| browser_native_widget_ = |
| BrowserNativeWidgetFactory::CreateBrowserNativeWidget(this, |
| browser_view_); |
| views::Widget::InitParams params = browser_native_widget_->GetWidgetParams( |
| views::Widget::InitParams::CLIENT_OWNS_WIDGET); |
| params.name = "BrowserWidget"; |
| params.delegate = browser_view_; |
| |
| Browser* browser = browser_view_->browser(); |
| if (browser->is_type_picture_in_picture()) { |
| params.z_order = ui::ZOrderLevel::kFloatingWindow; |
| params.visible_on_all_workspaces = true; |
| #if !BUILDFLAG(IS_WIN) |
| // This has the side-effect of keeping the pip window in the tab order. |
| // |
| // On all platforms, except for Windows, this doesn't change anything |
| // visually. If this is set for the Windows platform, the UI will be |
| // affected. Specifically, the title bar will not render correctly, see |
| // https://crbug.com/1456231 for more details. |
| params.remove_standard_frame = true; |
| #endif // !BUILDFLAG(IS_WIN) |
| } |
| |
| #if BUILDFLAG(IS_OZONE) |
| params.inhibit_keyboard_shortcuts = |
| browser->is_type_app() || browser->is_type_app_popup(); |
| |
| params.session_data = browser->platform_session_data(); |
| #endif |
| |
| if (browser_native_widget_->ShouldRestorePreviousBrowserWidgetState()) { |
| if (browser->is_type_normal() || browser->is_type_devtools() || |
| browser->is_type_app()) { |
| // Typed panel/popup can only return a size once the widget has been |
| // created. |
| // DevTools counts as a popup, but DevToolsWindow::CreateDevToolsBrowser |
| // ensures there is always a size available. Without this, the tools |
| // launch on the wrong display and can have sizing issues when |
| // repositioned to the saved bounds in Widget::SetInitialBounds. |
| chrome::GetSavedWindowBoundsAndShowState(browser, ¶ms.bounds, |
| ¶ms.show_state); |
| |
| params.workspace = browser->initial_workspace(); |
| if (browser_native_widget_->ShouldUseInitialVisibleOnAllWorkspaces()) { |
| params.visible_on_all_workspaces = |
| browser->initial_visible_on_all_workspaces_state(); |
| } |
| const base::CommandLine& parsed_command_line = |
| *base::CommandLine::ForCurrentProcess(); |
| |
| if (parsed_command_line.HasSwitch(switches::kWindowWorkspace)) { |
| params.workspace = |
| parsed_command_line.GetSwitchValueASCII(switches::kWindowWorkspace); |
| } |
| } |
| } |
| |
| Init(std::move(params)); |
| |
| #if BUILDFLAG(IS_LINUX) |
| SelectNativeTheme(); |
| #else |
| SetNativeTheme(ui::NativeTheme::GetInstanceForNativeUi()); |
| #endif |
| |
| if (!browser_native_widget_->UsesNativeSystemMenu()) { |
| DCHECK(non_client_view()); |
| non_client_view()->set_context_menu_controller(this); |
| } |
| } |
| |
| BrowserFrameView* BrowserWidget::GetFrameView() const { |
| return browser_frame_view_; |
| } |
| |
| bool BrowserWidget::ShouldSaveWindowPlacement() const { |
| return browser_native_widget_ && |
| browser_native_widget_->ShouldSaveWindowPlacement(); |
| } |
| |
| void BrowserWidget::GetWindowPlacement( |
| gfx::Rect* bounds, |
| ui::mojom::WindowShowState* show_state) const { |
| if (browser_native_widget_) { |
| browser_native_widget_->GetWindowPlacement(bounds, show_state); |
| } |
| } |
| |
| content::KeyboardEventProcessingResult BrowserWidget::PreHandleKeyboardEvent( |
| const input::NativeWebKeyboardEvent& event) { |
| return browser_native_widget_ |
| ? browser_native_widget_->PreHandleKeyboardEvent(event) |
| : content::KeyboardEventProcessingResult::NOT_HANDLED; |
| } |
| |
| bool BrowserWidget::HandleKeyboardEvent( |
| const input::NativeWebKeyboardEvent& event) { |
| return browser_native_widget_ && |
| browser_native_widget_->HandleKeyboardEvent(event); |
| } |
| |
| void BrowserWidget::UserChangedTheme(BrowserThemeChangeType theme_change_type) { |
| // kWebAppTheme is triggered by web apps and will only change colors, not the |
| // frame type; just refresh the theme on all views in the browser window. |
| if (theme_change_type == BrowserThemeChangeType::kWebAppTheme) { |
| ThemeChanged(); |
| return; |
| } |
| |
| // RegenerateFrameOnThemeChange() may or may not result in an implicit call to |
| // ThemeChanged(), regardless of whether the frame was regenerated or not. |
| // Ensure that ThemeChanged() is called for this Widget if no implicit call |
| // occurred. |
| // TODO(crbug.com/40280130): The entire theme propagation system needs to be |
| // moved to scheduling theme changes rather than synchronously demanding a |
| // ThemeChange() event take place. This will reduce a ton of churn resulting |
| // from independent clients increasingly issuing theme change requests. |
| ThemeChangedObserver theme_changed_observer(this); |
| RegenerateFrameOnThemeChange(theme_change_type); |
| |
| if (theme_change_type == BrowserThemeChangeType::kBrowserTheme) { |
| // When the browser theme changes, the NativeTheme may also change. |
| SelectNativeTheme(); |
| |
| // Browser theme changes are directly observed by the BrowserWidget. However |
| // the other Widgets in the frame's hierarchy may inherit this new theme |
| // information in their ColorProviderKeys and thus should also be forwarded |
| // theme change notifications. |
| Widget::Widgets widgets = GetAllOwnedWidgets(GetNativeView()); |
| for (Widget* widget : widgets) { |
| widget->ThemeChanged(); |
| } |
| } |
| |
| if (!theme_changed_observer.theme_changed()) { |
| ThemeChanged(); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // BrowserWidget, views::Widget overrides: |
| |
| views::internal::RootView* BrowserWidget::CreateRootView() { |
| root_view_ = new BrowserRootView(browser_view_, this); |
| return root_view_; |
| } |
| |
| std::unique_ptr<views::FrameView> BrowserWidget::CreateFrameView() { |
| auto browser_frame_view = chrome::CreateBrowserFrameView(this, browser_view_); |
| browser_frame_view_ = browser_frame_view.get(); |
| return browser_frame_view; |
| } |
| |
| bool BrowserWidget::GetAccelerator(int command_id, |
| ui::Accelerator* accelerator) const { |
| return browser_view_->GetAccelerator(command_id, accelerator); |
| } |
| |
| const ui::ThemeProvider* BrowserWidget::GetThemeProvider() const { |
| Browser* browser = browser_view_->browser(); |
| auto* app_controller = browser->app_controller(); |
| // 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: |
| // https://crbug.com/1219073. |
| if (app_controller && (!IsUsingLinuxSystemTheme(browser->profile()) || |
| app_controller->AppUsesWindowControlsOverlay())) { |
| return app_controller->GetThemeProvider(); |
| } |
| return &ThemeService::GetThemeProviderForProfile(browser->profile()); |
| } |
| |
| ui::ColorProviderKey::ThemeInitializerSupplier* BrowserWidget::GetCustomTheme() |
| const { |
| // Do not return any custom theme if this is an incognito browser. |
| if (IsIncognitoBrowser()) { |
| return nullptr; |
| } |
| |
| Browser* browser = browser_view_->browser(); |
| auto* app_controller = browser->app_controller(); |
| // 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: |
| // https://crbug.com/1219073. |
| if (app_controller && (!IsUsingLinuxSystemTheme(browser->profile()) || |
| app_controller->AppUsesWindowControlsOverlay())) { |
| return app_controller->GetThemeSupplier(); |
| } |
| auto* theme_service = ThemeServiceFactory::GetForProfile(browser->profile()); |
| return theme_service->UsingDeviceTheme() ? nullptr |
| : theme_service->GetThemeSupplier(); |
| } |
| |
| void BrowserWidget::OnNativeWidgetWorkspaceChanged() { |
| chrome::SaveWindowWorkspace(browser_view_->browser(), GetWorkspace()); |
| chrome::SaveWindowVisibleOnAllWorkspaces(browser_view_->browser(), |
| IsVisibleOnAllWorkspaces()); |
| #if BUILDFLAG(IS_LINUX) |
| // If the window was sent to a different workspace, prioritize it if |
| // it was sent to the current workspace and deprioritize it |
| // otherwise. This is done by MoveBrowsersInWorkspaceToFront() |
| // which reorders the browsers such that the ones in the current |
| // workspace appear before ones in other workspaces. |
| auto workspace = display::Screen::Get()->GetCurrentWorkspace(); |
| if (!workspace.empty()) { |
| BrowserList::MoveBrowsersInWorkspaceToFront(workspace); |
| } |
| #endif |
| Widget::OnNativeWidgetWorkspaceChanged(); |
| } |
| |
| void BrowserWidget::OnNativeWidgetDestroyed() { |
| browser_native_widget_ = nullptr; |
| Browser* const browser = browser_view_->browser(); |
| |
| // Current expectations are that the Browser is destroyed synchronously when |
| // its NativeWidget is destroyed. Prepare Browser and request synchronous |
| // destruction here. |
| // TODO(crbug.com/413168662): Once clients have been migrated away from |
| // closing Browsers via their NativeWidgets explore removing this completely. |
| browser->set_force_skip_warning_user_on_close(true); |
| browser->OnWindowClosing(); |
| Widget::OnNativeWidgetDestroyed(); |
| browser->SynchronouslyDestroyBrowser(); |
| } |
| |
| void BrowserWidget::ShowContextMenuForViewImpl( |
| views::View* source, |
| const gfx::Point& p, |
| ui::mojom::MenuSourceType source_type) { |
| if (IsRunningInForcedAppMode()) { |
| return; |
| } |
| |
| // Do not show context menu for Document picture-in-picture browser. Context: |
| // http://b/274862709. |
| if (browser_view_->browser()->is_type_picture_in_picture()) { |
| return; |
| } |
| |
| // Don't show a menu if a tab drag is active. https://crbug.com/1517709 |
| if (tab_drag_kind_ != TabDragKind::kNone) { |
| return; |
| } |
| |
| // Only show context menu if point is in unobscured parts of browser, i.e. |
| // if NonClientHitTest returns : |
| // - HTCAPTION: in title bar or unobscured part of tabstrip |
| // - HTNOWHERE: as the name implies. |
| gfx::Point point_in_view_coords(p); |
| views::View::ConvertPointFromScreen(non_client_view(), &point_in_view_coords); |
| int hit_test = non_client_view()->NonClientHitTest(point_in_view_coords); |
| if (hit_test == HTCAPTION || hit_test == HTNOWHERE) { |
| menu_runner_ = std::make_unique<views::MenuRunner>( |
| GetSystemMenuModel(), |
| views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU, |
| base::BindRepeating(&BrowserWidget::OnMenuClosed, |
| base::Unretained(this))); |
| menu_runner_->RunMenuAt(source->GetWidget(), nullptr, |
| gfx::Rect(p, gfx::Size(0, 0)), |
| views::MenuAnchorPosition::kTopLeft, source_type); |
| base::RecordAction(base::UserMetricsAction("SystemContextMenu_Opened")); |
| } |
| } |
| |
| bool BrowserWidget::IsMenuRunnerRunningForTesting() const { |
| return menu_runner_ ? menu_runner_->IsRunning() : false; |
| } |
| |
| ui::MenuModel* BrowserWidget::GetSystemMenuModel() { |
| // TODO(b/271137301): Refactor this class to remove chromeos specific code to |
| // subclasses. |
| if (!menu_model_builder_.get()) { |
| menu_model_builder_ = std::make_unique<SystemMenuModelBuilder>( |
| browser_view_, browser_view_->browser()); |
| } |
| menu_model_builder_->Init(); |
| return menu_model_builder_->menu_model(); |
| } |
| |
| void BrowserWidget::SetTabDragKind(TabDragKind tab_drag_kind) { |
| if (tab_drag_kind_ == tab_drag_kind) { |
| return; |
| } |
| |
| if (browser_native_widget_) { |
| browser_native_widget_->TabDraggingKindChanged(tab_drag_kind); |
| } |
| |
| bool was_dragging_any = tab_drag_kind_ != TabDragKind::kNone; |
| bool is_dragging_any = tab_drag_kind != TabDragKind::kNone; |
| if (was_dragging_any != is_dragging_any) { |
| browser_view_->TabDraggingStatusChanged(is_dragging_any); |
| } |
| |
| tab_drag_kind_ = tab_drag_kind; |
| } |
| |
| void BrowserWidget::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) { |
| UserChangedTheme(BrowserThemeChangeType::kNativeTheme); |
| } |
| |
| ui::ColorProviderKey BrowserWidget::GetColorProviderKey() const { |
| auto key = Widget::GetColorProviderKey(); |
| |
| key.app_controller = browser_view_->browser()->app_controller(); |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| // ChromeOS SystemWebApps use the OS theme all the time. |
| if (ash::IsSystemWebApp(browser_view_->browser())) { |
| return key; |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| const auto* theme_service = |
| ThemeServiceFactory::GetForProfile(browser_view_->browser()->profile()); |
| CHECK(theme_service); |
| |
| // color_mode. |
| [this, &key, theme_service]() { |
| // Currently the incognito browser is implemented as unthemed dark mode. |
| if (IsIncognitoBrowser()) { |
| key.color_mode = ui::ColorProviderKey::ColorMode::kDark; |
| return; |
| } |
| |
| 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 (IsIncognitoBrowser()) { |
| key.user_color_source = ui::ColorProviderKey::UserColorSource::kGrayscale; |
| } else 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. |
| const bool use_custom_frame = |
| browser_native_widget_ && browser_native_widget_->UseCustomFrame(); |
| key.frame_type = use_custom_frame ? ui::ColorProviderKey::FrameType::kChromium |
| : ui::ColorProviderKey::FrameType::kNative; |
| #if BUILDFLAG(IS_WIN) |
| if (theme_service && theme_service->UsingDeviceTheme() && use_custom_frame) { |
| key.frame_style = ui::ColorProviderKey::FrameStyle::kSystem; |
| } |
| #endif |
| |
| return key; |
| } |
| |
| void BrowserWidget::OnMenuClosed() { |
| menu_runner_.reset(); |
| } |
| |
| void BrowserWidget::SelectNativeTheme() { |
| #if BUILDFLAG(IS_LINUX) |
| // Use the regular NativeTheme instance if running incognito mode, regardless |
| // of system theme (gtk, qt etc). |
| ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi(); |
| if (IsIncognitoBrowser()) { |
| 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: |
| // https://crbug.com/1219073. |
| const auto* linux_ui_theme = |
| ui::LinuxUiTheme::GetForWindow(GetNativeWindow()); |
| SetNativeTheme(linux_ui_theme && |
| !browser_view_->AppUsesWindowControlsOverlay() |
| ? linux_ui_theme->GetNativeTheme() |
| : native_theme); |
| #endif |
| } |
| |
| void BrowserWidget::OnTouchUiChanged() { |
| client_view()->InvalidateLayout(); |
| |
| // For standard browser frame, if we do not invalidate the FrameView |
| // the client window bounds will not be properly updated which could cause |
| // visual artifacts. See crbug.com/1035959 for details. |
| if (non_client_view()->frame_view()) { |
| // Note that invalidating a view invalidates all of its ancestors, so it is |
| // not necessary to also invalidate the NonClientView or RootView here. |
| non_client_view()->frame_view()->InvalidateLayout(); |
| } else { |
| non_client_view()->InvalidateLayout(); |
| } |
| GetRootView()->InvalidateLayout(); |
| } |
| |
| bool BrowserWidget::RegenerateFrameOnThemeChange( |
| BrowserThemeChangeType theme_change_type) { |
| bool need_regenerate = false; |
| #if BUILDFLAG(IS_LINUX) |
| // System and user theme changes can both change frame buttons, so the frame |
| // always needs to be regenerated on Linux. |
| need_regenerate = true; |
| #endif |
| |
| #if BUILDFLAG(IS_WIN) |
| // On Windows, DWM transition does not performed for a frame regeneration in |
| // fullscreen mode, so do a lighweight theme change to refresh a bookmark bar |
| // on new tab. (see crbug/1002480) |
| // With Mica, toggling titlebar accent colors in the native theme needs a |
| // frame regen to switch between the system-drawn and custom-drawn titlebars. |
| need_regenerate |= |
| (theme_change_type == BrowserThemeChangeType::kBrowserTheme || |
| SystemTitlebarCanUseMicaMaterial()) && |
| !IsFullscreen(); |
| #else |
| need_regenerate |= theme_change_type == BrowserThemeChangeType::kBrowserTheme; |
| #endif |
| |
| if (need_regenerate) { |
| // This is a heavyweight theme change that requires regenerating the frame |
| // as well as repainting the browser window. |
| // Calling FrameTypeChanged() may or may not result in an implicit call to |
| // ThemeChanged(). |
| FrameTypeChanged(); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool BrowserWidget::IsIncognitoBrowser() const { |
| return browser_view_->browser()->profile()->IsIncognitoProfile(); |
| } |