Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Side by Side Diff: ui/views/controls/menu/menu_controller.cc

Issue 267593005: Refactor menu controller to isolate aura dependency. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removing ifdefs, work in progress Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/controls/menu/menu_controller.h" 5 #include "ui/views/controls/menu/menu_controller.h"
6 6
7 #if defined(OS_WIN) 7 #if defined(OS_WIN)
8 #include <windowsx.h> 8 #include <windowsx.h>
9 #endif 9 #endif
10 10
11 #include "base/i18n/case_conversion.h" 11 #include "base/i18n/case_conversion.h"
12 #include "base/i18n/rtl.h" 12 #include "base/i18n/rtl.h"
13 #include "base/run_loop.h"
14 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h" 14 #include "base/time/time.h"
16 #include "ui/aura/client/screen_position_client.h"
17 #include "ui/aura/env.h" 15 #include "ui/aura/env.h"
18 #include "ui/aura/window.h" 16 #include "ui/aura/window.h"
19 #include "ui/aura/window_event_dispatcher.h" 17 #include "ui/aura/window_event_dispatcher.h"
20 #include "ui/aura/window_tree_host.h" 18 #include "ui/aura/window_tree_host.h"
21 #include "ui/base/dragdrop/drag_utils.h" 19 #include "ui/base/dragdrop/drag_utils.h"
22 #include "ui/base/dragdrop/os_exchange_data.h" 20 #include "ui/base/dragdrop/os_exchange_data.h"
23 #include "ui/base/l10n/l10n_util.h" 21 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/events/event.h" 22 #include "ui/events/event.h"
25 #include "ui/events/event_utils.h" 23 #include "ui/events/event_utils.h"
26 #include "ui/events/platform/platform_event_source.h"
27 #include "ui/events/platform/scoped_event_dispatcher.h"
28 #include "ui/gfx/canvas.h" 24 #include "ui/gfx/canvas.h"
29 #include "ui/gfx/native_widget_types.h" 25 #include "ui/gfx/native_widget_types.h"
30 #include "ui/gfx/point.h" 26 #include "ui/gfx/point.h"
31 #include "ui/gfx/screen.h" 27 #include "ui/gfx/screen.h"
32 #include "ui/gfx/vector2d.h" 28 #include "ui/gfx/vector2d.h"
33 #include "ui/native_theme/native_theme.h" 29 #include "ui/native_theme/native_theme.h"
34 #include "ui/views/controls/button/menu_button.h" 30 #include "ui/views/controls/button/menu_button.h"
35 #include "ui/views/controls/menu/menu_config.h" 31 #include "ui/views/controls/menu/menu_config.h"
36 #include "ui/views/controls/menu/menu_controller_delegate.h" 32 #include "ui/views/controls/menu/menu_controller_delegate.h"
37 #include "ui/views/controls/menu/menu_host_root_view.h" 33 #include "ui/views/controls/menu/menu_host_root_view.h"
34 #include "ui/views/controls/menu/menu_message_loop.h"
38 #include "ui/views/controls/menu/menu_scroll_view_container.h" 35 #include "ui/views/controls/menu/menu_scroll_view_container.h"
39 #include "ui/views/controls/menu/submenu_view.h" 36 #include "ui/views/controls/menu/submenu_view.h"
40 #include "ui/views/drag_utils.h" 37 #include "ui/views/drag_utils.h"
41 #include "ui/views/focus/view_storage.h" 38 #include "ui/views/focus/view_storage.h"
42 #include "ui/views/mouse_constants.h" 39 #include "ui/views/mouse_constants.h"
43 #include "ui/views/view.h" 40 #include "ui/views/view.h"
44 #include "ui/views/view_constants.h" 41 #include "ui/views/view_constants.h"
45 #include "ui/views/views_delegate.h" 42 #include "ui/views/views_delegate.h"
46 #include "ui/views/widget/root_view.h" 43 #include "ui/views/widget/root_view.h"
47 #include "ui/views/widget/tooltip_manager.h" 44 #include "ui/views/widget/tooltip_manager.h"
48 #include "ui/views/widget/widget.h" 45 #include "ui/views/widget/widget.h"
49 #include "ui/wm/public/activation_change_observer.h"
50 #include "ui/wm/public/activation_client.h"
51 #include "ui/wm/public/dispatcher_client.h"
52 #include "ui/wm/public/drag_drop_client.h"
53 46
54 #if defined(OS_WIN) 47 #if defined(OS_WIN)
55 #include "ui/base/win/internal_constants.h" 48 #include "ui/base/win/internal_constants.h"
56 #include "ui/views/controls/menu/menu_message_pump_dispatcher_win.h"
57 #include "ui/views/win/hwnd_util.h" 49 #include "ui/views/win/hwnd_util.h"
58 #else
59 #include "ui/views/controls/menu/menu_event_dispatcher_linux.h"
60 #endif 50 #endif
61 51
62 using aura::client::ScreenPositionClient;
63 using base::Time; 52 using base::Time;
64 using base::TimeDelta; 53 using base::TimeDelta;
65 using ui::OSExchangeData; 54 using ui::OSExchangeData;
66 55
67 // Period of the scroll timer (in milliseconds). 56 // Period of the scroll timer (in milliseconds).
68 static const int kScrollTimerMS = 30; 57 static const int kScrollTimerMS = 30;
69 58
70 // Amount of time from when the drop exits the menu and the menu is hidden. 59 // Amount of time from when the drop exits the menu and the menu is hidden.
71 static const int kCloseOnExitTime = 1200; 60 static const int kCloseOnExitTime = 1200;
72 61
(...skipping 27 matching lines...) Expand all
100 // Returns true if |menu| doesn't have a mnemonic and first character of the its 89 // Returns true if |menu| doesn't have a mnemonic and first character of the its
101 // title is |key|. 90 // title is |key|.
102 bool TitleMatchesMnemonic(MenuItemView* menu, base::char16 key) { 91 bool TitleMatchesMnemonic(MenuItemView* menu, base::char16 key) {
103 if (menu->GetMnemonic()) 92 if (menu->GetMnemonic())
104 return false; 93 return false;
105 94
106 base::string16 lower_title = base::i18n::ToLower(menu->title()); 95 base::string16 lower_title = base::i18n::ToLower(menu->title());
107 return !lower_title.empty() && lower_title[0] == key; 96 return !lower_title.empty() && lower_title[0] == key;
108 } 97 }
109 98
110 aura::Window* GetOwnerRootWindow(views::Widget* owner) {
111 return owner ? owner->GetNativeWindow()->GetRootWindow() : NULL;
112 }
113
114 // ActivationChangeObserverImpl is used to observe activation changes and close
115 // the menu. Additionally it listens for the root window to be destroyed and
116 // cancel the menu as well.
117 class ActivationChangeObserverImpl
118 : public aura::client::ActivationChangeObserver,
119 public aura::WindowObserver,
120 public ui::EventHandler {
121 public:
122 ActivationChangeObserverImpl(MenuController* controller, aura::Window* root)
123 : controller_(controller),
124 root_(root) {
125 aura::client::GetActivationClient(root_)->AddObserver(this);
126 root_->AddObserver(this);
127 root_->AddPreTargetHandler(this);
128 }
129
130 virtual ~ActivationChangeObserverImpl() {
131 Cleanup();
132 }
133
134 // aura::client::ActivationChangeObserver:
135 virtual void OnWindowActivated(aura::Window* gained_active,
136 aura::Window* lost_active) OVERRIDE {
137 if (!controller_->drag_in_progress())
138 controller_->CancelAll();
139 }
140
141 // aura::WindowObserver:
142 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
143 Cleanup();
144 }
145
146 // ui::EventHandler:
147 virtual void OnCancelMode(ui::CancelModeEvent* event) OVERRIDE {
148 controller_->CancelAll();
149 }
150
151 private:
152 void Cleanup() {
153 if (!root_)
154 return;
155 // The ActivationClient may have been destroyed by the time we get here.
156 aura::client::ActivationClient* client =
157 aura::client::GetActivationClient(root_);
158 if (client)
159 client->RemoveObserver(this);
160 root_->RemovePreTargetHandler(this);
161 root_->RemoveObserver(this);
162 root_ = NULL;
163 }
164
165 MenuController* controller_;
166 aura::Window* root_;
167
168 DISALLOW_COPY_AND_ASSIGN(ActivationChangeObserverImpl);
169 };
170
171 } // namespace 99 } // namespace
172 100
173 // Returns the first descendant of |view| that is hot tracked. 101 // Returns the first descendant of |view| that is hot tracked.
174 static CustomButton* GetFirstHotTrackedView(View* view) { 102 static CustomButton* GetFirstHotTrackedView(View* view) {
175 if (!view) 103 if (!view)
176 return NULL; 104 return NULL;
177 CustomButton* button = CustomButton::AsCustomButton(view); 105 CustomButton* button = CustomButton::AsCustomButton(view);
178 if (button) { 106 if (button) {
179 if (button->IsHotTracked()) 107 if (button->IsHotTracked())
180 return button; 108 return button;
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 // Make sure Chrome doesn't attempt to shut down while the menu is showing. 364 // Make sure Chrome doesn't attempt to shut down while the menu is showing.
437 if (ViewsDelegate::views_delegate) 365 if (ViewsDelegate::views_delegate)
438 ViewsDelegate::views_delegate->AddRef(); 366 ViewsDelegate::views_delegate->AddRef();
439 367
440 // We need to turn on nestable tasks as in some situations (pressing alt-f for 368 // We need to turn on nestable tasks as in some situations (pressing alt-f for
441 // one) the menus are run from a task. If we don't do this and are invoked 369 // one) the menus are run from a task. If we don't do this and are invoked
442 // from a task none of the tasks we schedule are processed and the menu 370 // from a task none of the tasks we schedule are processed and the menu
443 // appears totally broken. 371 // appears totally broken.
444 message_loop_depth_++; 372 message_loop_depth_++;
445 DCHECK_LE(message_loop_depth_, 2); 373 DCHECK_LE(message_loop_depth_, 2);
446 RunMessageLoop(nested_menu); 374 message_loop_->Run(this, nested_menu);
447 message_loop_depth_--; 375 message_loop_depth_--;
448 376
449 if (ViewsDelegate::views_delegate) 377 if (ViewsDelegate::views_delegate)
450 ViewsDelegate::views_delegate->ReleaseRef(); 378 ViewsDelegate::views_delegate->ReleaseRef();
451 379
452 // Close any open menus. 380 // Close any open menus.
453 SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT); 381 SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
454 382
455 #if defined(OS_WIN) 383 #if defined(OS_WIN)
456 // On Windows, if we select the menu item by touch and if the window at the 384 // On Windows, if we select the menu item by touch and if the window at the
(...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after
1165 MenuController::~MenuController() { 1093 MenuController::~MenuController() {
1166 DCHECK(!showing_); 1094 DCHECK(!showing_);
1167 if (owner_) 1095 if (owner_)
1168 owner_->RemoveObserver(this); 1096 owner_->RemoveObserver(this);
1169 if (active_instance_ == this) 1097 if (active_instance_ == this)
1170 active_instance_ = NULL; 1098 active_instance_ = NULL;
1171 StopShowTimer(); 1099 StopShowTimer();
1172 StopCancelAllTimer(); 1100 StopCancelAllTimer();
1173 } 1101 }
1174 1102
1175 #if defined(OS_WIN)
1176 void MenuController::RunMessageLoop(bool nested_menu) {
1177 internal::MenuMessagePumpDispatcher nested_dispatcher(this);
1178
1179 // |owner_| may be NULL.
1180 aura::Window* root = GetOwnerRootWindow(owner_);
1181 if (root) {
1182 scoped_ptr<ActivationChangeObserverImpl> observer;
1183 if (!nested_menu)
1184 observer.reset(new ActivationChangeObserverImpl(this, root));
1185 aura::client::GetDispatcherClient(root)
1186 ->RunWithDispatcher(&nested_dispatcher);
1187 } else {
1188 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
1189 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
1190 base::RunLoop run_loop(&nested_dispatcher);
1191 run_loop.Run();
1192 }
1193 }
1194 #else
1195 void MenuController::RunMessageLoop(bool nested_menu) {
1196 internal::MenuEventDispatcher event_dispatcher(this);
1197 scoped_ptr<ui::ScopedEventDispatcher> old_dispatcher =
1198 nested_dispatcher_.Pass();
1199 if (ui::PlatformEventSource::GetInstance()) {
1200 nested_dispatcher_ =
1201 ui::PlatformEventSource::GetInstance()->OverrideDispatcher(
1202 &event_dispatcher);
1203 }
1204 // |owner_| may be NULL.
1205 aura::Window* root = GetOwnerRootWindow(owner_);
1206 if (root) {
1207 scoped_ptr<ActivationChangeObserverImpl> observer;
1208 if (!nested_menu)
1209 observer.reset(new ActivationChangeObserverImpl(this, root));
1210 aura::client::GetDispatcherClient(root)->RunWithDispatcher(NULL);
1211 } else {
1212 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
1213 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
1214 base::RunLoop run_loop;
1215 run_loop.Run();
1216 }
1217 nested_dispatcher_ = old_dispatcher.Pass();
1218 }
1219 #endif
1220
1221 MenuController::SendAcceleratorResultType 1103 MenuController::SendAcceleratorResultType
1222 MenuController::SendAcceleratorToHotTrackedView() { 1104 MenuController::SendAcceleratorToHotTrackedView() {
1223 CustomButton* hot_view = GetFirstHotTrackedView(pending_state_.item); 1105 CustomButton* hot_view = GetFirstHotTrackedView(pending_state_.item);
1224 if (!hot_view) 1106 if (!hot_view)
1225 return ACCELERATOR_NOT_PROCESSED; 1107 return ACCELERATOR_NOT_PROCESSED;
1226 1108
1227 ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE); 1109 ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE);
1228 hot_view->AcceleratorPressed(accelerator); 1110 hot_view->AcceleratorPressed(accelerator);
1229 CustomButton* button = static_cast<CustomButton*>(hot_view); 1111 CustomButton* button = static_cast<CustomButton*>(hot_view);
1230 button->SetHotTracked(true); 1112 button->SetHotTracked(true);
(...skipping 991 matching lines...) Expand 10 before | Expand all | Expand 10 after
2222 WPARAM target = client_area ? event.native_event().wParam : nc_hit_result; 2104 WPARAM target = client_area ? event.native_event().wParam : nc_hit_result;
2223 LPARAM window_coords = MAKELPARAM(window_x, window_y); 2105 LPARAM window_coords = MAKELPARAM(window_x, window_y);
2224 PostMessage(target_window, event_type, target, window_coords); 2106 PostMessage(target_window, event_type, target, window_coords);
2225 return; 2107 return;
2226 } 2108 }
2227 #endif 2109 #endif
2228 // Non-Windows Aura or |window| is in metro mode. 2110 // Non-Windows Aura or |window| is in metro mode.
2229 if (!window) 2111 if (!window)
2230 return; 2112 return;
2231 2113
2232 aura::Window* root = window->GetRootWindow(); 2114 message_loop_->RepostEvent(event);
2233 ScreenPositionClient* spc = aura::client::GetScreenPositionClient(root);
2234 if (!spc)
2235 return;
2236
2237 gfx::Point root_loc(screen_loc);
2238 spc->ConvertPointFromScreen(root, &root_loc);
2239
2240 ui::MouseEvent clone(static_cast<const ui::MouseEvent&>(event));
2241 clone.set_location(root_loc);
2242 clone.set_root_location(root_loc);
2243 root->GetHost()->dispatcher()->RepostEvent(clone);
2244 } 2115 }
2245 2116
2246 void MenuController::SetDropMenuItem( 2117 void MenuController::SetDropMenuItem(
2247 MenuItemView* new_target, 2118 MenuItemView* new_target,
2248 MenuDelegate::DropPosition new_position) { 2119 MenuDelegate::DropPosition new_position) {
2249 if (new_target == drop_target_ && new_position == drop_position_) 2120 if (new_target == drop_target_ && new_position == drop_position_)
2250 return; 2121 return;
2251 2122
2252 if (drop_target_) { 2123 if (drop_target_) {
2253 drop_target_->GetParentMenuItem()->GetSubmenu()->SetDropMenuItem( 2124 drop_target_->GetParentMenuItem()->GetSubmenu()->SetDropMenuItem(
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
2368 exit_type_ = type; 2239 exit_type_ = type;
2369 // Exit nested message loops as soon as possible. We do this as 2240 // Exit nested message loops as soon as possible. We do this as
2370 // MessagePumpDispatcher is only invoked before native events, which means 2241 // MessagePumpDispatcher is only invoked before native events, which means
2371 // its entirely possible for a Widget::CloseNow() task to be processed before 2242 // its entirely possible for a Widget::CloseNow() task to be processed before
2372 // the next native message. We quite the nested message loop as soon as 2243 // the next native message. We quite the nested message loop as soon as
2373 // possible to avoid having deleted views classes (such as widgets and 2244 // possible to avoid having deleted views classes (such as widgets and
2374 // rootviews) on the stack when the nested message loop stops. 2245 // rootviews) on the stack when the nested message loop stops.
2375 // 2246 //
2376 // It's safe to invoke QuitNestedMessageLoop() multiple times, it only effects 2247 // It's safe to invoke QuitNestedMessageLoop() multiple times, it only effects
2377 // the current loop. 2248 // the current loop.
2378 bool quit_now = ShouldQuitNow() && exit_type_ != EXIT_NONE && 2249 bool quit_now = message_loop_->ShouldQuitNow() && exit_type_ != EXIT_NONE &&
2379 message_loop_depth_; 2250 message_loop_depth_;
2380 2251
2381 if (quit_now) { 2252 if (quit_now)
2382 if (owner_) { 2253 message_loop_->QuitNow();
2383 aura::Window* root = owner_->GetNativeWindow()->GetRootWindow();
2384 aura::client::GetDispatcherClient(root)->QuitNestedMessageLoop();
2385 } else {
2386 base::MessageLoop::current()->QuitNow();
2387 }
2388 // Restore the previous dispatcher.
2389 nested_dispatcher_.reset();
2390 }
2391 }
2392
2393 bool MenuController::ShouldQuitNow() const {
2394 aura::Window* root = GetOwnerRootWindow(owner_);
2395 return !aura::client::GetDragDropClient(root) ||
2396 !aura::client::GetDragDropClient(root)->IsDragDropInProgress();
2397 } 2254 }
2398 2255
2399 void MenuController::HandleMouseLocation(SubmenuView* source, 2256 void MenuController::HandleMouseLocation(SubmenuView* source,
2400 const gfx::Point& mouse_location) { 2257 const gfx::Point& mouse_location) {
2401 if (showing_submenu_) 2258 if (showing_submenu_)
2402 return; 2259 return;
2403 2260
2404 // Ignore mouse events if we're closing the menu. 2261 // Ignore mouse events if we're closing the menu.
2405 if (exit_type_ != EXIT_NONE) 2262 if (exit_type_ != EXIT_NONE)
2406 return; 2263 return;
(...skipping 15 matching lines...) Expand all
2422 (!pending_state_.item->HasSubmenu() || 2279 (!pending_state_.item->HasSubmenu() ||
2423 !pending_state_.item->GetSubmenu()->IsShowing())) { 2280 !pending_state_.item->GetSubmenu()->IsShowing())) {
2424 // On exit if the user hasn't selected an item with a submenu, move the 2281 // On exit if the user hasn't selected an item with a submenu, move the
2425 // selection back to the parent menu item. 2282 // selection back to the parent menu item.
2426 SetSelection(pending_state_.item->GetParentMenuItem(), 2283 SetSelection(pending_state_.item->GetParentMenuItem(),
2427 SELECTION_OPEN_SUBMENU); 2284 SELECTION_OPEN_SUBMENU);
2428 } 2285 }
2429 } 2286 }
2430 2287
2431 gfx::Screen* MenuController::GetScreen() { 2288 gfx::Screen* MenuController::GetScreen() {
2432 aura::Window* root = GetOwnerRootWindow(owner_); 2289 Widget* root = owner_->GetTopLevelWidget();
2433 return root ? gfx::Screen::GetScreenFor(root) 2290 return root ? gfx::Screen::GetScreenFor(root->GetNativeView())
2434 : gfx::Screen::GetNativeScreen(); 2291 : gfx::Screen::GetNativeScreen();
2435 } 2292 }
2436 2293
2437 } // namespace views 2294 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698