diff --git a/cef_paths2.gypi b/cef_paths2.gypi index 23b910591..0b7359706 100644 --- a/cef_paths2.gypi +++ b/cef_paths2.gypi @@ -299,6 +299,8 @@ 'tests/cefclient/browser/root_window_win.h', 'tests/cefclient/browser/temp_window_win.cc', 'tests/cefclient/browser/temp_window_win.h', + 'tests/cefclient/browser/views_menu_bar.cc', + 'tests/cefclient/browser/views_menu_bar.h', 'tests/cefclient/browser/views_window.cc', 'tests/cefclient/browser/views_window.h', 'tests/cefclient/browser/window_test_runner_views.cc', @@ -350,6 +352,8 @@ 'tests/cefclient/browser/root_window_views.h', 'tests/cefclient/browser/temp_window_x11.cc', 'tests/cefclient/browser/temp_window_x11.h', + 'tests/cefclient/browser/views_menu_bar.cc', + 'tests/cefclient/browser/views_menu_bar.h', 'tests/cefclient/browser/views_window.cc', 'tests/cefclient/browser/views_window.h', 'tests/cefclient/browser/window_test_runner_gtk.cc', diff --git a/include/capi/cef_menu_model_capi.h b/include/capi/cef_menu_model_capi.h index d7035b089..762aeff0a 100644 --- a/include/capi/cef_menu_model_capi.h +++ b/include/capi/cef_menu_model_capi.h @@ -58,6 +58,11 @@ typedef struct _cef_menu_model_t { /// cef_base_ref_counted_t base; + /// + // Returns true (1) if this menu is a submenu. + /// + int (CEF_CALLBACK *is_sub_menu)(struct _cef_menu_model_t* self); + /// // Clears the menu. Returns true (1) on success. /// diff --git a/include/capi/cef_menu_model_delegate_capi.h b/include/capi/cef_menu_model_delegate_capi.h index 549ce6d3a..dc72e7836 100644 --- a/include/capi/cef_menu_model_delegate_capi.h +++ b/include/capi/cef_menu_model_delegate_capi.h @@ -65,6 +65,30 @@ typedef struct _cef_menu_model_delegate_t { struct _cef_menu_model_t* menu_model, int command_id, cef_event_flags_t event_flags); + /// + // Called when the user moves the mouse outside the menu and over the owning + // window. + /// + void (CEF_CALLBACK *mouse_outside_menu)( + struct _cef_menu_model_delegate_t* self, + struct _cef_menu_model_t* menu_model, const cef_point_t* screen_point); + + /// + // Called on unhandled open submenu keyboard commands. |is_rtl| will be true + // (1) if the menu is displaying a right-to-left language. + /// + void (CEF_CALLBACK *unhandled_open_submenu)( + struct _cef_menu_model_delegate_t* self, + struct _cef_menu_model_t* menu_model, int is_rtl); + + /// + // Called on unhandled close submenu keyboard commands. |is_rtl| will be true + // (1) if the menu is displaying a right-to-left language. + /// + void (CEF_CALLBACK *unhandled_close_submenu)( + struct _cef_menu_model_delegate_t* self, + struct _cef_menu_model_t* menu_model, int is_rtl); + /// // The menu is about to show. /// diff --git a/include/capi/views/cef_button_delegate_capi.h b/include/capi/views/cef_button_delegate_capi.h index ad9a6c699..ecd653e88 100644 --- a/include/capi/views/cef_button_delegate_capi.h +++ b/include/capi/views/cef_button_delegate_capi.h @@ -62,6 +62,12 @@ typedef struct _cef_button_delegate_t { /// void (CEF_CALLBACK *on_button_pressed)(struct _cef_button_delegate_t* self, struct _cef_button_t* button); + + /// + // Called when the state of |button| changes. + /// + void (CEF_CALLBACK *on_button_state_changed)( + struct _cef_button_delegate_t* self, struct _cef_button_t* button); } cef_button_delegate_t; diff --git a/include/capi/views/cef_menu_button_capi.h b/include/capi/views/cef_menu_button_capi.h index b51c80e8d..493842e57 100644 --- a/include/capi/views/cef_menu_button_capi.h +++ b/include/capi/views/cef_menu_button_capi.h @@ -68,6 +68,12 @@ typedef struct _cef_menu_button_t { void (CEF_CALLBACK *show_menu)(struct _cef_menu_button_t* self, struct _cef_menu_model_t* menu_model, const cef_point_t* screen_point, cef_menu_anchor_position_t anchor_position); + + /// + // Show the menu for this button. Results in a call to + // cef_menu_button_delegate_t::on_menu_button_pressed(). + /// + void (CEF_CALLBACK *trigger_menu)(struct _cef_menu_button_t* self); } cef_menu_button_t; diff --git a/include/cef_menu_model.h b/include/cef_menu_model.h index b2606a8da..c0a034013 100644 --- a/include/cef_menu_model.h +++ b/include/cef_menu_model.h @@ -59,6 +59,12 @@ class CefMenuModel : public virtual CefBaseRefCounted { static CefRefPtr CreateMenuModel( CefRefPtr delegate); + /// + // Returns true if this menu is a submenu. + /// + /*--cef()--*/ + virtual bool IsSubMenu() =0; + /// // Clears the menu. Returns true on success. /// diff --git a/include/cef_menu_model_delegate.h b/include/cef_menu_model_delegate.h index aa23ffcb5..d05b580a6 100644 --- a/include/cef_menu_model_delegate.h +++ b/include/cef_menu_model_delegate.h @@ -59,6 +59,30 @@ class CefMenuModelDelegate : public virtual CefBaseRefCounted { int command_id, cef_event_flags_t event_flags) =0; + /// + // Called when the user moves the mouse outside the menu and over the owning + // window. + /// + /*--cef()--*/ + virtual void MouseOutsideMenu(CefRefPtr menu_model, + const CefPoint& screen_point) {} + + /// + // Called on unhandled open submenu keyboard commands. |is_rtl| will be true + // if the menu is displaying a right-to-left language. + /// + /*--cef()--*/ + virtual void UnhandledOpenSubmenu(CefRefPtr menu_model, + bool is_rtl) {} + + /// + // Called on unhandled close submenu keyboard commands. |is_rtl| will be true + // if the menu is displaying a right-to-left language. + /// + /*--cef()--*/ + virtual void UnhandledCloseSubmenu(CefRefPtr menu_model, + bool is_rtl) {} + /// // The menu is about to show. /// diff --git a/include/views/cef_button_delegate.h b/include/views/cef_button_delegate.h index 99bd126e8..ec33d9be7 100644 --- a/include/views/cef_button_delegate.h +++ b/include/views/cef_button_delegate.h @@ -54,6 +54,12 @@ class CefButtonDelegate : public CefViewDelegate { /// /*--cef()--*/ virtual void OnButtonPressed(CefRefPtr button) =0; + + /// + // Called when the state of |button| changes. + /// + /*--cef()--*/ + virtual void OnButtonStateChanged(CefRefPtr button) {}; }; #endif // CEF_INCLUDE_VIEWS_CEF_BUTTON_DELEGATE_H_ diff --git a/include/views/cef_menu_button.h b/include/views/cef_menu_button.h index 4ae8c4f3a..60f803c47 100644 --- a/include/views/cef_menu_button.h +++ b/include/views/cef_menu_button.h @@ -78,6 +78,13 @@ class CefMenuButton : public CefLabelButton { virtual void ShowMenu(CefRefPtr menu_model, const CefPoint& screen_point, cef_menu_anchor_position_t anchor_position) =0; + + /// + // Show the menu for this button. Results in a call to + // CefMenuButtonDelegate::OnMenuButtonPressed(). + /// + /*--cef()--*/ + virtual void TriggerMenu() =0; }; #endif // CEF_INCLUDE_VIEWS_CEF_MENU_BUTTON_H_ diff --git a/include/views/cef_window_delegate.h b/include/views/cef_window_delegate.h index f33137cd9..a50e1fc41 100644 --- a/include/views/cef_window_delegate.h +++ b/include/views/cef_window_delegate.h @@ -113,6 +113,7 @@ class CefWindowDelegate : public CefPanelDelegate { /*--cef()--*/ virtual bool OnKeyEvent(CefRefPtr window, const CefKeyEvent& event) { return false; } + }; #endif // CEF_INCLUDE_VIEWS_CEF_WINDOW_DELEGATE_H_ diff --git a/libcef/browser/menu_manager.cc b/libcef/browser/menu_manager.cc index d783a6b5d..b869969ca 100644 --- a/libcef/browser/menu_manager.cc +++ b/libcef/browser/menu_manager.cc @@ -99,7 +99,7 @@ CefMenuManager::CefMenuManager(CefBrowserHostImpl* browser, weak_ptr_factory_(this) { DCHECK(web_contents()); DCHECK(runner_.get()); - model_ = new CefMenuModelImpl(this, nullptr); + model_ = new CefMenuModelImpl(this, nullptr, false); } CefMenuManager::~CefMenuManager() { @@ -289,7 +289,8 @@ void CefMenuManager::MenuClosed(CefRefPtr source) { web_contents()->NotifyContextMenuClosed(params_.custom_context); } -bool CefMenuManager::FormatLabel(base::string16& label) { +bool CefMenuManager::FormatLabel(CefRefPtr source, + base::string16& label) { return runner_->FormatLabel(label); } diff --git a/libcef/browser/menu_manager.h b/libcef/browser/menu_manager.h index 898da0dae..8f21abe07 100644 --- a/libcef/browser/menu_manager.h +++ b/libcef/browser/menu_manager.h @@ -46,7 +46,8 @@ class CefMenuManager : public CefMenuModelImpl::Delegate, cef_event_flags_t event_flags) override; void MenuWillShow(CefRefPtr source) override; void MenuClosed(CefRefPtr source) override; - bool FormatLabel(base::string16& label) override; + bool FormatLabel(CefRefPtr source, + base::string16& label) override; void ExecuteCommandCallback(int command_id, cef_event_flags_t event_flags); diff --git a/libcef/browser/menu_model_impl.cc b/libcef/browser/menu_model_impl.cc index 842b567d2..696d45a85 100644 --- a/libcef/browser/menu_model_impl.cc +++ b/libcef/browser/menu_model_impl.cc @@ -14,6 +14,7 @@ #include "base/message_loop/message_loop.h" #include "content/public/common/menu_item.h" #include "ui/base/accelerators/accelerator.h" +#include "ui/gfx/geometry/point.h" namespace { @@ -138,6 +139,18 @@ class CefSimpleMenuModel : public ui::MenuModel { return NULL; } + void MouseOutsideMenu(const gfx::Point& screen_point) override { + impl_->MouseOutsideMenu(screen_point); + } + + void UnhandledOpenSubmenu(bool is_rtl) override { + impl_->UnhandledOpenSubmenu(is_rtl); + } + + void UnhandledCloseSubmenu(bool is_rtl) override { + impl_->UnhandledCloseSubmenu(is_rtl); + } + void MenuWillShow() override { impl_->MenuWillShow(); } @@ -173,7 +186,7 @@ CefRefPtr CefMenuModel::CreateMenuModel( return nullptr; CefRefPtr menu_model = - new CefMenuModelImpl(nullptr, delegate); + new CefMenuModelImpl(nullptr, delegate, false); return menu_model; } @@ -219,10 +232,12 @@ struct CefMenuModelImpl::Item { CefMenuModelImpl::CefMenuModelImpl( Delegate* delegate, - CefRefPtr menu_model_delegate) + CefRefPtr menu_model_delegate, + bool is_submenu) : supported_thread_id_(base::PlatformThread::CurrentId()), delegate_(delegate), - menu_model_delegate_(menu_model_delegate) { + menu_model_delegate_(menu_model_delegate), + is_submenu_(is_submenu) { DCHECK(delegate_ || menu_model_delegate_); model_.reset(new CefSimpleMenuModel(this)); } @@ -230,6 +245,12 @@ CefMenuModelImpl::CefMenuModelImpl( CefMenuModelImpl::~CefMenuModelImpl() { } +bool CefMenuModelImpl::IsSubMenu() { + if (!VerifyContext()) + return false; + return is_submenu_; +} + bool CefMenuModelImpl::Clear() { if (!VerifyContext()) return false; @@ -284,7 +305,7 @@ CefRefPtr CefMenuModelImpl::AddSubMenu(int command_id, return NULL; Item item(MENUITEMTYPE_SUBMENU, command_id, label, -1); - item.submenu_ = new CefMenuModelImpl(delegate_, menu_model_delegate_); + item.submenu_ = new CefMenuModelImpl(delegate_, menu_model_delegate_, true); AppendItem(item); return item.submenu_.get(); } @@ -331,7 +352,7 @@ CefRefPtr CefMenuModelImpl::InsertSubMenuAt( return NULL; Item item(MENUITEMTYPE_SUBMENU, command_id, label, -1); - item.submenu_ = new CefMenuModelImpl(delegate_, menu_model_delegate_); + item.submenu_ = new CefMenuModelImpl(delegate_, menu_model_delegate_, true); InsertItemAt(item, index); return item.submenu_.get(); } @@ -646,6 +667,39 @@ void CefMenuModelImpl::ActivatedAt(int index, cef_event_flags_t event_flags) { menu_model_delegate_->ExecuteCommand(this, command_id, event_flags); } +void CefMenuModelImpl::MouseOutsideMenu(const gfx::Point& screen_point) { + if (!VerifyContext()) + return; + + // Allow the callstack to unwind before notifying the delegate since it may + // result in the menu being destroyed. + base::MessageLoop::current()->task_runner()->PostTask( + FROM_HERE, + base::Bind(&CefMenuModelImpl::OnMouseOutsideMenu, this, screen_point)); +} + +void CefMenuModelImpl::UnhandledOpenSubmenu(bool is_rtl) { + if (!VerifyContext()) + return; + + // Allow the callstack to unwind before notifying the delegate since it may + // result in the menu being destroyed. + base::MessageLoop::current()->task_runner()->PostTask( + FROM_HERE, + base::Bind(&CefMenuModelImpl::OnUnhandledOpenSubmenu, this, is_rtl)); +} + +void CefMenuModelImpl::UnhandledCloseSubmenu(bool is_rtl) { + if (!VerifyContext()) + return; + + // Allow the callstack to unwind before notifying the delegate since it may + // result in the menu being destroyed. + base::MessageLoop::current()->task_runner()->PostTask( + FROM_HERE, + base::Bind(&CefMenuModelImpl::OnUnhandledCloseSubmenu, this, is_rtl)); +} + void CefMenuModelImpl::MenuWillShow() { if (!VerifyContext()) return; @@ -654,14 +708,15 @@ void CefMenuModelImpl::MenuWillShow() { delegate_->MenuWillShow(this); if (menu_model_delegate_) menu_model_delegate_->MenuWillShow(this); - for (auto& observer : observers_) - observer.MenuWillShow(this); } void CefMenuModelImpl::MenuWillClose() { if (!VerifyContext()) return; + if (!auto_notify_menu_closed_) + return; + // Due to how menus work on the different platforms, ActivatedAt will be // called after this. It's more convenient for the delegate to be called // afterwards, though, so post a task. @@ -673,7 +728,7 @@ void CefMenuModelImpl::MenuWillClose() { base::string16 CefMenuModelImpl::GetFormattedLabelAt(int index) { base::string16 label = GetLabelAt(index).ToString16(); if (delegate_) - delegate_->FormatLabel(label); + delegate_->FormatLabel(this, label); if (menu_model_delegate_) { CefString new_label = label; if (menu_model_delegate_->FormatLabel(this, new_label)) @@ -699,18 +754,6 @@ bool CefMenuModelImpl::VerifyRefCount() { return true; } -void CefMenuModelImpl::AddObserver(Observer* observer) { - observers_.AddObserver(observer); -} - -void CefMenuModelImpl::RemoveObserver(Observer* observer) { - observers_.RemoveObserver(observer); -} - -bool CefMenuModelImpl::HasObserver(Observer* observer) const { - return observers_.HasObserver(observer); -} - void CefMenuModelImpl::AddMenuItem(const content::MenuItem& menu_item) { const int command_id = static_cast(menu_item.action); @@ -746,6 +789,11 @@ void CefMenuModelImpl::AddMenuItem(const content::MenuItem& menu_item) { } } +void CefMenuModelImpl::NotifyMenuClosed() { + DCHECK(!auto_notify_menu_closed_); + OnMenuClosed(); +} + void CefMenuModelImpl::AppendItem(const Item& item) { ValidateItem(item); items_.push_back(item); @@ -772,13 +820,34 @@ void CefMenuModelImpl::ValidateItem(const Item& item) { #endif } +void CefMenuModelImpl::OnMouseOutsideMenu(const gfx::Point& screen_point) { + if (delegate_) + delegate_->MouseOutsideMenu(this, screen_point); + if (menu_model_delegate_) { + menu_model_delegate_->MouseOutsideMenu(this, + CefPoint(screen_point.x(), screen_point.y())); + } +} + +void CefMenuModelImpl::OnUnhandledOpenSubmenu(bool is_rtl) { + if (delegate_) + delegate_->UnhandledOpenSubmenu(this, is_rtl); + if (menu_model_delegate_) + menu_model_delegate_->UnhandledOpenSubmenu(this, is_rtl); +} + +void CefMenuModelImpl::OnUnhandledCloseSubmenu(bool is_rtl) { + if (delegate_) + delegate_->UnhandledCloseSubmenu(this, is_rtl); + if (menu_model_delegate_) + menu_model_delegate_->UnhandledCloseSubmenu(this, is_rtl); +} + void CefMenuModelImpl::OnMenuClosed() { if (delegate_) delegate_->MenuClosed(this); if (menu_model_delegate_) menu_model_delegate_->MenuClosed(this); - for (auto& observer : observers_) - observer.MenuClosed(this); } bool CefMenuModelImpl::VerifyContext() { diff --git a/libcef/browser/menu_model_impl.h b/libcef/browser/menu_model_impl.h index fa6f06bca..ab07ee82e 100644 --- a/libcef/browser/menu_model_impl.h +++ b/libcef/browser/menu_model_impl.h @@ -12,7 +12,6 @@ #include "include/cef_menu_model.h" #include "include/cef_menu_model_delegate.h" -#include "base/observer_list.h" #include "base/threading/platform_thread.h" #include "ui/base/models/menu_model.h" @@ -30,38 +29,41 @@ class CefMenuModelImpl : public CefMenuModel { int command_id, cef_event_flags_t event_flags) =0; - // Notifies the delegate that the menu is about to show. + // Called when the user moves the mouse outside the menu and over the owning + // window. + virtual void MouseOutsideMenu(CefRefPtr source, + const gfx::Point& screen_point) {} + + // Called on unhandled open/close submenu keyboard commands. |is_rtl| will + // be true if the menu is displaying a right-to-left language. + virtual void UnhandledOpenSubmenu(CefRefPtr source, + bool is_rtl) {} + virtual void UnhandledCloseSubmenu(CefRefPtr source, + bool is_rtl) {} + + // Called when the menu is about to show. virtual void MenuWillShow(CefRefPtr source) =0; - // Notifies the delegate that the menu has closed. + // Called when the menu has closed. virtual void MenuClosed(CefRefPtr source) =0; // Allows the delegate to modify a menu item label before it's displayed. - virtual bool FormatLabel(base::string16& label) =0; + virtual bool FormatLabel(CefRefPtr source, + base::string16& label) =0; protected: virtual ~Delegate() {} }; - class Observer { - public: - // Notifies the delegate that the menu is about to show. - virtual void MenuWillShow(CefRefPtr source) {}; - - // Notifies the delegate that the menu has closed. - virtual void MenuClosed(CefRefPtr source) {}; - - protected: - virtual ~Observer() {} - }; - // Either |delegate| or |menu_model_delegate| must be non-nullptr. // If |delegate| is non-nullptr it must outlive this class. CefMenuModelImpl(Delegate* delegate, - CefRefPtr menu_model_delegate); + CefRefPtr menu_model_delegate, + bool is_submenu); ~CefMenuModelImpl() override; // CefMenuModel methods. + bool IsSubMenu() override; bool Clear() override; int GetCount() override; bool AddSeparator() override; @@ -124,6 +126,9 @@ class CefMenuModelImpl : public CefMenuModel { // Callbacks from the ui::MenuModel implementation. void ActivatedAt(int index, cef_event_flags_t event_flags); + void MouseOutsideMenu(const gfx::Point& screen_point); + void UnhandledOpenSubmenu(bool is_rtl); + void UnhandledCloseSubmenu(bool is_rtl); void MenuWillShow(); void MenuWillClose(); base::string16 GetFormattedLabelAt(int index); @@ -131,21 +136,20 @@ class CefMenuModelImpl : public CefMenuModel { // Verify that only a single reference exists to all CefMenuModelImpl objects. bool VerifyRefCount(); - // Manage observer objects. The observer must either outlive this object or - // remove itself before destruction. - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); - bool HasObserver(Observer* observer) const; - // Helper for adding custom menu items originating from the renderer process. void AddMenuItem(const content::MenuItem& menu_item); - ui::MenuModel* model() { return model_.get(); } + ui::MenuModel* model() const { return model_.get(); } // Used when created via CefMenuManager. - Delegate* delegate() { return delegate_; } + Delegate* delegate() const { return delegate_; } void set_delegate(Delegate* delegate) { delegate_ = delegate; } + // Used for menus run via CefWindowImpl::ShowMenu to provide more accurate + // menu close notification. + void set_auto_notify_menu_closed(bool val) { auto_notify_menu_closed_ = val; } + void NotifyMenuClosed(); + private: struct Item; @@ -156,7 +160,10 @@ class CefMenuModelImpl : public CefMenuModel { void InsertItemAt(const Item& item, int index); void ValidateItem(const Item& item); - // Notify the delegate that the menu is closed. + // Notify the delegate asynchronously. + void OnMouseOutsideMenu(const gfx::Point& screen_point); + void OnUnhandledOpenSubmenu(bool is_rtl); + void OnUnhandledCloseSubmenu(bool is_rtl); void OnMenuClosed(); // Verify that the object is being accessed from the correct thread. @@ -170,11 +177,12 @@ class CefMenuModelImpl : public CefMenuModel { // Used when created via CefMenuModel::CreateMenuModel(). CefRefPtr menu_model_delegate_; + const bool is_submenu_; + ItemVector items_; std::unique_ptr model_; - // Observers that want to be notified of changes to this object. - base::ObserverList observers_; + bool auto_notify_menu_closed_ = true; IMPLEMENT_REFCOUNTING(CefMenuModelImpl); DISALLOW_COPY_AND_ASSIGN(CefMenuModelImpl); diff --git a/libcef/browser/views/button_view.h b/libcef/browser/views/button_view.h index bd985dbba..40913b245 100644 --- a/libcef/browser/views/button_view.h +++ b/libcef/browser/views/button_view.h @@ -40,10 +40,19 @@ CEF_BUTTON_VIEW_T class CefButtonView : public CEF_VIEW_VIEW_D { return button; } + // views::CustomButton methods: + void StateChanged() override; + // views::ButtonListener methods: void ButtonPressed(views::Button* sender, const ui::Event& event) override; }; +CEF_BUTTON_VIEW_T void CEF_BUTTON_VIEW_D::StateChanged() { + ParentClass::StateChanged(); + if (ParentClass::cef_delegate()) + ParentClass::cef_delegate()->OnButtonStateChanged(GetCefButton()); +} + CEF_BUTTON_VIEW_T void CEF_BUTTON_VIEW_D::ButtonPressed( views::Button* sender, const ui::Event& event) { if (ParentClass::cef_delegate()) diff --git a/libcef/browser/views/menu_button_impl.cc b/libcef/browser/views/menu_button_impl.cc index bba0674f0..d5b2d8663 100644 --- a/libcef/browser/views/menu_button_impl.cc +++ b/libcef/browser/views/menu_button_impl.cc @@ -50,6 +50,11 @@ void CefMenuButtonImpl::ShowMenu(CefRefPtr menu_model, } } +void CefMenuButtonImpl::TriggerMenu() { + CEF_REQUIRE_VALID_RETURN_VOID(); + root_view()->Activate(nullptr); +} + CefMenuButtonImpl::CefMenuButtonImpl(CefRefPtr delegate) : ParentClass(delegate) { DCHECK(delegate); diff --git a/libcef/browser/views/menu_button_impl.h b/libcef/browser/views/menu_button_impl.h index d1dec09df..2ef1e88eb 100644 --- a/libcef/browser/views/menu_button_impl.h +++ b/libcef/browser/views/menu_button_impl.h @@ -32,6 +32,7 @@ class CefMenuButtonImpl : void ShowMenu(CefRefPtr menu_model, const CefPoint& screen_point, cef_menu_anchor_position_t anchor_position) override; + void TriggerMenu() override; // CefLabelButton methods: CefRefPtr AsMenuButton() override { return this; } diff --git a/libcef/browser/views/window_impl.cc b/libcef/browser/views/window_impl.cc index 5fd52b464..bcd16e830 100644 --- a/libcef/browser/views/window_impl.cc +++ b/libcef/browser/views/window_impl.cc @@ -390,13 +390,6 @@ void CefWindowImpl::OnWindowViewDeleted() { Detach(); } -void CefWindowImpl::MenuClosed(CefRefPtr source) { - DCHECK_EQ(menu_model_, source); - menu_model_->RemoveObserver(this); - menu_model_ = nullptr; - menu_runner_.reset(nullptr); -} - // Will only be called if CanHandleAccelerators() returns true. bool CefWindowImpl::AcceleratorPressed(const ui::Accelerator& accelerator) { for (const auto& entry : accelerator_map_) { @@ -433,12 +426,16 @@ void CefWindowImpl::ShowMenu(views::MenuButton* menu_button, return; menu_model_ = menu_model_impl; - menu_model_->AddObserver(this); + + // We'll send the MenuClosed notification manually for better accuracy. + menu_model_->set_auto_notify_menu_closed(false); menu_runner_.reset( new views::MenuRunner(menu_model_impl->model(), - menu_button ? views::MenuRunner::HAS_MNEMONICS : - views::MenuRunner::CONTEXT_MENU)); + views::MenuRunner::ASYNC | + (menu_button ? views::MenuRunner::HAS_MNEMONICS : + views::MenuRunner::CONTEXT_MENU), + base::Bind(&CefWindowImpl::MenuClosed, this))); views::MenuRunner::RunResult result = menu_runner_->RunMenuAt( widget_, @@ -449,6 +446,12 @@ void CefWindowImpl::ShowMenu(views::MenuButton* menu_button, ALLOW_UNUSED_LOCAL(result); } +void CefWindowImpl::MenuClosed() { + menu_model_->NotifyMenuClosed(); + menu_model_ = nullptr; + menu_runner_.reset(nullptr); +} + void CefWindowImpl::CancelMenu() { CEF_REQUIRE_VALID_RETURN_VOID(); if (menu_runner_) diff --git a/libcef/browser/views/window_impl.h b/libcef/browser/views/window_impl.h index 4f8598cdf..39f54c860 100644 --- a/libcef/browser/views/window_impl.h +++ b/libcef/browser/views/window_impl.h @@ -26,7 +26,6 @@ class MenuButton; class CefWindowImpl : public CefPanelImpl, public CefWindowView::Delegate, - public CefMenuModelImpl::Observer, public ui::AcceleratorTarget { public: typedef CefPanelImpl ParentClass; @@ -105,9 +104,6 @@ class CefWindowImpl : void OnWindowClosing() override; void OnWindowViewDeleted() override; - // CefMenuModelImpl::Observer methods: - void MenuClosed(CefRefPtr source) override; - // CefViewAdapter methods: std::string GetDebugType() override { return "Window"; } void GetDebugInfo(base::DictionaryValue* info, @@ -125,6 +121,7 @@ class CefWindowImpl : CefRefPtr menu_model, const CefPoint& screen_point, cef_menu_anchor_position_t anchor_position); + void MenuClosed(); private: // Create a new implementation object. diff --git a/libcef_dll/cpptoc/menu_model_cpptoc.cc b/libcef_dll/cpptoc/menu_model_cpptoc.cc index 5e1aa20c3..277b59f0c 100644 --- a/libcef_dll/cpptoc/menu_model_cpptoc.cc +++ b/libcef_dll/cpptoc/menu_model_cpptoc.cc @@ -38,6 +38,20 @@ namespace { // MEMBER FUNCTIONS - Body may be edited by hand. +int CEF_CALLBACK menu_model_is_sub_menu(struct _cef_menu_model_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + bool _retval = CefMenuModelCppToC::Get(self)->IsSubMenu(); + + // Return type: bool + return _retval; +} + int CEF_CALLBACK menu_model_clear(struct _cef_menu_model_t* self) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -986,6 +1000,7 @@ int CEF_CALLBACK menu_model_get_accelerator_at(struct _cef_menu_model_t* self, // CONSTRUCTOR - Do not edit by hand. CefMenuModelCppToC::CefMenuModelCppToC() { + GetStruct()->is_sub_menu = menu_model_is_sub_menu; GetStruct()->clear = menu_model_clear; GetStruct()->get_count = menu_model_get_count; GetStruct()->add_separator = menu_model_add_separator; diff --git a/libcef_dll/cpptoc/menu_model_delegate_cpptoc.cc b/libcef_dll/cpptoc/menu_model_delegate_cpptoc.cc index f022b8189..439fa71fa 100644 --- a/libcef_dll/cpptoc/menu_model_delegate_cpptoc.cc +++ b/libcef_dll/cpptoc/menu_model_delegate_cpptoc.cc @@ -38,6 +38,70 @@ void CEF_CALLBACK menu_model_delegate_execute_command( event_flags); } +void CEF_CALLBACK menu_model_delegate_mouse_outside_menu( + struct _cef_menu_model_delegate_t* self, cef_menu_model_t* menu_model, + const cef_point_t* screen_point) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: menu_model; type: refptr_diff + DCHECK(menu_model); + if (!menu_model) + return; + // Verify param: screen_point; type: simple_byref_const + DCHECK(screen_point); + if (!screen_point) + return; + + // Translate param: screen_point; type: simple_byref_const + CefPoint screen_pointVal = screen_point?*screen_point:CefPoint(); + + // Execute + CefMenuModelDelegateCppToC::Get(self)->MouseOutsideMenu( + CefMenuModelCToCpp::Wrap(menu_model), + screen_pointVal); +} + +void CEF_CALLBACK menu_model_delegate_unhandled_open_submenu( + struct _cef_menu_model_delegate_t* self, cef_menu_model_t* menu_model, + int is_rtl) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: menu_model; type: refptr_diff + DCHECK(menu_model); + if (!menu_model) + return; + + // Execute + CefMenuModelDelegateCppToC::Get(self)->UnhandledOpenSubmenu( + CefMenuModelCToCpp::Wrap(menu_model), + is_rtl?true:false); +} + +void CEF_CALLBACK menu_model_delegate_unhandled_close_submenu( + struct _cef_menu_model_delegate_t* self, cef_menu_model_t* menu_model, + int is_rtl) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: menu_model; type: refptr_diff + DCHECK(menu_model); + if (!menu_model) + return; + + // Execute + CefMenuModelDelegateCppToC::Get(self)->UnhandledCloseSubmenu( + CefMenuModelCToCpp::Wrap(menu_model), + is_rtl?true:false); +} + void CEF_CALLBACK menu_model_delegate_menu_will_show( struct _cef_menu_model_delegate_t* self, cef_menu_model_t* menu_model) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -108,6 +172,11 @@ int CEF_CALLBACK menu_model_delegate_format_label( CefMenuModelDelegateCppToC::CefMenuModelDelegateCppToC() { GetStruct()->execute_command = menu_model_delegate_execute_command; + GetStruct()->mouse_outside_menu = menu_model_delegate_mouse_outside_menu; + GetStruct()->unhandled_open_submenu = + menu_model_delegate_unhandled_open_submenu; + GetStruct()->unhandled_close_submenu = + menu_model_delegate_unhandled_close_submenu; GetStruct()->menu_will_show = menu_model_delegate_menu_will_show; GetStruct()->menu_closed = menu_model_delegate_menu_closed; GetStruct()->format_label = menu_model_delegate_format_label; diff --git a/libcef_dll/cpptoc/views/button_delegate_cpptoc.cc b/libcef_dll/cpptoc/views/button_delegate_cpptoc.cc index 7fc694f34..930bd1ab8 100644 --- a/libcef_dll/cpptoc/views/button_delegate_cpptoc.cc +++ b/libcef_dll/cpptoc/views/button_delegate_cpptoc.cc @@ -37,6 +37,23 @@ void CEF_CALLBACK button_delegate_on_button_pressed( CefButtonCToCpp::Wrap(button)); } +void CEF_CALLBACK button_delegate_on_button_state_changed( + struct _cef_button_delegate_t* self, cef_button_t* button) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: button; type: refptr_diff + DCHECK(button); + if (!button) + return; + + // Execute + CefButtonDelegateCppToC::Get(self)->OnButtonStateChanged( + CefButtonCToCpp::Wrap(button)); +} + cef_size_t CEF_CALLBACK button_delegate_get_preferred_size( struct _cef_view_delegate_t* self, cef_view_t* view) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -215,6 +232,8 @@ void CEF_CALLBACK button_delegate_on_blur(struct _cef_view_delegate_t* self, CefButtonDelegateCppToC::CefButtonDelegateCppToC() { GetStruct()->on_button_pressed = button_delegate_on_button_pressed; + GetStruct()->on_button_state_changed = + button_delegate_on_button_state_changed; GetStruct()->base.get_preferred_size = button_delegate_get_preferred_size; GetStruct()->base.get_minimum_size = button_delegate_get_minimum_size; GetStruct()->base.get_maximum_size = button_delegate_get_maximum_size; diff --git a/libcef_dll/cpptoc/views/menu_button_cpptoc.cc b/libcef_dll/cpptoc/views/menu_button_cpptoc.cc index bbe47edf4..d7e0c17a6 100644 --- a/libcef_dll/cpptoc/views/menu_button_cpptoc.cc +++ b/libcef_dll/cpptoc/views/menu_button_cpptoc.cc @@ -81,6 +81,17 @@ void CEF_CALLBACK menu_button_show_menu(struct _cef_menu_button_t* self, anchor_position); } +void CEF_CALLBACK menu_button_trigger_menu(struct _cef_menu_button_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefMenuButtonCppToC::Get(self)->TriggerMenu(); +} + cef_menu_button_t* CEF_CALLBACK menu_button_as_menu_button( struct _cef_label_button_t* self) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -1186,6 +1197,7 @@ int CEF_CALLBACK menu_button_convert_point_from_view(struct _cef_view_t* self, CefMenuButtonCppToC::CefMenuButtonCppToC() { GetStruct()->show_menu = menu_button_show_menu; + GetStruct()->trigger_menu = menu_button_trigger_menu; GetStruct()->base.as_menu_button = menu_button_as_menu_button; GetStruct()->base.set_text = menu_button_set_text; GetStruct()->base.get_text = menu_button_get_text; diff --git a/libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.cc b/libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.cc index 5305cac41..f86c6b4b8 100644 --- a/libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.cc +++ b/libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.cc @@ -64,6 +64,25 @@ void CEF_CALLBACK menu_button_delegate_on_button_pressed( CefButtonCToCpp::Wrap(button)); } +void CEF_CALLBACK menu_button_delegate_on_button_state_changed( + struct _cef_button_delegate_t* self, cef_button_t* button) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: button; type: refptr_diff + DCHECK(button); + if (!button) + return; + + // Execute + CefMenuButtonDelegateCppToC::Get( + reinterpret_cast( + self))->OnButtonStateChanged( + CefButtonCToCpp::Wrap(button)); +} + cef_size_t CEF_CALLBACK menu_button_delegate_get_preferred_size( struct _cef_view_delegate_t* self, cef_view_t* view) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -244,6 +263,8 @@ CefMenuButtonDelegateCppToC::CefMenuButtonDelegateCppToC() { GetStruct()->on_menu_button_pressed = menu_button_delegate_on_menu_button_pressed; GetStruct()->base.on_button_pressed = menu_button_delegate_on_button_pressed; + GetStruct()->base.on_button_state_changed = + menu_button_delegate_on_button_state_changed; GetStruct()->base.base.get_preferred_size = menu_button_delegate_get_preferred_size; GetStruct()->base.base.get_minimum_size = diff --git a/libcef_dll/ctocpp/menu_model_ctocpp.cc b/libcef_dll/ctocpp/menu_model_ctocpp.cc index 0c469babd..b727527b9 100644 --- a/libcef_dll/ctocpp/menu_model_ctocpp.cc +++ b/libcef_dll/ctocpp/menu_model_ctocpp.cc @@ -36,6 +36,20 @@ CefRefPtr CefMenuModel::CreateMenuModel( // VIRTUAL METHODS - Body may be edited by hand. +bool CefMenuModelCToCpp::IsSubMenu() { + cef_menu_model_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, is_sub_menu)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = _struct->is_sub_menu(_struct); + + // Return type: bool + return _retval?true:false; +} + bool CefMenuModelCToCpp::Clear() { cef_menu_model_t* _struct = GetStruct(); if (CEF_MEMBER_MISSING(_struct, clear)) diff --git a/libcef_dll/ctocpp/menu_model_ctocpp.h b/libcef_dll/ctocpp/menu_model_ctocpp.h index 5f43bf19e..baea2d41b 100644 --- a/libcef_dll/ctocpp/menu_model_ctocpp.h +++ b/libcef_dll/ctocpp/menu_model_ctocpp.h @@ -31,6 +31,7 @@ class CefMenuModelCToCpp CefMenuModelCToCpp(); // CefMenuModel methods. + bool IsSubMenu() OVERRIDE; bool Clear() OVERRIDE; int GetCount() OVERRIDE; bool AddSeparator() OVERRIDE; diff --git a/libcef_dll/ctocpp/menu_model_delegate_ctocpp.cc b/libcef_dll/ctocpp/menu_model_delegate_ctocpp.cc index 96eadabab..58600dbed 100644 --- a/libcef_dll/ctocpp/menu_model_delegate_ctocpp.cc +++ b/libcef_dll/ctocpp/menu_model_delegate_ctocpp.cc @@ -37,6 +37,63 @@ void CefMenuModelDelegateCToCpp::ExecuteCommand( event_flags); } +void CefMenuModelDelegateCToCpp::MouseOutsideMenu( + CefRefPtr menu_model, const CefPoint& screen_point) { + cef_menu_model_delegate_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, mouse_outside_menu)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: menu_model; type: refptr_diff + DCHECK(menu_model.get()); + if (!menu_model.get()) + return; + + // Execute + _struct->mouse_outside_menu(_struct, + CefMenuModelCppToC::Wrap(menu_model), + &screen_point); +} + +void CefMenuModelDelegateCToCpp::UnhandledOpenSubmenu( + CefRefPtr menu_model, bool is_rtl) { + cef_menu_model_delegate_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, unhandled_open_submenu)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: menu_model; type: refptr_diff + DCHECK(menu_model.get()); + if (!menu_model.get()) + return; + + // Execute + _struct->unhandled_open_submenu(_struct, + CefMenuModelCppToC::Wrap(menu_model), + is_rtl); +} + +void CefMenuModelDelegateCToCpp::UnhandledCloseSubmenu( + CefRefPtr menu_model, bool is_rtl) { + cef_menu_model_delegate_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, unhandled_close_submenu)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: menu_model; type: refptr_diff + DCHECK(menu_model.get()); + if (!menu_model.get()) + return; + + // Execute + _struct->unhandled_close_submenu(_struct, + CefMenuModelCppToC::Wrap(menu_model), + is_rtl); +} + void CefMenuModelDelegateCToCpp::MenuWillShow( CefRefPtr menu_model) { cef_menu_model_delegate_t* _struct = GetStruct(); diff --git a/libcef_dll/ctocpp/menu_model_delegate_ctocpp.h b/libcef_dll/ctocpp/menu_model_delegate_ctocpp.h index e8feba065..9e206507d 100644 --- a/libcef_dll/ctocpp/menu_model_delegate_ctocpp.h +++ b/libcef_dll/ctocpp/menu_model_delegate_ctocpp.h @@ -35,6 +35,12 @@ class CefMenuModelDelegateCToCpp // CefMenuModelDelegate methods. void ExecuteCommand(CefRefPtr menu_model, int command_id, cef_event_flags_t event_flags) override; + void MouseOutsideMenu(CefRefPtr menu_model, + const CefPoint& screen_point) override; + void UnhandledOpenSubmenu(CefRefPtr menu_model, + bool is_rtl) override; + void UnhandledCloseSubmenu(CefRefPtr menu_model, + bool is_rtl) override; void MenuWillShow(CefRefPtr menu_model) override; void MenuClosed(CefRefPtr menu_model) override; bool FormatLabel(CefRefPtr menu_model, diff --git a/libcef_dll/ctocpp/views/button_delegate_ctocpp.cc b/libcef_dll/ctocpp/views/button_delegate_ctocpp.cc index 24dbaeb63..674e2df53 100644 --- a/libcef_dll/ctocpp/views/button_delegate_ctocpp.cc +++ b/libcef_dll/ctocpp/views/button_delegate_ctocpp.cc @@ -35,6 +35,24 @@ void CefButtonDelegateCToCpp::OnButtonPressed(CefRefPtr button) { CefButtonCppToC::Wrap(button)); } +void CefButtonDelegateCToCpp::OnButtonStateChanged( + CefRefPtr button) { + cef_button_delegate_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, on_button_state_changed)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: button; type: refptr_diff + DCHECK(button.get()); + if (!button.get()) + return; + + // Execute + _struct->on_button_state_changed(_struct, + CefButtonCppToC::Wrap(button)); +} + CefSize CefButtonDelegateCToCpp::GetPreferredSize(CefRefPtr view) { cef_view_delegate_t* _struct = reinterpret_cast( GetStruct()); diff --git a/libcef_dll/ctocpp/views/button_delegate_ctocpp.h b/libcef_dll/ctocpp/views/button_delegate_ctocpp.h index d794f1203..0e65769b3 100644 --- a/libcef_dll/ctocpp/views/button_delegate_ctocpp.h +++ b/libcef_dll/ctocpp/views/button_delegate_ctocpp.h @@ -34,6 +34,7 @@ class CefButtonDelegateCToCpp // CefButtonDelegate methods. void OnButtonPressed(CefRefPtr button) override; + void OnButtonStateChanged(CefRefPtr button) override; // CefViewDelegate methods. CefSize GetPreferredSize(CefRefPtr view) override; diff --git a/libcef_dll/ctocpp/views/menu_button_ctocpp.cc b/libcef_dll/ctocpp/views/menu_button_ctocpp.cc index 7d93089ac..009bc6647 100644 --- a/libcef_dll/ctocpp/views/menu_button_ctocpp.cc +++ b/libcef_dll/ctocpp/views/menu_button_ctocpp.cc @@ -73,6 +73,17 @@ void CefMenuButtonCToCpp::ShowMenu(CefRefPtr menu_model, anchor_position); } +void CefMenuButtonCToCpp::TriggerMenu() { + cef_menu_button_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, trigger_menu)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + _struct->trigger_menu(_struct); +} + CefRefPtr CefMenuButtonCToCpp::AsMenuButton() { cef_label_button_t* _struct = reinterpret_cast(GetStruct( )); diff --git a/libcef_dll/ctocpp/views/menu_button_ctocpp.h b/libcef_dll/ctocpp/views/menu_button_ctocpp.h index d9a397a3d..b4342ed8d 100644 --- a/libcef_dll/ctocpp/views/menu_button_ctocpp.h +++ b/libcef_dll/ctocpp/views/menu_button_ctocpp.h @@ -34,6 +34,7 @@ class CefMenuButtonCToCpp void ShowMenu(CefRefPtr menu_model, const CefPoint& screen_point, cef_menu_anchor_position_t anchor_position) OVERRIDE; + void TriggerMenu() OVERRIDE; // CefLabelButton methods. CefRefPtr AsMenuButton() OVERRIDE; diff --git a/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.cc b/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.cc index c39cea275..a29127f99 100644 --- a/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.cc +++ b/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.cc @@ -55,6 +55,25 @@ void CefMenuButtonDelegateCToCpp::OnButtonPressed(CefRefPtr button) { CefButtonCppToC::Wrap(button)); } +void CefMenuButtonDelegateCToCpp::OnButtonStateChanged( + CefRefPtr button) { + cef_button_delegate_t* _struct = reinterpret_cast( + GetStruct()); + if (CEF_MEMBER_MISSING(_struct, on_button_state_changed)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: button; type: refptr_diff + DCHECK(button.get()); + if (!button.get()) + return; + + // Execute + _struct->on_button_state_changed(_struct, + CefButtonCppToC::Wrap(button)); +} + CefSize CefMenuButtonDelegateCToCpp::GetPreferredSize(CefRefPtr view) { cef_view_delegate_t* _struct = reinterpret_cast( GetStruct()); diff --git a/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h b/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h index 701ea49cf..cd02c0e82 100644 --- a/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h +++ b/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h @@ -38,6 +38,7 @@ class CefMenuButtonDelegateCToCpp // CefButtonDelegate methods. void OnButtonPressed(CefRefPtr button) override; + void OnButtonStateChanged(CefRefPtr button) override; // CefViewDelegate methods. CefSize GetPreferredSize(CefRefPtr view) override; diff --git a/patch/patch.cfg b/patch/patch.cfg index 7f854b692..d897a2541 100644 --- a/patch/patch.cfg +++ b/patch/patch.cfg @@ -327,4 +327,10 @@ patches = [ 'name': 'plugin_info_webkit_2015', 'path': '../third_party/WebKit/', }, + { + # Expose callbacks for mouse/keyboard events that trigger menu switching. + # https://bitbucket.org/chromiumembedded/cef/issues/2102 + 'name': 'views_menu_2102', + 'path': '../', + }, ] diff --git a/patch/patches/views_menu_2102.patch b/patch/patches/views_menu_2102.patch new file mode 100644 index 000000000..10630916d --- /dev/null +++ b/patch/patches/views_menu_2102.patch @@ -0,0 +1,147 @@ +diff --git ui/base/models/menu_model.h ui/base/models/menu_model.h +index 0755f27..72db677 100644 +--- ui/base/models/menu_model.h ++++ ui/base/models/menu_model.h +@@ -15,6 +15,7 @@ + namespace gfx { + class FontList; + class Image; ++class Point; + } + + namespace ui { +@@ -115,6 +116,15 @@ class UI_BASE_EXPORT MenuModel { + // |event_flags| is a bit mask of ui::EventFlags. + virtual void ActivatedAt(int index, int event_flags); + ++ // Called when the user moves the mouse outside the menu and over the owning ++ // window. ++ virtual void MouseOutsideMenu(const gfx::Point& screen_point) {} ++ ++ // Called on unhandled open/close submenu keyboard commands. |is_rtl| will be ++ // true if the menu is displaying a right-to-left language. ++ virtual void UnhandledOpenSubmenu(bool is_rtl) {} ++ virtual void UnhandledCloseSubmenu(bool is_rtl) {} ++ + // Called when the menu is about to be shown. + virtual void MenuWillShow() {} + +diff --git ui/views/controls/menu/menu_controller.cc ui/views/controls/menu/menu_controller.cc +index 79ff77c..a0582c0 100644 +--- ui/views/controls/menu/menu_controller.cc ++++ ui/views/controls/menu/menu_controller.cc +@@ -2254,8 +2254,13 @@ MenuItemView* MenuController::FindNextSelectableMenuItem( + + void MenuController::OpenSubmenuChangeSelectionIfCan() { + MenuItemView* item = pending_state_.item; +- if (!item->HasSubmenu() || !item->enabled()) ++ if (!item->HasSubmenu() || !item->enabled() || !item->GetParentMenuItem()) { ++ MenuItemView* submenu_item = ++ item->GetParentMenuItem() ? item->GetParentMenuItem() : item; ++ submenu_item->GetDelegate()->OnUnhandledOpenSubmenu(submenu_item, ++ base::i18n::IsRTL()); + return; ++ } + MenuItemView* to_select = NULL; + if (item->GetSubmenu()->GetMenuItemCount() > 0) + to_select = FindInitialSelectableMenuItem(item, INCREMENT_SELECTION_DOWN); +@@ -2270,8 +2275,10 @@ void MenuController::OpenSubmenuChangeSelectionIfCan() { + void MenuController::CloseSubmenu() { + MenuItemView* item = state_.item; + DCHECK(item); +- if (!item->GetParentMenuItem()) ++ if (!item->GetParentMenuItem()) { ++ item->GetDelegate()->OnUnhandledCloseSubmenu(item, base::i18n::IsRTL()); + return; ++ } + if (item->HasSubmenu() && item->GetSubmenu()->IsShowing()) + SetSelection(item, SELECTION_UPDATE_IMMEDIATELY); + else if (item->GetParentMenuItem()->GetParentMenuItem()) +diff --git ui/views/controls/menu/menu_delegate.h ui/views/controls/menu/menu_delegate.h +index 3b7cb7f..3ad68d0 100644 +--- ui/views/controls/menu/menu_delegate.h ++++ ui/views/controls/menu/menu_delegate.h +@@ -229,6 +229,11 @@ class VIEWS_EXPORT MenuDelegate { + bool* has_mnemonics, + MenuButton** button); + ++ // Called on unhandled open/close submenu keyboard commands. |is_rtl| will be ++ // true if the menu is displaying a right-to-left language. ++ virtual void OnUnhandledOpenSubmenu(MenuItemView* menu, bool is_rtl) {} ++ virtual void OnUnhandledCloseSubmenu(MenuItemView* menu, bool is_rtl) {} ++ + // Returns the max width menus can grow to be. + virtual int GetMaxWidthForMenu(MenuItemView* menu); + +diff --git ui/views/controls/menu/menu_model_adapter.cc ui/views/controls/menu/menu_model_adapter.cc +index bc04dcb..b2ec114 100644 +--- ui/views/controls/menu/menu_model_adapter.cc ++++ ui/views/controls/menu/menu_model_adapter.cc +@@ -245,6 +245,49 @@ void MenuModelAdapter::SelectionChanged(MenuItemView* menu) { + NOTREACHED(); + } + ++MenuItemView* MenuModelAdapter::GetSiblingMenu(MenuItemView* menu, ++ const gfx::Point& screen_point, ++ MenuAnchorPosition* anchor, ++ bool* has_mnemonics, ++ MenuButton** button) { ++ // Look up the menu model for this menu. ++ const std::map::const_iterator map_iterator = ++ menu_map_.find(menu); ++ if (map_iterator != menu_map_.end()) { ++ map_iterator->second->MouseOutsideMenu(screen_point); ++ return nullptr; ++ } ++ ++ NOTREACHED(); ++ return nullptr; ++} ++ ++void MenuModelAdapter::OnUnhandledOpenSubmenu(MenuItemView* menu, ++ bool is_rtl) { ++ // Look up the menu model for this menu. ++ const std::map::const_iterator map_iterator = ++ menu_map_.find(menu); ++ if (map_iterator != menu_map_.end()) { ++ map_iterator->second->UnhandledOpenSubmenu(is_rtl); ++ return; ++ } ++ ++ NOTREACHED(); ++} ++ ++void MenuModelAdapter::OnUnhandledCloseSubmenu(MenuItemView* menu, ++ bool is_rtl) { ++ // Look up the menu model for this menu. ++ const std::map::const_iterator map_iterator = ++ menu_map_.find(menu); ++ if (map_iterator != menu_map_.end()) { ++ map_iterator->second->UnhandledCloseSubmenu(is_rtl); ++ return; ++ } ++ ++ NOTREACHED(); ++} ++ + void MenuModelAdapter::WillShowMenu(MenuItemView* menu) { + // Look up the menu model for this menu. + const std::map::const_iterator map_iterator = +diff --git ui/views/controls/menu/menu_model_adapter.h ui/views/controls/menu/menu_model_adapter.h +index c9799da..c7ecca6 100644 +--- ui/views/controls/menu/menu_model_adapter.h ++++ ui/views/controls/menu/menu_model_adapter.h +@@ -76,6 +76,13 @@ class VIEWS_EXPORT MenuModelAdapter : public MenuDelegate { + bool IsCommandVisible(int id) const override; + bool IsItemChecked(int id) const override; + void SelectionChanged(MenuItemView* menu) override; ++ MenuItemView* GetSiblingMenu(MenuItemView* menu, ++ const gfx::Point& screen_point, ++ MenuAnchorPosition* anchor, ++ bool* has_mnemonics, ++ MenuButton** button) override; ++ void OnUnhandledOpenSubmenu(MenuItemView* menu, bool is_rtl) override; ++ void OnUnhandledCloseSubmenu(MenuItemView* menu, bool is_rtl) override; + void WillShowMenu(MenuItemView* menu) override; + void WillHideMenu(MenuItemView* menu) override; + void OnMenuClosed(MenuItemView* menu, MenuRunner::RunResult result) override; diff --git a/tests/cefclient/browser/views_menu_bar.cc b/tests/cefclient/browser/views_menu_bar.cc new file mode 100644 index 000000000..06b291cef --- /dev/null +++ b/tests/cefclient/browser/views_menu_bar.cc @@ -0,0 +1,230 @@ +// Copyright (c) 2017 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_menu_bar.h" + +#include "include/views/cef_box_layout.h" +#include "include/views/cef_window.h" + +namespace client { + +namespace { + +const int kMenuBarGroupId = 100; + +} // namespace + +ViewsMenuBar::ViewsMenuBar(Delegate* delegate, + int menu_id_start) + : delegate_(delegate), + id_start_(menu_id_start), + id_next_(menu_id_start), + last_nav_with_keyboard_(false) { + DCHECK(delegate_); + DCHECK_GT(id_start_, 0); +} + +bool ViewsMenuBar::HasMenuId(int menu_id) const { + return menu_id >= id_start_ && menu_id < id_next_; +} + +CefRefPtr ViewsMenuBar::GetMenuPanel() { + EnsureMenuPanel(); + return panel_; +} + +CefRefPtr ViewsMenuBar::CreateMenuModel(const std::string& label, + int* menu_id) { + EnsureMenuPanel(); + + // Assign the new menu ID. + const int new_menu_id = id_next_++; + if (menu_id) + *menu_id = new_menu_id; + + // Create the new MenuModel. + CefRefPtr model = CefMenuModel::CreateMenuModel(this); + models_.push_back(model); + + // Create the new MenuButton. + CefRefPtr button = + CefMenuButton::CreateMenuButton(this, label, false, false); + button->SetID(new_menu_id); + + // Assign a group ID to allow focus traversal between MenuButtons using the + // arrow keys when the menu is not displayed. + button->SetGroupID(kMenuBarGroupId); + + // Add the new MenuButton to the Planel. + panel_->AddChildView(button); + + return model; +} + +CefRefPtr ViewsMenuBar::GetMenuModel(int menu_id) const { + if (HasMenuId(menu_id)) + return models_[menu_id - id_start_]; + return NULL; +} + +void ViewsMenuBar::SetMenuFocusable(bool focusable) { + if (!panel_) + return; + + for (int id = id_start_; id < id_next_; ++id) + panel_->GetViewForID(id)->SetFocusable(focusable); + + if (focusable) { + // Give focus to the first MenuButton. + panel_->GetViewForID(id_start_)->RequestFocus(); + } +} + +void ViewsMenuBar::Reset() { + panel_ = NULL; + models_.clear(); + id_next_ = id_start_; +} + +void ViewsMenuBar::OnMenuButtonPressed(CefRefPtr menu_button, + const CefPoint& screen_point) { + CefRefPtr menu_model = GetMenuModel(menu_button->GetID()); + + // Adjust menu position left by button width. + CefPoint point = screen_point; + point.x -= menu_button->GetBounds().width - 4; + + // Keep track of the current |last_nav_with_keyboard_| status and restore it + // after displaying the new menu. + bool cur_last_nav_with_keyboard = last_nav_with_keyboard_; + + // May result in the previous menu being closed, in which case MenuClosed will + // be called before the new menu is displayed. + menu_button->ShowMenu(menu_model, point, CEF_MENU_ANCHOR_TOPLEFT); + + last_nav_with_keyboard_ = cur_last_nav_with_keyboard; +} + +void ViewsMenuBar::ExecuteCommand(CefRefPtr menu_model, + int command_id, + cef_event_flags_t event_flags) { + delegate_->MenuBarExecuteCommand(menu_model, command_id, event_flags); +} + +void ViewsMenuBar::MouseOutsideMenu(CefRefPtr menu_model, + const CefPoint& screen_point) { + DCHECK(panel_); + + // Retrieve the Window hosting the Panel. + CefRefPtr window = panel_->GetWindow(); + DCHECK(window); + + // Convert the point from screen to window coordinates. + CefPoint window_point = screen_point; + if (!window->ConvertPointFromScreen(window_point)) + return; + + CefRect panel_bounds = panel_->GetBounds(); + + if (last_nav_with_keyboard_) { + // The user navigated last using the keyboard. Don't change menus using + // mouse movements until the mouse exits and re-enters the Panel. + if (panel_bounds.Contains(window_point)) + return; + last_nav_with_keyboard_ = false; + } + + // Check that the point is inside the Panel. + if (!panel_bounds.Contains(window_point)) + return; + + const int active_menu_id = GetActiveMenuId(); + + // Determine which MenuButton is under the specified point. + for (int id = id_start_; id < id_next_; ++id) { + // Skip the currently active MenuButton. + if (id == active_menu_id) + continue; + + CefRefPtr button = panel_->GetViewForID(id); + CefRect button_bounds = button->GetBounds(); + if (button_bounds.Contains(window_point)) { + // Trigger the hovered MenuButton. + TriggerMenuButton(button); + break; + } + } +} + +void ViewsMenuBar::UnhandledOpenSubmenu(CefRefPtr menu_model, + bool is_rtl) { + TriggerNextMenu(is_rtl ? 1 : -1); +} + +void ViewsMenuBar::UnhandledCloseSubmenu(CefRefPtr menu_model, + bool is_rtl) { + TriggerNextMenu(is_rtl ? -1 : 1); +} + +void ViewsMenuBar::MenuClosed(CefRefPtr menu_model) { + // Reset |last_nav_with_keyboard_| status whenever the main menu closes. + if (!menu_model->IsSubMenu() && last_nav_with_keyboard_) + last_nav_with_keyboard_ = false; +} + +void ViewsMenuBar::EnsureMenuPanel() { + if (panel_) + return; + + panel_ = CefPanel::CreatePanel(NULL); + + // Use a horizontal box layout. + CefBoxLayoutSettings top_panel_layout_settings; + top_panel_layout_settings.horizontal = true; + panel_->SetToBoxLayout(top_panel_layout_settings); +} + +int ViewsMenuBar::GetActiveMenuId() { + DCHECK(panel_); + + for (int id = id_start_; id < id_next_; ++id) { + CefRefPtr button = panel_->GetViewForID(id)->AsButton(); + if (button->GetState() == CEF_BUTTON_STATE_PRESSED) + return id; + } + + return -1; +} + +void ViewsMenuBar::TriggerNextMenu(int offset) { + DCHECK(panel_); + + const int active_menu_id = GetActiveMenuId(); + const int menu_count = id_next_ - id_start_; + const int active_menu_index = active_menu_id - id_start_; + + // Compute the modulus to avoid negative values. + int next_menu_index = (active_menu_index + offset) % menu_count; + if (next_menu_index < 0) + next_menu_index += menu_count; + + // Cancel the existing menu. MenuClosed may be called. + panel_->GetWindow()->CancelMenu(); + + // Set status indicating that we navigated using the keyboard. + last_nav_with_keyboard_ = true; + + // Show the new menu. + TriggerMenuButton(panel_->GetViewForID(id_start_ + next_menu_index)); +} + +void ViewsMenuBar::TriggerMenuButton(CefRefPtr button) { + CefRefPtr menu_button = + button->AsButton()->AsLabelButton()->AsMenuButton(); + if (menu_button->IsFocusable()) + menu_button->RequestFocus(); + menu_button->TriggerMenu(); +} + +} // namespace client diff --git a/tests/cefclient/browser/views_menu_bar.h b/tests/cefclient/browser/views_menu_bar.h new file mode 100644 index 000000000..c24ef54c5 --- /dev/null +++ b/tests/cefclient/browser/views_menu_bar.h @@ -0,0 +1,116 @@ +// Copyright (c) 2017 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_TESTS_CEFCLIENT_BROWSER_VIEWS_MENU_BAR_H_ +#define CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_MENU_BAR_H_ +#pragma once + +#include +#include + +#include "include/cef_menu_model.h" +#include "include/cef_menu_model_delegate.h" +#include "include/views/cef_menu_button.h" +#include "include/views/cef_menu_button_delegate.h" +#include "include/views/cef_panel.h" + +namespace client { + +// Implements a menu bar which is composed of CefMenuButtons positioned in a +// row with automatic switching between them via mouse/keyboard. All methods +// must be called on the browser process UI thread. +class ViewsMenuBar : public CefMenuButtonDelegate, + public CefMenuModelDelegate { + public: + // Delegate methods will be called on the browser process UI thread. + class Delegate { + public: + // Called when a menu command is selected. + virtual void MenuBarExecuteCommand(CefRefPtr menu_model, + int command_id, + cef_event_flags_t event_flags) =0; + + protected: + virtual ~Delegate() {} + }; + + // |delegate| must outlive this object. + // |menu_id_start| is the ID for the first CefMenuButton in the bar. An ID + // range starting with |menu_id_start| and extending for a reasonable distance + // should be reserved in the client for MenuBar usage. + ViewsMenuBar(Delegate* delegate, + int menu_id_start); + + // Returns true if |menu_id| exists in the menu bar. + bool HasMenuId(int menu_id) const; + + // Returns the CefPanel that represents the menu bar. + CefRefPtr GetMenuPanel(); + + // Create a new menu with the specified |label|. If |menu_id| is non-NULL it + // will be populated with the new menu ID. + CefRefPtr CreateMenuModel(const std::string& label, + int* menu_id); + + // Returns the menu with the specified |menu_id|, or NULL if no such menu + // exists. + CefRefPtr GetMenuModel(int menu_id) const; + + // Assign or remove focus from the menu bar. + // Focus is assigned to the menu bar by ViewsWindow::OnKeyEvent when the ALT + // key is pressed. Focus is removed from the menu bar by ViewsWindow::OnFocus + // when a control not in the menu bar gains focus. + void SetMenuFocusable(bool focusable); + + // Reset menu bar state. + void Reset(); + + protected: + // CefButtonDelegate methods: + void OnButtonPressed(CefRefPtr button) OVERRIDE {} + + // CefMenuButtonDelegate methods: + void OnMenuButtonPressed(CefRefPtr menu_button, + const CefPoint& screen_point) OVERRIDE; + + // CefMenuModelDelegate methods: + void ExecuteCommand(CefRefPtr menu_model, + int command_id, + cef_event_flags_t event_flags) OVERRIDE; + void MouseOutsideMenu(CefRefPtr menu_model, + const CefPoint& screen_point) OVERRIDE; + void UnhandledOpenSubmenu(CefRefPtr menu_model, + bool is_rtl) OVERRIDE; + void UnhandledCloseSubmenu(CefRefPtr menu_model, + bool is_rtl) OVERRIDE; + void MenuClosed(CefRefPtr menu_model) OVERRIDE; + + private: + // Creates the menu panel if it doesn't already exist. + void EnsureMenuPanel(); + + // Returns the ID for the currently active menu, or -1 if no menu is currently + // active. + int GetActiveMenuId(); + + // Triggers the menu at the specified |offset| from the currently active menu. + void TriggerNextMenu(int offset); + + // Triggers the specified MenuButton |button|. + void TriggerMenuButton(CefRefPtr button); + + Delegate* delegate_; // Not owned by this object. + const int id_start_; + int id_next_; + CefRefPtr panel_; + std::vector > models_; + bool last_nav_with_keyboard_; + + IMPLEMENT_REFCOUNTING(ViewsMenuBar); + DISALLOW_COPY_AND_ASSIGN(ViewsMenuBar); +}; + +} // namespace client + +#endif // CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_MENU_BAR_H_ diff --git a/tests/cefclient/browser/views_window.cc b/tests/cefclient/browser/views_window.cc index 7a756b256..639761de2 100644 --- a/tests/cefclient/browser/views_window.cc +++ b/tests/cefclient/browser/views_window.cc @@ -34,8 +34,10 @@ enum ControlIds { ID_RELOAD_BUTTON, ID_URL_TEXTFIELD, ID_MENU_BUTTON, - ID_TOP_FILE_MENU_BUTTON, - ID_TOP_TEST_MENU_BUTTON, + + // Reserved range of top menu button IDs. + ID_TOP_MENU_FIRST, + ID_TOP_MENU_LAST = ID_TOP_MENU_FIRST + 10, }; typedef std::vector > LabelButtons; @@ -301,31 +303,10 @@ void ViewsWindow::OnMenuButtonPressed(CefRefPtr menu_button, const CefPoint& screen_point) { CEF_REQUIRE_UI_THREAD(); DCHECK(with_controls_); + DCHECK_EQ(ID_MENU_BUTTON, menu_button->GetID()); - CefRefPtr menu_model; - cef_menu_anchor_position_t position = CEF_MENU_ANCHOR_TOPLEFT; - - switch (menu_button->GetID()) { - case ID_MENU_BUTTON: - menu_model = button_menu_model_; - position = CEF_MENU_ANCHOR_TOPRIGHT; - break; - case ID_TOP_FILE_MENU_BUTTON: - menu_model = file_menu_model_; - break; - case ID_TOP_TEST_MENU_BUTTON: - menu_model = test_menu_model_; - break; - } - - CefPoint point = screen_point; - if (position == CEF_MENU_ANCHOR_TOPLEFT) { - // Adjust menu position left by button width. - point.x -= menu_button->GetBounds().width - 4; - } - - if (menu_model) - menu_button->ShowMenu(menu_model, point, position); + menu_button->ShowMenu(button_menu_model_, screen_point, + CEF_MENU_ANCHOR_TOPRIGHT); } void ViewsWindow::ExecuteCommand(CefRefPtr menu_model, @@ -430,8 +411,10 @@ void ViewsWindow::OnWindowDestroyed(CefRefPtr window) { browser_view_ = NULL; button_menu_model_ = NULL; - file_menu_model_ = NULL; - test_menu_model_ = NULL; + if (top_menu_bar_) { + top_menu_bar_->Reset(); + top_menu_bar_ = NULL; + } window_ = NULL; } @@ -492,17 +475,21 @@ void ViewsWindow::OnFocus(CefRefPtr view) { // When focus leaves the menu buttons make them unfocusable. if (menu_has_focus_) { const int view_id = view->GetID(); - if (with_top_menu_) { - if (view_id != ID_TOP_FILE_MENU_BUTTON && - view_id != ID_TOP_TEST_MENU_BUTTON) { + if (top_menu_bar_) { + if (!top_menu_bar_->HasMenuId(view_id)) SetMenuFocusable(false); - } } else if (view_id != ID_MENU_BUTTON) { SetMenuFocusable(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), @@ -515,7 +502,9 @@ ViewsWindow::ViewsWindow(Delegate* delegate, CefRefPtr command_line = CefCommandLine::GetGlobalCommandLine(); frameless_ = command_line->HasSwitch(switches::kHideFrame); - with_top_menu_ = command_line->HasSwitch(switches::kShowTopMenu); + + if (!command_line->HasSwitch(switches::kHideTopMenu)) + top_menu_bar_ = new ViewsMenuBar(this, ID_TOP_MENU_FIRST); } void ViewsWindow::SetBrowserView(CefRefPtr browser_view) { @@ -534,26 +523,13 @@ void ViewsWindow::CreateMenuModel() { AddTestMenuItems(test_menu); AddFileMenuItems(button_menu_model_, 1); - if (with_top_menu_) { - // Create the top menu model. - file_menu_model_ = CefMenuModel::CreateMenuModel(this); - AddFileMenuItems(file_menu_model_, 0); - test_menu_model_ = CefMenuModel::CreateMenuModel(this); - AddTestMenuItems(test_menu_model_); + if (top_menu_bar_) { + // Add the menus to the top menu bar. + AddFileMenuItems(top_menu_bar_->CreateMenuModel("File", NULL), 0); + AddTestMenuItems(top_menu_bar_->CreateMenuModel("Tests", NULL)); } } -CefRefPtr ViewsWindow::CreateTopMenuButton( - const std::string& label, int id) { - CefRefPtr button = - CefMenuButton::CreateMenuButton(this, label, false, false); - button->SetID(id); - // Assign a group ID to allow focus traversal between top menu buttons using - // the arrow keys. - button->SetGroupID(1); - return button; -} - CefRefPtr ViewsWindow::CreateBrowseButton( const std::string& label, int id) { @@ -570,25 +546,8 @@ void ViewsWindow::AddControls() { CreateMenuModel(); CefRefPtr top_menu_panel; - if (with_top_menu_) { - // Create the top menu buttons. - CefRefPtr top_file_menu_button = - CreateTopMenuButton("File", ID_TOP_FILE_MENU_BUTTON); - CefRefPtr top_test_menu_button = - CreateTopMenuButton("Test", ID_TOP_TEST_MENU_BUTTON); - - // Create the top menu panel. - top_menu_panel = CefPanel::CreatePanel(NULL); - - // Use a horizontal box layout for |top_panel|. - CefBoxLayoutSettings top_panel_layout_settings; - top_panel_layout_settings.horizontal = true; - CefRefPtr top_panel_layout = - top_menu_panel->SetToBoxLayout(top_panel_layout_settings); - - top_menu_panel->AddChildView(top_file_menu_button); - top_menu_panel->AddChildView(top_test_menu_button); - } + if (top_menu_bar_) + top_menu_panel = top_menu_bar_->GetMenuPanel(); // Create the browse buttons. LabelButtons browse_buttons; @@ -677,14 +636,8 @@ void ViewsWindow::SetMenuFocusable(bool focusable) { if (!window_ || !with_controls_) return; - if (with_top_menu_) { - window_->GetViewForID(ID_TOP_FILE_MENU_BUTTON)->SetFocusable(focusable); - window_->GetViewForID(ID_TOP_TEST_MENU_BUTTON)->SetFocusable(focusable); - - if (focusable) { - // Give focus to top file menu button. - window_->GetViewForID(ID_TOP_FILE_MENU_BUTTON)->RequestFocus(); - } + if (top_menu_bar_) { + top_menu_bar_->SetMenuFocusable(focusable); } else { window_->GetViewForID(ID_MENU_BUTTON)->SetFocusable(focusable); diff --git a/tests/cefclient/browser/views_window.h b/tests/cefclient/browser/views_window.h index 6b99a2807..3302bfc5a 100644 --- a/tests/cefclient/browser/views_window.h +++ b/tests/cefclient/browser/views_window.h @@ -19,6 +19,7 @@ #include "include/views/cef_textfield_delegate.h" #include "include/views/cef_window.h" #include "include/views/cef_window_delegate.h" +#include "tests/cefclient/browser/views_menu_bar.h" namespace client { @@ -29,7 +30,8 @@ class ViewsWindow : public CefBrowserViewDelegate, public CefMenuButtonDelegate, public CefMenuModelDelegate, public CefTextfieldDelegate, - public CefWindowDelegate { + public CefWindowDelegate, + public ViewsMenuBar::Delegate { public: // Delegate methods will be called on the browser process UI thread. class Delegate { @@ -120,6 +122,11 @@ class ViewsWindow : public CefBrowserViewDelegate, CefSize GetMinimumSize(CefRefPtr view) OVERRIDE; void OnFocus(CefRefPtr view) OVERRIDE; + // ViewsMenuBar::Delegate methods: + void MenuBarExecuteCommand(CefRefPtr menu_model, + int command_id, + cef_event_flags_t event_flags) OVERRIDE; + private: // |delegate| is guaranteed to outlive this object. // |browser_view| may be NULL, in which case SetBrowserView() will be called. @@ -130,8 +137,6 @@ class ViewsWindow : public CefBrowserViewDelegate, // Create controls. void CreateMenuModel(); - CefRefPtr CreateTopMenuButton(const std::string& label, - int id); CefRefPtr CreateBrowseButton(const std::string& label, int id); @@ -154,12 +159,10 @@ class ViewsWindow : public CefBrowserViewDelegate, CefRefPtr browser_view_; bool frameless_; bool with_controls_; - bool with_top_menu_; CefRefPtr window_; CefRefPtr button_menu_model_; - CefRefPtr file_menu_model_; - CefRefPtr test_menu_model_; + CefRefPtr top_menu_bar_; bool menu_has_focus_; CefSize minimum_window_size_; diff --git a/tests/shared/common/client_switches.cc b/tests/shared/common/client_switches.cc index 1b9411ddd..910eaadda 100644 --- a/tests/shared/common/client_switches.cc +++ b/tests/shared/common/client_switches.cc @@ -34,7 +34,7 @@ const char kFilterURL[] = "filter-url"; const char kUseViews[] = "use-views"; const char kHideFrame[] = "hide-frame"; const char kHideControls[] = "hide-controls"; -const char kShowTopMenu[] = "show-top-menu"; +const char kHideTopMenu[] = "hide-top-menu"; const char kWidevineCdmPath[] = "widevine-cdm-path"; const char kSslClientCertificate[] = "ssl-client-certificate"; diff --git a/tests/shared/common/client_switches.h b/tests/shared/common/client_switches.h index 6ce695633..7c656d9d4 100644 --- a/tests/shared/common/client_switches.h +++ b/tests/shared/common/client_switches.h @@ -28,7 +28,7 @@ extern const char kFilterURL[]; extern const char kUseViews[]; extern const char kHideFrame[]; extern const char kHideControls[]; -extern const char kShowTopMenu[]; +extern const char kHideTopMenu[]; extern const char kWidevineCdmPath[]; extern const char kSslClientCertificate[];