| // Copyright 2025 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/webui_browser/webui_browser_window.h" |
| |
| #include "base/notimplemented.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/accelerator_table.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_element_identifiers.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_window/public/browser_window_features.h" |
| #include "chrome/browser/ui/find_bar/find_bar.h" |
| #include "chrome/browser/ui/views/find_bar_host.h" |
| #include "chrome/browser/ui/views/side_panel/side_panel_ui_base.h" |
| #include "chrome/browser/ui/web_applications/app_browser_controller.h" |
| #include "chrome/browser/ui/webui_browser/webui_browser_client_view.h" |
| #include "chrome/browser/ui/webui_browser/webui_browser_extensions_container.h" |
| #include "chrome/browser/ui/webui_browser/webui_browser_modal_dialog_host.h" |
| #include "chrome/browser/ui/webui_browser/webui_browser_side_panel_ui.h" |
| #include "chrome/browser/ui/webui_browser/webui_browser_ui.h" |
| #include "chrome/browser/ui/webui_browser/webui_browser_web_contents_delegate.h" |
| #include "chrome/browser/ui/webui_browser/webui_location_bar.h" |
| #include "chrome/common/chrome_render_frame.mojom.h" |
| #include "chrome/common/webui_url_constants.h" |
| #include "components/input/native_web_keyboard_event.h" |
| #include "components/sharing_message/sharing_dialog_data.h" |
| #include "components/web_modal/web_contents_modal_dialog_manager.h" |
| #include "content/public/browser/keyboard_event_processing_result.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" |
| #include "third_party/blink/public/mojom/page/draggable_region.mojom.h" |
| #include "ui/base/interaction/element_tracker.h" |
| #include "ui/content_accelerators/accelerator_util.h" |
| #include "ui/views/controls/webview/webview.h" |
| #include "ui/views/interaction/element_tracker_views.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/views/widget/widget_delegate.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h" |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| namespace { |
| |
| const char* const kWebUIBrowserWindowKey = "__WEBUI_BROWSER_WINDOW__"; |
| |
| // Copied from chrome/browser/ui/views/frame/browser_widget.cc. |
| bool IsUsingLinuxSystemTheme(Profile* profile) { |
| #if BUILDFLAG(IS_LINUX) |
| return ThemeServiceFactory::GetForProfile(profile)->UsingSystemTheme(); |
| #else |
| return false; |
| #endif |
| } |
| |
| // WebShell is the WebContents that hosts the top-chrome WebUI. This UserData |
| // establishes a link from WebShell to WebUIBrowserWindow. |
| class WebShellWebContentsUserData : public base::SupportsUserData::Data { |
| public: |
| constexpr static char Key[] = "webshell-user-data"; |
| explicit WebShellWebContentsUserData(WebUIBrowserWindow* browser_window) |
| : browser_window_(browser_window) {} |
| |
| raw_ptr<WebUIBrowserWindow> browser_window_; |
| }; |
| |
| 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 |
| |
| class WebUIBrowserWindow::WidgetDelegate : public views::WidgetDelegate { |
| public: |
| explicit WidgetDelegate( |
| WebUIBrowserWindow* window, |
| WebUIBrowserWebContentsDelegate* web_contents_delegate); |
| |
| views::ClientView* CreateClientView(views::Widget* widget) override; |
| std::u16string GetWindowTitle() const override; |
| |
| private: |
| raw_ptr<WebUIBrowserWindow> browser_window_; |
| raw_ptr<WebUIBrowserWebContentsDelegate> web_contents_delegate_; |
| }; |
| |
| WebUIBrowserWindow::WebUIBrowserWindow(Browser* browser) : browser_(browser) { |
| location_bar_ = std::make_unique<WebUILocationBar>(this); |
| web_contents_delegate_ = |
| std::make_unique<WebUIBrowserWebContentsDelegate>(this); |
| widget_delegate_ = |
| std::make_unique<WidgetDelegate>(this, web_contents_delegate_.get()); |
| widget_ = std::make_unique<views::Widget>(); |
| widget_->AddObserver(this); |
| views::Widget::InitParams params( |
| views::Widget::InitParams::CLIENT_OWNS_WIDGET); |
| params.name = "WebUIBrowserWindow"; |
| params.bounds = gfx::Rect(0, 0, 800, 600); |
| params.delegate = widget_delegate_.get(); |
| params.native_widget = CreateNativeWidget(); |
| widget_->Init(std::move(params)); |
| widget_->SetNativeWindowProperty(kWebUIBrowserWindowKey, this); |
| widget_->MakeCloseSynchronous(base::BindOnce( |
| &WebUIBrowserWindow::OnWindowCloseRequested, base::Unretained(this))); |
| auto web_view = std::make_unique<views::WebView>(browser_->profile()); |
| |
| auto* ui_web_contents = web_view->GetWebContents(); |
| web_contents_delegate_->SetUIWebContents(ui_web_contents); |
| ui_web_contents->SetDelegate(web_contents_delegate_.get()); |
| ui_web_contents->SetUserData( |
| WebShellWebContentsUserData::Key, |
| std::make_unique<WebShellWebContentsUserData>(this)); |
| |
| modal_dialog_host_ = std::make_unique<WebUIBrowserModalDialogHost>(this); |
| extensions_container_ = |
| std::make_unique<WebUIBrowserExtensionsContainer>(*browser_, *this); |
| |
| web_view->LoadInitialURL(GURL(chrome::kChromeUIWebuiBrowserURL)); |
| web_view_ = widget_->SetClientContentsView(std::move(web_view)); |
| // Set the ColorProviderSource after attaching to the WebView otherwise |
| // attaching overwrites it. |
| // TODO(webium): |widget_| should use |this| as its ColorProviderSource as |
| // secondary UIs need it to get the correct color mode from their parent |
| // widget. |
| ui_web_contents->SetColorProviderSource(this); |
| |
| widget_->Show(); |
| // Give our main web contents the focus so that accelerators work. |
| ui_web_contents->SetInitialFocus(); |
| |
| LoadAccelerators(); |
| } |
| |
| WebUIBrowserWindow::~WebUIBrowserWindow() { |
| browser_->GetFeatures().TearDownPreBrowserWindowDestruction(); |
| web_view_ = nullptr; |
| // We want to destroy the extensions container before the `widget_` since |
| // it wants to de-register itself for focus stuff. |
| extensions_container_.reset(); |
| widget_->RemoveObserver(this); |
| widget_.reset(); |
| } |
| |
| // static |
| WebUIBrowserWindow* WebUIBrowserWindow::FromWebShellWebContents( |
| content::WebContents* web_contents) { |
| WebShellWebContentsUserData* user_data = |
| static_cast<WebShellWebContentsUserData*>( |
| web_contents->GetUserData(WebShellWebContentsUserData::Key)); |
| |
| if (!user_data) { |
| return nullptr; |
| } |
| |
| return user_data->browser_window_; |
| } |
| |
| // static |
| WebUIBrowserWindow* WebUIBrowserWindow::FromBrowser(Browser* browser) { |
| // This function is implemented based on |
| // BrowserView::GetBrowserViewForBrowser(). Please see the comments in that |
| // function for the implementation rationale. |
| if (!browser->window() || !browser->window()->GetNativeWindow()) { |
| return nullptr; |
| } |
| return FromNativeWindow(browser->window()->GetNativeWindow()); |
| } |
| |
| // static |
| WebUIBrowserWindow* WebUIBrowserWindow::FromNativeWindow( |
| gfx::NativeWindow window) { |
| views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window); |
| return widget ? reinterpret_cast<WebUIBrowserWindow*>( |
| widget->GetNativeWindowProperty(kWebUIBrowserWindowKey)) |
| : nullptr; |
| } |
| |
| void WebUIBrowserWindow::Show() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::ShowInactive() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::Hide() { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::IsVisible() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void WebUIBrowserWindow::SetBounds(const gfx::Rect& bounds) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::Close() { |
| widget_->Close(); |
| |
| // This will not close the window immediately. |
| // Instead, we send the close request to the OS, then the OS notifies us that |
| // such a request has been made. This results in the invocation of |
| // OnWindowCloseRequested(), which gives unload handlers |
| // a chance to stop the closing. When all unload handlers are clear, Close() |
| // will be called again. This time the close request will go through and the |
| // window will be actually closed. |
| } |
| |
| void WebUIBrowserWindow::Activate() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::Deactivate() { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::IsActive() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void WebUIBrowserWindow::FlashFrame(bool flash) { |
| NOTIMPLEMENTED(); |
| } |
| |
| ui::ZOrderLevel WebUIBrowserWindow::GetZOrderLevel() const { |
| NOTIMPLEMENTED(); |
| return ui::ZOrderLevel::kNormal; |
| } |
| |
| void WebUIBrowserWindow::SetZOrderLevel(ui::ZOrderLevel order) { |
| NOTIMPLEMENTED(); |
| } |
| |
| gfx::NativeWindow WebUIBrowserWindow::GetNativeWindow() const { |
| #if BUILDFLAG(IS_CHROMEOS) |
| // Ash ChromeOS has a UaF on widget's aura::Window during browser shutdown. |
| // The window is stored in apps::InstanceRegistry which becomes dangling after |
| // the BrowserWindow is destroyed. |
| // TODO(webium): Fix ChromeOS. Run WebUIBrowserTest.StartupAndShutdown |
| // to verify. |
| return gfx::NativeWindow(); |
| #else |
| return widget_->GetNativeWindow(); |
| #endif |
| } |
| |
| bool WebUIBrowserWindow::IsOnCurrentWorkspace() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool WebUIBrowserWindow::IsVisibleOnScreen() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void WebUIBrowserWindow::SetTopControlsShownRatio( |
| content::WebContents* web_contents, |
| float ratio) { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::DoBrowserControlsShrinkRendererSize( |
| const content::WebContents* contents) const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| ui::NativeTheme* WebUIBrowserWindow::GetNativeTheme() { |
| return ui::NativeTheme::GetInstanceForNativeUi(); |
| } |
| |
| const ui::ThemeProvider* WebUIBrowserWindow::GetThemeProvider() const { |
| // Copied from BrowserWidget::GetThemeProvider(). |
| 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()); |
| } |
| |
| const ui::ColorProvider* WebUIBrowserWindow::GetColorProvider() const { |
| return ui::ColorProviderManager::Get().GetColorProviderFor( |
| GetColorProviderKey()); |
| } |
| |
| ui::ColorProviderKey::ThemeInitializerSupplier* |
| WebUIBrowserWindow::GetThemeInitializerSupplier() const { |
| // Do not return any custom theme if this is an incognito browser. |
| if (browser_->profile()->IsIncognitoProfile()) { |
| return nullptr; |
| } |
| |
| 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(); |
| } |
| |
| ui::ColorProviderKey WebUIBrowserWindow::GetColorProviderKey() const { |
| auto key = ui::NativeTheme::GetInstanceForNativeUi()->GetColorProviderKey( |
| GetThemeInitializerSupplier()); |
| |
| key.app_controller = browser_->app_controller(); |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| // ChromeOS SystemWebApps use the OS theme all the time. |
| if (ash::IsSystemWebApp(browser_)) { |
| return key; |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| const auto* theme_service = |
| ThemeServiceFactory::GetForProfile(browser_->profile()); |
| CHECK(theme_service); |
| |
| // Determine appropriate key.color_mode. |
| [this, &key, theme_service]() { |
| // Currently the incognito browser is implemented as unthemed dark mode. |
| if (browser_->profile()->IsIncognitoProfile()) { |
| 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; |
| } |
| }(); |
| |
| // Determine appropriate key.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; |
| } |
| } |
| |
| // Determine appropriate key.user_color_source. |
| if (browser_->profile()->IsIncognitoProfile()) { |
| 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; |
| } |
| |
| // Determine appropriate key.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); |
| } |
| |
| // Determine appropriate key.frame_type. |
| // TODO(webium): special windows might need FrameType::kNative. |
| key.frame_type = ui::ColorProviderKey::FrameType::kChromium; |
| |
| #if BUILDFLAG(IS_WIN) |
| if (theme_service && theme_service->UsingDeviceTheme()) { |
| key.frame_style = ui::ColorProviderKey::FrameStyle::kSystem; |
| } |
| #endif |
| |
| return key; |
| } |
| |
| ui::RendererColorMap WebUIBrowserWindow::GetRendererColorMap( |
| ui::ColorProviderKey::ColorMode color_mode, |
| ui::ColorProviderKey::ForcedColors forced_colors) const { |
| auto key = GetColorProviderKey(); |
| key.color_mode = color_mode; |
| key.forced_colors = forced_colors; |
| ui::ColorProvider* color_provider = |
| ui::ColorProviderManager::Get().GetColorProviderFor(key); |
| CHECK(color_provider); |
| return ui::CreateRendererColorMap(*color_provider); |
| } |
| |
| bool WebUIBrowserWindow::GetAcceleratorForCommandId( |
| int command_id, |
| ui::Accelerator* accelerator) const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void WebUIBrowserWindow::OnWidgetBoundsChanged(views::Widget* widget, |
| const gfx::Rect& new_bounds) { |
| DCHECK_EQ(widget, widget_.get()); |
| if (modal_dialog_host_) { |
| modal_dialog_host_->NotifyPositionRequiresUpdate(); |
| } |
| } |
| |
| gfx::Rect WebUIBrowserWindow::GetContentsBoundsInScreen() const { |
| ui::TrackedElement* content_region = |
| ui::ElementTracker::GetElementTracker()->GetFirstMatchingElement( |
| kContentsContainerViewElementId, |
| views::ElementTrackerViews::GetContextForWidget(widget_.get())); |
| return content_region->GetScreenBounds(); |
| } |
| |
| ui::TrackedElement* WebUIBrowserWindow::GetExtensionsMenuButtonAnchor() const { |
| return ui::ElementTracker::GetElementTracker()->GetFirstMatchingElement( |
| kExtensionsMenuButtonElementId, |
| views::ElementTrackerViews::GetContextForWidget(widget_.get())); |
| } |
| |
| void WebUIBrowserWindow::DeleteBrowserWindow() { |
| delete this; |
| } |
| |
| bool WebUIBrowserWindow::FindCommandIdForAccelerator( |
| const ui::Accelerator& accelerator, |
| int* command_id) const { |
| auto iter = accelerator_table_.find(accelerator); |
| if (iter == accelerator_table_.end()) { |
| return false; |
| } |
| |
| *command_id = iter->second; |
| if (accelerator.IsRepeat() && !IsCommandRepeatable(*command_id)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void WebUIBrowserWindow::LoadAccelerators() { |
| // Let's fill our own accelerator table. |
| const bool is_app_mode = IsRunningInForcedAppMode(); |
| #if BUILDFLAG(IS_CHROMEOS) |
| const bool is_captive_portal_signin_window = |
| browser_->profile()->IsOffTheRecord() && |
| browser_->profile()->GetOTRProfileID().IsCaptivePortal(); |
| #endif |
| const std::vector<AcceleratorMapping> accelerator_list(GetAcceleratorList()); |
| for (const auto& entry : accelerator_list) { |
| // In app mode, only allow accelerators of allowlisted commands to pass |
| // through. |
| if (is_app_mode && !IsCommandAllowedInAppMode(entry.command_id, |
| browser_->is_type_popup())) { |
| continue; |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| if (is_captive_portal_signin_window) { |
| int command = entry.command_id; |
| // Captive portal signin uses an OTR profile without history. |
| if (command == IDC_SHOW_HISTORY) { |
| continue; |
| } |
| // The NewTab command expects navigation to occur in the same browser |
| // window. For captive portal signin this is not the case, so hide these |
| // to reduce confusion. |
| if (command == IDC_NEW_TAB || command == IDC_NEW_TAB_TO_RIGHT || |
| command == IDC_CREATE_NEW_TAB_GROUP) { |
| continue; |
| } |
| } |
| #endif |
| |
| ui::Accelerator accelerator(entry.keycode, entry.modifiers); |
| accelerator_table_[accelerator] = entry.command_id; |
| accelerator_manager_.Register( |
| {accelerator}, ui::AcceleratorManager::kNormalPriority, this); |
| } |
| } |
| |
| bool WebUIBrowserWindow::AcceleratorPressed( |
| const ui::Accelerator& accelerator) { |
| int command_id; |
| // Though AcceleratorManager should not send unknown |accelerator| to us, it's |
| // still possible the command cannot be executed now. |
| if (!FindCommandIdForAccelerator(accelerator, &command_id)) { |
| return false; |
| } |
| |
| return chrome::ExecuteCommand(browser_.get(), command_id, |
| accelerator.time_stamp()); |
| } |
| |
| bool WebUIBrowserWindow::CanHandleAccelerators() const { |
| return true; |
| } |
| |
| int WebUIBrowserWindow::GetTopControlsHeight() const { |
| NOTIMPLEMENTED(); |
| return 0; |
| } |
| |
| void WebUIBrowserWindow::SetTopControlsGestureScrollInProgress( |
| bool in_progress) { |
| NOTIMPLEMENTED(); |
| } |
| |
| std::vector<StatusBubble*> WebUIBrowserWindow::GetStatusBubbles() { |
| NOTIMPLEMENTED(); |
| return {}; |
| } |
| |
| void WebUIBrowserWindow::UpdateTitleBar() { |
| widget_->UpdateWindowTitle(); |
| // TODO(webium): The icon might also need updating. |
| } |
| |
| void WebUIBrowserWindow::BookmarkBarStateChanged( |
| BookmarkBar::AnimateChangeType change_type) { |
| GetWebUIBrowserUI()->BookmarkBarStateChanged(change_type); |
| } |
| |
| void WebUIBrowserWindow::TemporarilyShowBookmarkBar(base::TimeDelta duration) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::UpdateDevTools( |
| content::WebContents* inspected_web_contents) { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::CanDockDevTools() const { |
| // This forces DevTools to open in a new window, which is currently necessary |
| // because the code path for a launching docked DevTools requires BrowserView, |
| // ContentsContainerView, etc. |
| return false; |
| } |
| |
| void WebUIBrowserWindow::UpdateLoadingAnimations(bool is_visible) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::SetStarredState(bool is_starred) { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::IsTabModalPopupDeprecated() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void WebUIBrowserWindow::SetIsTabModalPopupDeprecated( |
| bool is_tab_modal_popup_deprecated) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::OnActiveTabChanged(content::WebContents* old_contents, |
| content::WebContents* new_contents, |
| int index, |
| int reason) { |
| // New tabs have their ColorProviderSource set to the Widget initially. |
| // Set the ColorProviderSource back to |this| when they're first activated. |
| // This is a no-op if it's already set to |this|. |
| new_contents->SetColorProviderSource(this); |
| |
| // State of extensions depends on what's active --- e.g. some may be disabled |
| // on some URLs. |
| extensions_container_->NotifyOfAllActions(); |
| |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::OnTabDetached(content::WebContents* contents, |
| bool was_active) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::ZoomChangedForActiveTab(bool can_show_bubble) { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::ShouldHideUIForFullscreen() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool WebUIBrowserWindow::IsFullscreenBubbleVisible() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool WebUIBrowserWindow::IsForceFullscreen() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void WebUIBrowserWindow::SetForceFullscreen(bool force_fullscreen) { |
| NOTIMPLEMENTED(); |
| } |
| |
| gfx::Size WebUIBrowserWindow::GetContentsSize() const { |
| NOTIMPLEMENTED(); |
| return gfx::Size(); |
| } |
| |
| void WebUIBrowserWindow::SetContentsSize(const gfx::Size& size) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::UpdatePageActionIcon(PageActionIconType type) { |
| NOTIMPLEMENTED(); |
| } |
| |
| autofill::AutofillBubbleHandler* |
| WebUIBrowserWindow::GetAutofillBubbleHandler() { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| void WebUIBrowserWindow::ExecutePageActionIconForTesting( |
| PageActionIconType type) { |
| NOTIMPLEMENTED(); |
| } |
| |
| LocationBar* WebUIBrowserWindow::GetLocationBar() const { |
| return location_bar_.get(); |
| } |
| |
| void WebUIBrowserWindow::SetFocusToLocationBar(bool is_user_initiated) { |
| if (webui_browser::mojom::Page* page = GetWebUIBrowserUI()->page()) { |
| page->SetFocusToLocationBar(is_user_initiated); |
| } |
| } |
| |
| void WebUIBrowserWindow::UpdateReloadStopState(bool is_loading, bool force) { |
| if (webui_browser::mojom::Page* page = GetWebUIBrowserUI()->page()) { |
| page->SetReloadStopState(is_loading); |
| } |
| } |
| |
| void WebUIBrowserWindow::UpdateToolbar(content::WebContents* contents) { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::UpdateToolbarSecurityState() { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void WebUIBrowserWindow::UpdateCustomTabBarVisibility(bool visible, |
| bool animate) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::SetDevToolsScrimVisibility(bool visible) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::ResetToolbarTabState(content::WebContents* contents) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::FocusToolbar() { |
| NOTIMPLEMENTED(); |
| } |
| |
| ExtensionsContainer* WebUIBrowserWindow::GetExtensionsContainer() { |
| return extensions_container_.get(); |
| } |
| |
| void WebUIBrowserWindow::ToolbarSizeChanged(bool is_animating) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::TabDraggingStatusChanged(bool is_dragging) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::LinkOpeningFromGesture( |
| WindowOpenDisposition disposition) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::FocusAppMenu() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::FocusBookmarksToolbar() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::FocusInactivePopupForAccessibility() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::RotatePaneFocus(bool forwards) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::FocusWebContentsPane() { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::IsBookmarkBarVisible() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool WebUIBrowserWindow::IsBookmarkBarAnimating() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool WebUIBrowserWindow::IsTabStripEditable() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void WebUIBrowserWindow::SetTabStripNotEditableForTesting() { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::IsToolbarVisible() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool WebUIBrowserWindow::IsToolbarShowing() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool WebUIBrowserWindow::IsLocationBarVisible() const { |
| return true; |
| } |
| |
| SharingDialog* WebUIBrowserWindow::ShowSharingDialog( |
| content::WebContents* contents, |
| SharingDialogData data) { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| void WebUIBrowserWindow::ShowUpdateChromeDialog() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::ShowIntentPickerBubble( |
| std::vector<apps::IntentPickerAppInfo> app_info, |
| bool show_stay_in_chrome, |
| bool show_remember_selection, |
| apps::IntentPickerBubbleType bubble_type, |
| const std::optional<url::Origin>& initiating_origin, |
| IntentPickerResponse callback) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::ShowBookmarkBubble(const GURL& url, |
| bool already_bookmarked) { |
| NOTIMPLEMENTED(); |
| } |
| |
| sharing_hub::ScreenshotCapturedBubble* |
| WebUIBrowserWindow::ShowScreenshotCapturedBubble(content::WebContents* contents, |
| const gfx::Image& image) { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| qrcode_generator::QRCodeGeneratorBubbleView* |
| WebUIBrowserWindow::ShowQRCodeGeneratorBubble(content::WebContents* contents, |
| const GURL& url, |
| bool show_back_button) { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| send_tab_to_self::SendTabToSelfBubbleView* |
| WebUIBrowserWindow::ShowSendTabToSelfDevicePickerBubble( |
| content::WebContents* contents) { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| send_tab_to_self::SendTabToSelfBubbleView* |
| WebUIBrowserWindow::ShowSendTabToSelfPromoBubble(content::WebContents* contents, |
| bool show_signin_button) { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| views::Button* WebUIBrowserWindow::GetSharingHubIconButton() { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| void WebUIBrowserWindow::ToggleMultitaskMenu() { |
| NOTIMPLEMENTED(); |
| } |
| #else |
| sharing_hub::SharingHubBubbleView* WebUIBrowserWindow::ShowSharingHubBubble( |
| share::ShareAttempt attempt) { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| ShowTranslateBubbleResult WebUIBrowserWindow::ShowTranslateBubble( |
| content::WebContents* contents, |
| translate::TranslateStep step, |
| const std::string& source_language, |
| const std::string& target_language, |
| translate::TranslateErrors error_type, |
| bool is_user_gesture) { |
| NOTIMPLEMENTED(); |
| return ShowTranslateBubbleResult::BROWSER_WINDOW_NOT_VALID; |
| } |
| |
| void WebUIBrowserWindow::StartPartialTranslate( |
| const std::string& source_language, |
| const std::string& target_language, |
| const std::u16string& text_selection) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::ShowOneClickSigninConfirmation( |
| const std::u16string& email, |
| base::OnceCallback<void(bool)> confirmed_callback) { |
| NOTIMPLEMENTED(); |
| } |
| |
| views::View* WebUIBrowserWindow::GetTopContainer() { |
| // This view is technically the entire window, not just the top container. |
| // We return it because the BookmarkContextMenu constructor needs to be able |
| // get to a NativeWindow whenever the context menu is triggered from the |
| // bookmarks side panel, and uses |
| // browser_window->TopContainer()->GetWidget()->GetNativeWindow(). |
| return web_view_; |
| } |
| |
| views::View* WebUIBrowserWindow::GetLensOverlayView() { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| DownloadBubbleUIController* |
| WebUIBrowserWindow::GetDownloadBubbleUIController() { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| void WebUIBrowserWindow::ConfirmBrowserCloseWithPendingDownloads( |
| int download_count, |
| Browser::DownloadCloseType dialog_type, |
| base::OnceCallback<void(bool)> callback) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::UserChangedTheme( |
| BrowserThemeChangeType theme_change_type) { |
| NotifyColorProviderChanged(); |
| extensions_container_->NotifyOfAllActions(); // Icons may need re-rendering. |
| } |
| |
| void WebUIBrowserWindow::ShowAppMenu() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::PreHandleDragUpdate(const content::DropData& drop_data, |
| const gfx::PointF& point) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::PreHandleDragExit() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::HandleDragEnded() { |
| NOTIMPLEMENTED(); |
| } |
| |
| content::KeyboardEventProcessingResult |
| WebUIBrowserWindow::PreHandleKeyboardEvent( |
| const input::NativeWebKeyboardEvent& event) { |
| if ((event.GetType() != blink::WebInputEvent::Type::kRawKeyDown) && |
| (event.GetType() != blink::WebInputEvent::Type::kKeyUp)) { |
| return content::KeyboardEventProcessingResult::NOT_HANDLED; |
| } |
| |
| ui::Accelerator accelerator = |
| ui::GetAcceleratorFromNativeWebKeyboardEvent(event); |
| |
| // What we have to do here is as follows: |
| // - If the |browser_| is for an app, do nothing. |
| // - On CrOS if |accelerator| is deprecated, we allow web contents to consume |
| // it if needed. |
| // - If the |browser_| is not for an app, and the |accelerator| is not |
| // associated with the browser (e.g. an Ash shortcut), process it. |
| // - If the |browser_| is not for an app, and the |accelerator| is associated |
| // with the browser, and it is a reserved one (e.g. Ctrl+w), process it. |
| // - If the |browser_| is not for an app, and the |accelerator| is associated |
| // with the browser, and it is not a reserved one, do nothing. |
| |
| if (browser_->is_type_app() || browser_->is_type_app_popup()) { |
| // Let all keys fall through to a v1 app's web content, even accelerators. |
| // We don't use NOT_HANDLED_IS_SHORTCUT here. If we do that, the app |
| // might not be able to see a subsequent Char event. See OnHandleInputEvent |
| // in content/renderer/render_widget.cc for details. |
| return content::KeyboardEventProcessingResult::NOT_HANDLED; |
| } |
| |
| int command_id; |
| if (!FindCommandIdForAccelerator(accelerator, &command_id)) { |
| return content::KeyboardEventProcessingResult::NOT_HANDLED; |
| } |
| |
| // TODO(webium): Handle shortcuts that are registered in the FocusManager. |
| // We handle only browser window shortcuts here. Secondary UIs can |
| // registered their own shortcuts (e.g. Ctrl+Enter closes the Find Bar) via |
| // FocusManager::RegisterAccelerator(). |
| if (accelerator_manager_.Process(accelerator)) { |
| return content::KeyboardEventProcessingResult::HANDLED; |
| } |
| |
| // BrowserView does not register RELEASED accelerators. So if we can find the |
| // command id from |accelerator_table_|, it must be a keydown event. This |
| // DCHECK ensures we won't accidentally return NOT_HANDLED for a later added |
| // RELEASED accelerator in BrowserView. |
| DCHECK_EQ(event.GetType(), blink::WebInputEvent::Type::kRawKeyDown); |
| // |accelerator| is a non-reserved browser shortcut (e.g. Ctrl+f). |
| return content::KeyboardEventProcessingResult::NOT_HANDLED_IS_SHORTCUT; |
| } |
| |
| // These functions have Mac implementations in webui_browser_window_mac.mm. |
| #if !BUILDFLAG(IS_MAC) |
| bool WebUIBrowserWindow::HandleKeyboardEvent( |
| const input::NativeWebKeyboardEvent& event) { |
| return false; |
| } |
| |
| views::NativeWidget* WebUIBrowserWindow::CreateNativeWidget() { |
| return nullptr; |
| } |
| #endif |
| |
| std::unique_ptr<FindBar> WebUIBrowserWindow::CreateFindBar() { |
| return std::make_unique<FindBarHost>( |
| browser_->GetFeatures().find_bar_owner()); |
| } |
| |
| web_modal::WebContentsModalDialogHost* |
| WebUIBrowserWindow::GetWebContentsModalDialogHost() { |
| return modal_dialog_host_.get(); |
| } |
| |
| web_modal::WebContentsModalDialogHost* |
| WebUIBrowserWindow::GetWebContentsModalDialogHostFor( |
| content::WebContents* web_contents) { |
| return modal_dialog_host_.get(); |
| } |
| |
| void WebUIBrowserWindow::ShowAvatarBubbleFromAvatarButton( |
| bool is_source_accelerator) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::MaybeShowProfileSwitchIPH() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::MaybeShowSupervisedUserProfileSignInIPH() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::ShowHatsDialog( |
| const std::string& site_id, |
| const std::optional<std::string>& hats_histogram_name, |
| const std::optional<uint64_t> hats_survey_ukm_id, |
| base::OnceClosure success_callback, |
| base::OnceClosure failure_callback, |
| const SurveyBitsData& product_specific_bits_data, |
| const SurveyStringData& product_specific_string_data) { |
| NOTIMPLEMENTED(); |
| } |
| |
| ExclusiveAccessContext* WebUIBrowserWindow::GetExclusiveAccessContext() { |
| return this; |
| } |
| |
| std::string WebUIBrowserWindow::GetWorkspace() const { |
| NOTIMPLEMENTED(); |
| return std::string(); |
| } |
| |
| bool WebUIBrowserWindow::IsVisibleOnAllWorkspaces() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void WebUIBrowserWindow::ShowEmojiPanel() { |
| NOTIMPLEMENTED(); |
| } |
| |
| std::unique_ptr<content::EyeDropper> WebUIBrowserWindow::OpenEyeDropper( |
| content::RenderFrameHost* frame, |
| content::EyeDropperListener* listener) { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| void WebUIBrowserWindow::ShowCaretBrowsingDialog() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::CreateTabSearchBubble( |
| tab_search::mojom::TabSearchSection section, |
| tab_search::mojom::TabOrganizationFeature organization_feature) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::CloseTabSearchBubble() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::ShowIncognitoClearBrowsingDataDialog() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::ShowIncognitoHistoryDisclaimerDialog() { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::IsBorderlessModeEnabled() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void WebUIBrowserWindow::OnWebApiWindowResizableChanged() { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::GetCanResize() { |
| return widget_delegate_->CanResize(); |
| } |
| |
| ui::mojom::WindowShowState WebUIBrowserWindow::GetWindowShowState() const { |
| if (IsMaximized()) { |
| return ui::mojom::WindowShowState::kMaximized; |
| } else if (IsMinimized()) { |
| return ui::mojom::WindowShowState::kMinimized; |
| } else if (IsFullscreen()) { |
| return ui::mojom::WindowShowState::kFullscreen; |
| } else { |
| return ui::mojom::WindowShowState::kDefault; |
| } |
| } |
| |
| void WebUIBrowserWindow::ShowChromeLabs() { |
| NOTIMPLEMENTED(); |
| } |
| |
| views::WebView* WebUIBrowserWindow::GetContentsWebView() { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| BrowserView* WebUIBrowserWindow::AsBrowserView() { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| gfx::Rect WebUIBrowserWindow::GetBounds() const { |
| return widget_->GetWindowBoundsInScreen(); |
| } |
| |
| bool WebUIBrowserWindow::IsMaximized() const { |
| return widget_->IsMaximized(); |
| } |
| |
| bool WebUIBrowserWindow::IsMinimized() const { |
| return widget_->IsMinimized(); |
| } |
| |
| bool WebUIBrowserWindow::IsFullscreen() const { |
| return widget_->IsFullscreen(); |
| } |
| |
| gfx::Rect WebUIBrowserWindow::GetRestoredBounds() const { |
| NOTIMPLEMENTED(); |
| return gfx::Rect(); |
| } |
| |
| ui::mojom::WindowShowState WebUIBrowserWindow::GetRestoredState() const { |
| NOTIMPLEMENTED(); |
| return ui::mojom::WindowShowState::kDefault; |
| } |
| |
| void WebUIBrowserWindow::Maximize() { |
| widget_->Maximize(); |
| } |
| |
| void WebUIBrowserWindow::Minimize() { |
| widget_->Minimize(); |
| } |
| |
| void WebUIBrowserWindow::Restore() { |
| widget_->Restore(); |
| } |
| |
| Profile* WebUIBrowserWindow::GetProfile() { |
| return browser_->profile(); |
| } |
| |
| void WebUIBrowserWindow::EnterFullscreen( |
| const url::Origin& origin, |
| ExclusiveAccessBubbleType bubble_type, |
| FullscreenTabParams fullscreen_tab_params) { |
| // TODO(webium): Implement this. |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::ExitFullscreen() { |
| // TODO(webium): Implement this. |
| NOTIMPLEMENTED(); |
| } |
| |
| void WebUIBrowserWindow::UpdateExclusiveAccessBubble( |
| const ExclusiveAccessBubbleParams& params, |
| ExclusiveAccessBubbleHideCallback first_hide_callback) { |
| // TODO(webium): Implement this. |
| NOTIMPLEMENTED(); |
| } |
| |
| bool WebUIBrowserWindow::IsExclusiveAccessBubbleDisplayed() const { |
| // TODO(webium): Implement this. |
| return false; |
| } |
| |
| void WebUIBrowserWindow::OnExclusiveAccessUserInput() { |
| // TODO(webium): Implement this. |
| } |
| |
| content::WebContents* WebUIBrowserWindow::GetWebContentsForExclusiveAccess() { |
| return browser_->tab_strip_model()->GetActiveWebContents(); |
| } |
| |
| bool WebUIBrowserWindow::CanUserEnterFullscreen() const { |
| // TODO(webium): Implement this. |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool WebUIBrowserWindow::CanUserExitFullscreen() const { |
| // TODO(webium): Implement this. |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void WebUIBrowserWindow::OnWindowCloseRequested( |
| views::Widget::ClosedReason close_reason) { |
| // TODO(webium): don't close a window during tab dragging. |
| |
| // Give beforeunload handlers, the user, or policy the chance to cancel the |
| // close before we hide the window below. |
| if (!browser_->HandleBeforeClose()) { |
| // Need to reset the synchronous close callback after each Close() call as |
| // it's reset once used. Close() is generally called twice during shutdown. |
| widget_->MakeCloseSynchronous(base::BindOnce( |
| &WebUIBrowserWindow::OnWindowCloseRequested, base::Unretained(this))); |
| return; |
| } |
| |
| browser_->OnWindowClosing(); |
| if (!browser_->tab_strip_model()->empty()) { |
| // Tab strip isn't empty. Hide the frame (so it appears to have closed |
| // immediately) and close all the tabs, allowing the renderers to shut |
| // down. When the tab strip is empty we'll be called back again. |
| widget_->Hide(); |
| } |
| } |
| |
| WebUIBrowserWindow::WidgetDelegate::WidgetDelegate( |
| WebUIBrowserWindow* window, |
| WebUIBrowserWebContentsDelegate* web_contents_delegate) |
| : browser_window_(window), web_contents_delegate_(web_contents_delegate) { |
| // TODO(webium): May want to override these for Apps or Picture-in-picture. |
| SetCanResize(browser_window_->browser_->create_params().can_resize); |
| SetCanMaximize(browser_window_->browser_->create_params().can_maximize); |
| SetCanFullscreen(browser_window_->browser_->create_params().can_fullscreen); |
| SetCanMinimize(true); |
| } |
| |
| views::ClientView* WebUIBrowserWindow::WidgetDelegate::CreateClientView( |
| views::Widget* widget) { |
| return new WebUIBrowserClientView(web_contents_delegate_, widget, |
| TransferOwnershipOfContentsView()); |
| } |
| |
| std::u16string WebUIBrowserWindow::WidgetDelegate::GetWindowTitle() const { |
| // TODO(webium): BrowserView::GetWindowTitle() has some magic for media |
| // on Mac. |
| return browser_window_->browser()->GetWindowTitleForCurrentTab( |
| true /* include_app_name */); |
| } |
| |
| WebUIBrowserUI* WebUIBrowserWindow::GetWebUIBrowserUI() const { |
| return web_contents_delegate_->web_contents() |
| ->GetWebUI() |
| ->GetController() |
| ->GetAs<WebUIBrowserUI>(); |
| } |
| |
| void WebUIBrowserWindow::ShowSidePanel(SidePanelEntryKey side_panel_entry_key) { |
| GetWebUIBrowserUI()->ShowSidePanel(side_panel_entry_key); |
| } |
| |
| void WebUIBrowserWindow::CloseSidePanel() { |
| GetWebUIBrowserUI()->CloseSidePanel(); |
| } |
| |
| WebUIBrowserSidePanelUI* WebUIBrowserWindow::GetWebUIBrowserSidePanelUI() { |
| return static_cast<WebUIBrowserSidePanelUI*>( |
| browser_->browser_window_features()->side_panel_ui()); |
| } |