1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// found in the LICENSE file. 4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/controls/menu/menu_runner_impl.h" 6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/native_theme/native_theme.h" 8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/controls/button/menu_button.h" 9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/controls/menu/menu_controller.h" 10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/controls/menu/menu_delegate.h" 11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/controls/menu/menu_item_view.h" 12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/controls/menu/menu_runner_impl_adapter.h" 13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/widget/widget.h" 14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(OS_WIN) 16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/win/win_util.h" 17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif 18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 19116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace views { 20116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace internal { 21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if !defined(OS_MACOSX) 23116680a4aac90f2aa7413d9095a592090648e557Ben MurdochMenuRunnerImplInterface* MenuRunnerImplInterface::Create( 24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ui::MenuModel* menu_model, 25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int32 run_types) { 26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return new MenuRunnerImplAdapter(menu_model); 27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif 29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 30116680a4aac90f2aa7413d9095a592090648e557Ben MurdochMenuRunnerImpl::MenuRunnerImpl(MenuItemView* menu) 31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch : menu_(menu), 32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch running_(false), 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch delete_after_run_(false), 34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for_drop_(false), 35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller_(NULL), 36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch owns_controller_(false), 37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch closing_event_time_(base::TimeDelta()), 38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch weak_factory_(this) { 39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 41116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool MenuRunnerImpl::IsRunning() const { 42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return running_; 43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 45116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid MenuRunnerImpl::Release() { 46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (running_) { 47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (delete_after_run_) 48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; // We already canceled. 49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // The menu is running a nested message loop, we can't delete it now 51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // otherwise the stack would be in a really bad state (many frames would 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // have deleted objects on them). Instead cancel the menu, when it returns 53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Holder will delete itself. 54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch delete_after_run_ = true; 55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Swap in a different delegate. That way we know the original MenuDelegate 57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // won't be notified later on (when it's likely already been deleted). 58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!empty_delegate_.get()) 59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch empty_delegate_.reset(new MenuDelegate()); 60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch menu_->set_delegate(empty_delegate_.get()); 61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(controller_); 63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Release is invoked when MenuRunner is destroyed. Assume this is happening 64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // because the object referencing the menu has been destroyed and the menu 65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // button is no longer valid. 66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller_->Cancel(MenuController::EXIT_DESTROYED); 67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } else { 68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch delete this; 69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 72116680a4aac90f2aa7413d9095a592090648e557Ben MurdochMenuRunner::RunResult MenuRunnerImpl::RunMenuAt(Widget* parent, 73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch MenuButton* button, 74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const gfx::Rect& bounds, 75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch MenuAnchorPosition anchor, 76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int32 run_types) { 77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch closing_event_time_ = base::TimeDelta(); 78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (running_) { 79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Ignore requests to show the menu while it's already showing. MenuItemView 80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // doesn't handle this very well (meaning it crashes). 81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return MenuRunner::NORMAL_EXIT; 82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch MenuController* controller = MenuController::GetActiveInstance(); 85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (controller) { 86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if ((run_types & MenuRunner::IS_NESTED) != 0) { 87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!controller->IsBlockingRun()) { 88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller->CancelAll(); 89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller = NULL; 90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } else { 92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // There's some other menu open and we're not nested. Cancel the menu. 93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller->CancelAll(); 94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if ((run_types & MenuRunner::FOR_DROP) == 0) { 95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // We can't open another menu, otherwise the message loop would become 96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // twice nested. This isn't necessarily a problem, but generally isn't 97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // expected. 98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return MenuRunner::NORMAL_EXIT; 99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Drop menus don't block the message loop, so it's ok to create a new 101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // MenuController. 102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller = NULL; 103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch running_ = true; 107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for_drop_ = (run_types & MenuRunner::FOR_DROP) != 0; 1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool has_mnemonics = (run_types & MenuRunner::HAS_MNEMONICS) != 0; 109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch owns_controller_ = false; 110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!controller) { 111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // No menus are showing, show one. 112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ui::NativeTheme* theme = 113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch parent ? parent->GetNativeTheme() : ui::NativeTheme::instance(); 114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller = new MenuController(theme, !for_drop_, this); 115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch owns_controller_ = true; 116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller->set_is_combobox((run_types & MenuRunner::COMBOBOX) != 0); 118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller_ = controller; 119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch menu_->set_controller(controller_); 120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch menu_->PrepareForRun(owns_controller_, 121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch has_mnemonics, 122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch !for_drop_ && ShouldShowMnemonics(button)); 123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Run the loop. 125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int mouse_event_flags = 0; 126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch MenuItemView* result = 127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller->Run(parent, 128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch button, 129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch menu_, 130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bounds, 131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch anchor, 132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch (run_types & MenuRunner::CONTEXT_MENU) != 0, 1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (run_types & MenuRunner::NESTED_DRAG) != 0, 134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch &mouse_event_flags); 135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Get the time of the event which closed this menu. 136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch closing_event_time_ = controller->closing_event_time(); 137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (for_drop_) { 138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Drop menus return immediately. We finish processing in DropMenuClosed. 139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return MenuRunner::NORMAL_EXIT; 140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return MenuDone(result, mouse_event_flags); 142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 144116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid MenuRunnerImpl::Cancel() { 145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (running_) 146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller_->Cancel(MenuController::EXIT_ALL); 147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 149116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbase::TimeDelta MenuRunnerImpl::GetClosingEventTime() const { 150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return closing_event_time_; 151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 153116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid MenuRunnerImpl::DropMenuClosed(NotifyType type, MenuItemView* menu) { 154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch MenuDone(NULL, 0); 155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (type == NOTIFY_DELEGATE && menu->GetDelegate()) { 157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Delegate is null when invoked from the destructor. 158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch menu->GetDelegate()->DropMenuClosed(menu); 159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 162116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid MenuRunnerImpl::SiblingMenuCreated(MenuItemView* menu) { 163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (menu != menu_ && sibling_menus_.count(menu) == 0) 164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch sibling_menus_.insert(menu); 165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 167116680a4aac90f2aa7413d9095a592090648e557Ben MurdochMenuRunnerImpl::~MenuRunnerImpl() { 168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch delete menu_; 169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for (std::set<MenuItemView*>::iterator i = sibling_menus_.begin(); 170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch i != sibling_menus_.end(); 171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ++i) 172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch delete *i; 173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 175116680a4aac90f2aa7413d9095a592090648e557Ben MurdochMenuRunner::RunResult MenuRunnerImpl::MenuDone(MenuItemView* result, 176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int mouse_event_flags) { 177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch menu_->RemoveEmptyMenus(); 178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch menu_->set_controller(NULL); 179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (owns_controller_) { 181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // We created the controller and need to delete it. 182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch delete controller_; 183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch owns_controller_ = false; 184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch controller_ = NULL; 186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Make sure all the windows we created to show the menus have been 187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // destroyed. 188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch menu_->DestroyAllMenuHosts(); 189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (delete_after_run_) { 190116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch delete this; 191116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return MenuRunner::MENU_DELETED; 192116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch running_ = false; 194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (result && menu_->GetDelegate()) { 195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Executing the command may also delete this. 196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::WeakPtr<MenuRunnerImpl> ref(weak_factory_.GetWeakPtr()); 197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch menu_->GetDelegate()->ExecuteCommand(result->GetCommand(), 198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch mouse_event_flags); 199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!ref) 200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return MenuRunner::MENU_DELETED; 201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return MenuRunner::NORMAL_EXIT; 203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 205116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool MenuRunnerImpl::ShouldShowMnemonics(MenuButton* button) { 206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Show mnemonics if the button has focus or alt is pressed. 207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool show_mnemonics = button ? button->HasFocus() : false; 208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(OS_WIN) 209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // This is only needed on Windows. 210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!show_mnemonics) 211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch show_mnemonics = base::win::IsAltPressed(); 212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif 213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return show_mnemonics; 214116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} // namespace internal 217116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} // namespace views 218