// Copyright (c) 2016 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 "tests/cefclient/browser/views_window.h" #include #include "include/base/cef_bind.h" #include "include/base/cef_build.h" #include "include/cef_app.h" #include "include/views/cef_box_layout.h" #include "include/wrapper/cef_helpers.h" #include "tests/cefclient/browser/resource.h" #include "tests/cefclient/browser/views_style.h" #include "tests/shared/browser/extension_util.h" #include "tests/shared/common/client_switches.h" #if !defined(OS_WIN) #define VK_ESCAPE 0x1B #define VK_RETURN 0x0D #define VK_MENU 0x12 // ALT key. #endif namespace client { namespace { const char kDefaultExtensionIcon[] = "window_icon"; // Control IDs for Views in the top-level Window. enum ControlIds { ID_WINDOW = 1, ID_BROWSER_VIEW, ID_BACK_BUTTON, ID_FORWARD_BUTTON, ID_STOP_BUTTON, ID_RELOAD_BUTTON, ID_URL_TEXTFIELD, ID_MENU_BUTTON, // Reserved range of top menu button IDs. ID_TOP_MENU_FIRST, ID_TOP_MENU_LAST = ID_TOP_MENU_FIRST + 10, // Reserved range of extension button IDs. ID_EXTENSION_BUTTON_FIRST, ID_EXTENSION_BUTTON_LAST = ID_EXTENSION_BUTTON_FIRST + 10, }; typedef std::vector> LabelButtons; // Make all |buttons| the same size. void MakeButtonsSameSize(const LabelButtons& buttons) { CefSize size; // Determine the largest button size. for (size_t i = 0U; i < buttons.size(); ++i) { const CefSize& button_size = buttons[i]->GetPreferredSize(); if (size.width < button_size.width) size.width = button_size.width; if (size.height < button_size.height) size.height = button_size.height; } for (size_t i = 0U; i < buttons.size(); ++i) { // Set the button's minimum size. buttons[i]->SetMinimumSize(size); // Re-layout the button and all parent Views. buttons[i]->InvalidateLayout(); } } void AddTestMenuItems(CefRefPtr test_menu) { test_menu->AddItem(ID_TESTS_GETSOURCE, "Get Source"); test_menu->AddItem(ID_TESTS_GETTEXT, "Get Text"); test_menu->AddItem(ID_TESTS_WINDOW_NEW, "New Window"); test_menu->AddItem(ID_TESTS_WINDOW_POPUP, "Popup Window"); test_menu->AddItem(ID_TESTS_REQUEST, "Request"); test_menu->AddItem(ID_TESTS_PLUGIN_INFO, "Plugin Info"); test_menu->AddItem(ID_TESTS_ZOOM_IN, "Zoom In"); test_menu->AddItem(ID_TESTS_ZOOM_OUT, "Zoom Out"); test_menu->AddItem(ID_TESTS_ZOOM_RESET, "Zoom Reset"); test_menu->AddItem(ID_TESTS_TRACING_BEGIN, "Begin Tracing"); test_menu->AddItem(ID_TESTS_TRACING_END, "End Tracing"); test_menu->AddItem(ID_TESTS_PRINT, "Print"); test_menu->AddItem(ID_TESTS_PRINT_TO_PDF, "Print to PDF"); test_menu->AddItem(ID_TESTS_MUTE_AUDIO, "Mute Audio"); test_menu->AddItem(ID_TESTS_UNMUTE_AUDIO, "Unmute Audio"); test_menu->AddItem(ID_TESTS_OTHER_TESTS, "Other Tests"); } void AddFileMenuItems(CefRefPtr file_menu) { file_menu->AddItem(ID_QUIT, "E&xit"); // Show the accelerator shortcut text in the menu. file_menu->SetAcceleratorAt(file_menu->GetCount() - 1, 'X', false, false, true); } } // namespace // static CefRefPtr ViewsWindow::Create( Delegate* delegate, CefRefPtr client, const CefString& url, const CefBrowserSettings& settings, CefRefPtr request_context) { CEF_REQUIRE_UI_THREAD(); DCHECK(delegate); // Create a new ViewsWindow. CefRefPtr views_window = new ViewsWindow(delegate, nullptr); // Create a new BrowserView. CefRefPtr browser_view = CefBrowserView::CreateBrowserView( client, url, settings, nullptr, request_context, views_window); // Associate the BrowserView with the ViewsWindow. views_window->SetBrowserView(browser_view); // Create a new top-level Window. It will show itself after creation. CefWindow::CreateTopLevelWindow(views_window); return views_window; } void ViewsWindow::Show() { CEF_REQUIRE_UI_THREAD(); if (window_) window_->Show(); if (browser_view_) { // Give keyboard focus to the BrowserView. browser_view_->RequestFocus(); } } void ViewsWindow::Hide() { CEF_REQUIRE_UI_THREAD(); if (window_) window_->Hide(); } void ViewsWindow::Minimize() { CEF_REQUIRE_UI_THREAD(); if (window_) window_->Minimize(); } void ViewsWindow::Maximize() { CEF_REQUIRE_UI_THREAD(); if (window_) window_->Maximize(); } void ViewsWindow::SetBounds(const CefRect& bounds) { CEF_REQUIRE_UI_THREAD(); if (window_) window_->SetBounds(bounds); } void ViewsWindow::SetBrowserSize(const CefSize& size, bool has_position, const CefPoint& position) { CEF_REQUIRE_UI_THREAD(); if (browser_view_) browser_view_->SetSize(size); if (window_) { window_->SizeToPreferredSize(); if (has_position) window_->SetPosition(position); } } void ViewsWindow::Close(bool force) { CEF_REQUIRE_UI_THREAD(); if (!browser_view_) return; CefRefPtr browser = browser_view_->GetBrowser(); if (browser) { // This will result in a call to CefWindow::Close() which will then call // ViewsWindow::CanClose(). browser->GetHost()->CloseBrowser(force); } } void ViewsWindow::SetAddress(const std::string& url) { CEF_REQUIRE_UI_THREAD(); if (!window_ || !with_controls_) return; CefRefPtr view = window_->GetViewForID(ID_URL_TEXTFIELD); if (view && view->AsTextfield()) view->AsTextfield()->SetText(url); } void ViewsWindow::SetTitle(const std::string& title) { CEF_REQUIRE_UI_THREAD(); if (window_) window_->SetTitle(title); } void ViewsWindow::SetFavicon(CefRefPtr image) { CEF_REQUIRE_UI_THREAD(); // Window icons should be 16 DIP in size. DCHECK_EQ(std::max(image->GetWidth(), image->GetHeight()), 16U); if (window_) window_->SetWindowIcon(image); } void ViewsWindow::SetFullscreen(bool fullscreen) { CEF_REQUIRE_UI_THREAD(); if (window_) { // Hide the top controls while in full-screen mode. if (with_controls_) ShowTopControls(!fullscreen); window_->SetFullscreen(fullscreen); } } void ViewsWindow::SetAlwaysOnTop(bool on_top) { CEF_REQUIRE_UI_THREAD(); if (window_) { window_->SetAlwaysOnTop(on_top); } } void ViewsWindow::SetLoadingState(bool isLoading, bool canGoBack, bool canGoForward) { CEF_REQUIRE_UI_THREAD(); if (!window_ || !with_controls_) return; EnableView(ID_BACK_BUTTON, canGoBack); EnableView(ID_FORWARD_BUTTON, canGoForward); EnableView(ID_RELOAD_BUTTON, !isLoading); EnableView(ID_STOP_BUTTON, isLoading); EnableView(ID_URL_TEXTFIELD, true); } void ViewsWindow::SetDraggableRegions( const std::vector& regions) { CEF_REQUIRE_UI_THREAD(); if (!window_ || !browser_view_) return; std::vector window_regions; // Convert the regions from BrowserView to Window coordinates. std::vector::const_iterator it = regions.begin(); for (; it != regions.end(); ++it) { CefDraggableRegion region = *it; CefPoint origin = CefPoint(region.bounds.x, region.bounds.y); browser_view_->ConvertPointToWindow(origin); region.bounds.x = origin.x; region.bounds.y = origin.y; window_regions.push_back(region); } window_->SetDraggableRegions(window_regions); } void ViewsWindow::TakeFocus(bool next) { CEF_REQUIRE_UI_THREAD(); if (!window_ || !with_controls_) return; // Give focus to the URL textfield. window_->GetViewForID(ID_URL_TEXTFIELD)->RequestFocus(); } void ViewsWindow::OnBeforeContextMenu(CefRefPtr model) { CEF_REQUIRE_UI_THREAD(); views_style::ApplyTo(model); } void ViewsWindow::OnExtensionsChanged(const ExtensionSet& extensions) { CEF_REQUIRE_UI_THREAD(); if (extensions.empty()) { if (!extensions_.empty()) { extensions_.clear(); UpdateExtensionControls(); } return; } ImageCache::ImageInfoSet image_set; ExtensionSet::const_iterator it = extensions.begin(); for (; it != extensions.end(); ++it) { CefRefPtr extension = *it; bool internal = false; const std::string& icon_path = extension_util::GetExtensionIconPath(extension, &internal); if (!icon_path.empty()) { // Load the extension icon. image_set.push_back( ImageCache::ImageInfo::Create1x(icon_path, icon_path, internal)); } else { // Get a NULL image and use the default icon. image_set.push_back(ImageCache::ImageInfo::Empty()); } } delegate_->GetImageCache()->LoadImages( image_set, base::Bind(&ViewsWindow::OnExtensionIconsLoaded, this, extensions)); } CefRefPtr ViewsWindow::GetDelegateForPopupBrowserView( CefRefPtr browser_view, const CefBrowserSettings& settings, CefRefPtr client, bool is_devtools) { CEF_REQUIRE_UI_THREAD(); // The popup browser client is created in CefLifeSpanHandler::OnBeforePopup() // (e.g. via RootWindowViews::InitAsPopup()). The Delegate (RootWindowViews) // knows the association between |client| and itself. Delegate* popup_delegate = delegate_->GetDelegateForPopup(client); // Should not be the same RootWindowViews that owns |this|. DCHECK(popup_delegate && popup_delegate != delegate_); // Create a new ViewsWindow for the popup BrowserView. return new ViewsWindow(popup_delegate, nullptr); } bool ViewsWindow::OnPopupBrowserViewCreated( CefRefPtr browser_view, CefRefPtr popup_browser_view, bool is_devtools) { CEF_REQUIRE_UI_THREAD(); // Retrieve the ViewsWindow created in GetDelegateForPopupBrowserView. CefRefPtr popup_window = static_cast(static_cast( popup_browser_view->GetDelegate().get())); // Should not be the same ViewsWindow as |this|. DCHECK(popup_window && popup_window != this); // Associate the ViewsWindow with the new popup browser. popup_window->SetBrowserView(popup_browser_view); // Create a new top-level Window for the popup. It will show itself after // creation. CefWindow::CreateTopLevelWindow(popup_window); // We created the Window. return true; } void ViewsWindow::OnButtonPressed(CefRefPtr button) { CEF_REQUIRE_UI_THREAD(); DCHECK(with_controls_); if (!browser_view_) return; CefRefPtr browser = browser_view_->GetBrowser(); if (!browser) return; switch (button->GetID()) { case ID_BACK_BUTTON: browser->GoBack(); break; case ID_FORWARD_BUTTON: browser->GoForward(); break; case ID_STOP_BUTTON: browser->StopLoad(); break; case ID_RELOAD_BUTTON: browser->Reload(); break; case ID_MENU_BUTTON: break; default: NOTREACHED(); break; } } void ViewsWindow::OnMenuButtonPressed( CefRefPtr menu_button, const CefPoint& screen_point, CefRefPtr button_pressed_lock) { CEF_REQUIRE_UI_THREAD(); const int id = menu_button->GetID(); if (id >= ID_EXTENSION_BUTTON_FIRST && id <= ID_EXTENSION_BUTTON_LAST) { const size_t extension_idx = id - ID_EXTENSION_BUTTON_FIRST; if (extension_idx >= extensions_.size()) { LOG(ERROR) << "Invalid extension index " << extension_idx; return; } // Keep the button pressed until the extension window is closed. extension_button_pressed_lock_ = button_pressed_lock; // Create a window for the extension. delegate_->CreateExtensionWindow( extensions_[extension_idx].extension_, menu_button->GetBoundsInScreen(), window_, base::Bind(&ViewsWindow::OnExtensionWindowClosed, this)); return; } DCHECK(with_controls_); DCHECK_EQ(ID_MENU_BUTTON, id); menu_button->ShowMenu(button_menu_model_, screen_point, CEF_MENU_ANCHOR_TOPRIGHT); } void ViewsWindow::ExecuteCommand(CefRefPtr menu_model, int command_id, cef_event_flags_t event_flags) { CEF_REQUIRE_UI_THREAD(); DCHECK(with_controls_); if (command_id == ID_QUIT) { delegate_->OnExit(); } else if (command_id >= ID_TESTS_FIRST && command_id <= ID_TESTS_LAST) { delegate_->OnTest(command_id); } else { NOTREACHED(); } } bool ViewsWindow::OnKeyEvent(CefRefPtr textfield, const CefKeyEvent& event) { CEF_REQUIRE_UI_THREAD(); DCHECK(with_controls_); DCHECK_EQ(ID_URL_TEXTFIELD, textfield->GetID()); // Trigger when the return key is pressed. if (window_ && browser_view_ && event.type == KEYEVENT_RAWKEYDOWN && event.windows_key_code == VK_RETURN) { CefRefPtr browser = browser_view_->GetBrowser(); if (browser) { CefRefPtr view = window_->GetViewForID(ID_URL_TEXTFIELD); if (view && view->AsTextfield()) { const CefString& url = view->AsTextfield()->GetText(); if (!url.empty()) browser->GetMainFrame()->LoadURL(url); } } // We handled the event. return true; } return false; } void ViewsWindow::OnWindowCreated(CefRefPtr window) { CEF_REQUIRE_UI_THREAD(); DCHECK(browser_view_); DCHECK(!window_); DCHECK(window); window_ = window; window_->SetID(ID_WINDOW); with_controls_ = delegate_->WithControls(); delegate_->OnViewsWindowCreated(this); CefRect bounds = delegate_->GetWindowBounds(); if (bounds.IsEmpty()) { // Use the default size. bounds.width = 800; bounds.height = 600; } if (bounds.x == 0 && bounds.y == 0) { // Size the Window and center it. window_->CenterWindow(CefSize(bounds.width, bounds.height)); } else { // Set the Window bounds as specified. window_->SetBounds(bounds); } // Set the background color for regions that are not obscured by other Views. views_style::ApplyTo(window_.get()); if (with_controls_) { // Add the BrowserView and other controls to the Window. AddControls(); // Add keyboard accelerators to the Window. AddAccelerators(); } else { // Add the BrowserView as the only child of the Window. window_->AddChildView(browser_view_); if (!delegate_->WithExtension()) { // Choose a reasonable minimum window size. minimum_window_size_ = CefSize(100, 100); } } if (!delegate_->InitiallyHidden()) { // Show the Window. Show(); } } void ViewsWindow::OnWindowDestroyed(CefRefPtr window) { CEF_REQUIRE_UI_THREAD(); DCHECK(window_); delegate_->OnViewsWindowDestroyed(this); browser_view_ = nullptr; button_menu_model_ = nullptr; if (top_menu_bar_) { top_menu_bar_->Reset(); top_menu_bar_ = nullptr; } extensions_panel_ = nullptr; window_ = nullptr; } bool ViewsWindow::CanClose(CefRefPtr window) { CEF_REQUIRE_UI_THREAD(); // Allow the window to close if the browser says it's OK. CefRefPtr browser = browser_view_->GetBrowser(); if (browser) return browser->GetHost()->TryCloseBrowser(); return true; } CefRefPtr ViewsWindow::GetParentWindow(CefRefPtr window, bool* is_menu, bool* can_activate_menu) { CEF_REQUIRE_UI_THREAD(); CefRefPtr parent_window = delegate_->GetParentWindow(); if (parent_window) { // Should be an extension window, in which case we want it to behave as a // menu and allow activation. DCHECK(delegate_->WithExtension()); *is_menu = true; *can_activate_menu = true; } return parent_window; } bool ViewsWindow::IsFrameless(CefRefPtr window) { CEF_REQUIRE_UI_THREAD(); return frameless_; } bool ViewsWindow::CanResize(CefRefPtr window) { CEF_REQUIRE_UI_THREAD(); // Don't allow windows hosting extensions to resize. return !delegate_->WithExtension(); } bool ViewsWindow::OnAccelerator(CefRefPtr window, int command_id) { CEF_REQUIRE_UI_THREAD(); if (command_id == ID_QUIT) { delegate_->OnExit(); return true; } return false; } bool ViewsWindow::OnKeyEvent(CefRefPtr window, const CefKeyEvent& event) { CEF_REQUIRE_UI_THREAD(); if (!window_) return false; if (delegate_->WithExtension() && event.type == KEYEVENT_RAWKEYDOWN && event.windows_key_code == VK_ESCAPE) { // Close the extension window on escape. Close(false); return true; } if (!with_controls_) return false; if (event.type == KEYEVENT_RAWKEYDOWN && event.windows_key_code == VK_MENU) { // ALT key is pressed. int last_focused_view = last_focused_view_; bool menu_had_focus = menu_has_focus_; // Toggle menu button focusable. SetMenuFocusable(!menu_has_focus_); if (menu_had_focus && last_focused_view != 0) { // Restore focus to the view that was previously focused. window_->GetViewForID(last_focused_view)->RequestFocus(); } return true; } if (menu_has_focus_ && top_menu_bar_) return top_menu_bar_->OnKeyEvent(event); return false; } CefSize ViewsWindow::GetMinimumSize(CefRefPtr view) { CEF_REQUIRE_UI_THREAD(); if (view->GetID() == ID_WINDOW) return minimum_window_size_; return CefSize(); } void ViewsWindow::OnFocus(CefRefPtr view) { CEF_REQUIRE_UI_THREAD(); const int view_id = view->GetID(); // Keep track of the non-menu view that was last focused. if (last_focused_view_ != view_id && (!top_menu_bar_ || !top_menu_bar_->HasMenuId(view_id))) { last_focused_view_ = view_id; } // When focus leaves the menu buttons make them unfocusable. if (menu_has_focus_) { if (top_menu_bar_) { if (!top_menu_bar_->HasMenuId(view_id)) SetMenuFocusable(false); } else if (view_id != ID_MENU_BUTTON) { SetMenuFocusable(false); } } if (view_id == ID_BROWSER_VIEW) delegate_->OnViewsWindowActivated(this); } void ViewsWindow::OnBlur(CefRefPtr view) { CEF_REQUIRE_UI_THREAD(); const int view_id = view->GetID(); if (view_id == ID_BROWSER_VIEW && delegate_->WithExtension()) { // Close windows hosting extensions when the browser loses focus. Close(false); } } void ViewsWindow::MenuBarExecuteCommand(CefRefPtr menu_model, int command_id, cef_event_flags_t event_flags) { ExecuteCommand(menu_model, command_id, event_flags); } ViewsWindow::ViewsWindow(Delegate* delegate, CefRefPtr browser_view) : delegate_(delegate), with_controls_(false), menu_has_focus_(false), last_focused_view_(false) { DCHECK(delegate_); if (browser_view) SetBrowserView(browser_view); CefRefPtr command_line = CefCommandLine::GetGlobalCommandLine(); frameless_ = command_line->HasSwitch(switches::kHideFrame) || delegate_->WithExtension(); if (!command_line->HasSwitch(switches::kHideTopMenu)) { top_menu_bar_ = new ViewsMenuBar(this, ID_TOP_MENU_FIRST); } } void ViewsWindow::SetBrowserView(CefRefPtr browser_view) { DCHECK(!browser_view_); DCHECK(browser_view); DCHECK(browser_view->IsValid()); DCHECK(!browser_view->IsAttached()); browser_view_ = browser_view; browser_view_->SetID(ID_BROWSER_VIEW); } void ViewsWindow::CreateMenuModel() { // Create the menu button model. button_menu_model_ = CefMenuModel::CreateMenuModel(this); CefRefPtr test_menu = button_menu_model_->AddSubMenu(0, "&Tests"); views_style::ApplyTo(button_menu_model_); AddTestMenuItems(test_menu); AddFileMenuItems(button_menu_model_); if (top_menu_bar_) { // Add the menus to the top menu bar. AddFileMenuItems(top_menu_bar_->CreateMenuModel("&File", nullptr)); AddTestMenuItems(top_menu_bar_->CreateMenuModel("&Tests", nullptr)); } } CefRefPtr ViewsWindow::CreateBrowseButton( const std::string& label, int id) { CefRefPtr button = CefLabelButton::CreateLabelButton(this, label); button->SetID(id); button->SetEnabled(false); // Disabled by default. button->SetFocusable(false); // Don't give focus to the button. return button; } void ViewsWindow::AddControls() { // Create the MenuModel that will be displayed via the menu button. CreateMenuModel(); CefRefPtr top_menu_panel; if (top_menu_bar_) top_menu_panel = top_menu_bar_->GetMenuPanel(); // Create the browse buttons. LabelButtons browse_buttons; browse_buttons.push_back(CreateBrowseButton("Back", ID_BACK_BUTTON)); browse_buttons.push_back(CreateBrowseButton("Forward", ID_FORWARD_BUTTON)); browse_buttons.push_back(CreateBrowseButton("Reload", ID_RELOAD_BUTTON)); browse_buttons.push_back(CreateBrowseButton("Stop", ID_STOP_BUTTON)); // Create the URL textfield. CefRefPtr url_textfield = CefTextfield::CreateTextfield(this); url_textfield->SetID(ID_URL_TEXTFIELD); url_textfield->SetEnabled(false); // Disabled by default. views_style::ApplyTo(url_textfield); // Create the menu button. CefRefPtr menu_button = CefMenuButton::CreateMenuButton(this, CefString()); menu_button->SetID(ID_MENU_BUTTON); menu_button->SetImage( CEF_BUTTON_STATE_NORMAL, delegate_->GetImageCache()->GetCachedImage("menu_icon")); views_style::ApplyTo(menu_button.get()); menu_button->SetInkDropEnabled(true); // Override the default minimum size. menu_button->SetMinimumSize(CefSize(0, 0)); // Create the top panel. CefRefPtr top_panel = CefPanel::CreatePanel(nullptr); // Use a horizontal box layout for |top_panel|. CefBoxLayoutSettings top_panel_layout_settings; top_panel_layout_settings.horizontal = true; CefRefPtr top_panel_layout = top_panel->SetToBoxLayout(top_panel_layout_settings); // Add the buttons and URL textfield to |top_panel|. for (size_t i = 0U; i < browse_buttons.size(); ++i) top_panel->AddChildView(browse_buttons[i]); top_panel->AddChildView(url_textfield); UpdateExtensionControls(); DCHECK(extensions_panel_); top_panel->AddChildView(extensions_panel_); top_panel->AddChildView(menu_button); views_style::ApplyTo(top_panel); // Allow |url_textfield| to grow and fill any remaining space. top_panel_layout->SetFlexForView(url_textfield, 1); // Use a vertical box layout for |window|. CefBoxLayoutSettings window_layout_settings; window_layout_settings.horizontal = false; window_layout_settings.between_child_spacing = 2; CefRefPtr window_layout = window_->SetToBoxLayout(window_layout_settings); // Add the top panel and browser view to |window|. if (top_menu_panel) window_->AddChildView(top_menu_panel); window_->AddChildView(top_panel); window_->AddChildView(browser_view_); // Allow |browser_view_| to grow and fill any remaining space. window_layout->SetFlexForView(browser_view_, 1); // Lay out |window| so we can get the default button sizes. window_->Layout(); // Make all browse buttons the same size. MakeButtonsSameSize(browse_buttons); // Lay out |window| again with the new button sizes. window_->Layout(); // Minimum window width is the size of all buttons plus some extra. const int min_width = browse_buttons[0]->GetBounds().width * 4 + menu_button->GetBounds().width + 100; // Minimum window height is the hight of the top toolbar plus some extra. int min_height = top_panel->GetBounds().height + 100; if (top_menu_panel) min_height += top_menu_panel->GetBounds().height; minimum_window_size_ = CefSize(min_width, min_height); } void ViewsWindow::AddAccelerators() { // Trigger accelerators without first forwarding to web content. browser_view_->SetPreferAccelerators(true); // Specify the accelerators to handle. OnAccelerator will be called when the // accelerator is triggered. window_->SetAccelerator(ID_QUIT, 'X', false, false, true); } void ViewsWindow::SetMenuFocusable(bool focusable) { if (!window_ || !with_controls_) return; if (top_menu_bar_) { top_menu_bar_->SetMenuFocusable(focusable); } else { window_->GetViewForID(ID_MENU_BUTTON)->SetFocusable(focusable); if (focusable) { // Give focus to menu button. window_->GetViewForID(ID_MENU_BUTTON)->RequestFocus(); } } menu_has_focus_ = focusable; } void ViewsWindow::EnableView(int id, bool enable) { if (!window_) return; CefRefPtr view = window_->GetViewForID(id); if (view) view->SetEnabled(enable); } void ViewsWindow::ShowTopControls(bool show) { if (!window_ || !with_controls_) return; // Change the visibility of the panel that contains the buttons. CefRefPtr parent_view = window_->GetViewForID(ID_BACK_BUTTON)->GetParentView(); if (parent_view->IsVisible() != show) { parent_view->SetVisible(show); parent_view->InvalidateLayout(); } } void ViewsWindow::UpdateExtensionControls() { CEF_REQUIRE_UI_THREAD(); if (!window_ || !with_controls_) return; if (!extensions_panel_) { extensions_panel_ = CefPanel::CreatePanel(nullptr); // Use a horizontal box layout for |top_panel|. CefBoxLayoutSettings top_panel_layout_settings; top_panel_layout_settings.horizontal = true; CefRefPtr top_panel_layout = extensions_panel_->SetToBoxLayout(top_panel_layout_settings); } else { extensions_panel_->RemoveAllChildViews(); } if (extensions_.size() > ID_EXTENSION_BUTTON_LAST - ID_EXTENSION_BUTTON_FIRST) { LOG(WARNING) << "Too many extensions loaded. Some will be ignored."; } ExtensionInfoSet::const_iterator it = extensions_.begin(); for (int id = ID_EXTENSION_BUTTON_FIRST; it != extensions_.end() && id <= ID_EXTENSION_BUTTON_LAST; ++id, ++it) { CefRefPtr button = CefMenuButton::CreateMenuButton(this, CefString()); button->SetID(id); button->SetImage(CEF_BUTTON_STATE_NORMAL, (*it).image_); views_style::ApplyTo(button.get()); button->SetInkDropEnabled(true); // Override the default minimum size. button->SetMinimumSize(CefSize(0, 0)); extensions_panel_->AddChildView(button); } CefRefPtr parent_view = extensions_panel_->GetParentView(); if (parent_view) parent_view->InvalidateLayout(); } void ViewsWindow::OnExtensionIconsLoaded(const ExtensionSet& extensions, const ImageCache::ImageSet& images) { if (!CefCurrentlyOn(TID_UI)) { // Execute this method on the UI thread. CefPostTask(TID_UI, base::Bind(&ViewsWindow::OnExtensionIconsLoaded, this, extensions, images)); return; } DCHECK_EQ(extensions.size(), images.size()); extensions_.clear(); ExtensionSet::const_iterator it1 = extensions.begin(); ImageCache::ImageSet::const_iterator it2 = images.begin(); for (; it1 != extensions.end() && it2 != images.end(); ++it1, ++it2) { CefRefPtr icon = *it2; if (!icon) icon = delegate_->GetImageCache()->GetCachedImage(kDefaultExtensionIcon); extensions_.push_back(ExtensionInfo(*it1, icon)); } UpdateExtensionControls(); } void ViewsWindow::OnExtensionWindowClosed() { if (!CefCurrentlyOn(TID_UI)) { // Execute this method on the UI thread. CefPostTask(TID_UI, base::Bind(&ViewsWindow::OnExtensionWindowClosed, this)); return; } // Restore the button state. extension_button_pressed_lock_ = nullptr; } } // namespace client