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

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

Issue 2772863002: Delete MenuController Nested Message Loop (Closed)
Patch Set: remove another async flag Created 3 years, 9 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
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 #include "base/i18n/case_conversion.h" 7 #include "base/i18n/case_conversion.h"
8 #include "base/i18n/rtl.h" 8 #include "base/i18n/rtl.h"
9 #include "base/macros.h" 9 #include "base/macros.h"
10 #include "base/strings/utf_string_conversions.h" 10 #include "base/strings/utf_string_conversions.h"
11 #include "base/time/time.h" 11 #include "base/time/time.h"
12 #include "build/build_config.h" 12 #include "build/build_config.h"
13 #include "ui/base/dragdrop/drag_utils.h" 13 #include "ui/base/dragdrop/drag_utils.h"
14 #include "ui/base/dragdrop/os_exchange_data.h" 14 #include "ui/base/dragdrop/os_exchange_data.h"
15 #include "ui/display/screen.h" 15 #include "ui/display/screen.h"
16 #include "ui/events/event.h" 16 #include "ui/events/event.h"
17 #include "ui/events/event_utils.h" 17 #include "ui/events/event_utils.h"
18 #include "ui/gfx/canvas.h" 18 #include "ui/gfx/canvas.h"
19 #include "ui/gfx/geometry/point.h" 19 #include "ui/gfx/geometry/point.h"
20 #include "ui/gfx/geometry/vector2d.h" 20 #include "ui/gfx/geometry/vector2d.h"
21 #include "ui/gfx/native_widget_types.h" 21 #include "ui/gfx/native_widget_types.h"
22 #include "ui/native_theme/native_theme.h" 22 #include "ui/native_theme/native_theme.h"
23 #include "ui/views/controls/button/menu_button.h" 23 #include "ui/views/controls/button/menu_button.h"
24 #include "ui/views/controls/menu/menu_config.h" 24 #include "ui/views/controls/menu/menu_config.h"
25 #include "ui/views/controls/menu/menu_controller_delegate.h" 25 #include "ui/views/controls/menu/menu_controller_delegate.h"
26 #include "ui/views/controls/menu/menu_host_root_view.h" 26 #include "ui/views/controls/menu/menu_host_root_view.h"
27 #include "ui/views/controls/menu/menu_item_view.h" 27 #include "ui/views/controls/menu/menu_item_view.h"
28 #include "ui/views/controls/menu/menu_message_loop.h"
29 #include "ui/views/controls/menu/menu_scroll_view_container.h" 28 #include "ui/views/controls/menu/menu_scroll_view_container.h"
30 #include "ui/views/controls/menu/submenu_view.h" 29 #include "ui/views/controls/menu/submenu_view.h"
31 #include "ui/views/drag_utils.h" 30 #include "ui/views/drag_utils.h"
32 #include "ui/views/focus/view_storage.h" 31 #include "ui/views/focus/view_storage.h"
33 #include "ui/views/mouse_constants.h" 32 #include "ui/views/mouse_constants.h"
34 #include "ui/views/view.h" 33 #include "ui/views/view.h"
35 #include "ui/views/view_constants.h" 34 #include "ui/views/view_constants.h"
36 #include "ui/views/views_delegate.h" 35 #include "ui/views/views_delegate.h"
37 #include "ui/views/widget/root_view.h" 36 #include "ui/views/widget/root_view.h"
38 #include "ui/views/widget/tooltip_manager.h" 37 #include "ui/views/widget/tooltip_manager.h"
39 #include "ui/views/widget/widget.h" 38 #include "ui/views/widget/widget.h"
40 39
41 #if defined(OS_WIN) 40 #if defined(OS_WIN)
42 #include "ui/aura/window_tree_host.h" 41 #include "ui/aura/window_tree_host.h"
43 #include "ui/base/win/internal_constants.h" 42 #include "ui/base/win/internal_constants.h"
44 #include "ui/display/win/screen_win.h" 43 #include "ui/display/win/screen_win.h"
45 #include "ui/views/win/hwnd_util.h" 44 #include "ui/views/win/hwnd_util.h"
46 #endif 45 #endif
47 46
48 #if defined(USE_AURA) 47 #if defined(USE_AURA)
48 #include "ui/aura/client/screen_position_client.h"
49 #include "ui/aura/window.h"
50 #include "ui/aura/window_event_dispatcher.h"
51 #include "ui/aura/window_tree_host.h"
49 #include "ui/views/controls/menu/menu_pre_target_handler.h" 52 #include "ui/views/controls/menu/menu_pre_target_handler.h"
50 #endif 53 #endif
51 54
52 using base::Time; 55 using base::Time;
53 using base::TimeDelta; 56 using base::TimeDelta;
54 using ui::OSExchangeData; 57 using ui::OSExchangeData;
55 58
56 namespace views { 59 namespace views {
57 60
58 namespace { 61 namespace {
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 WPARAM target = client_area ? event->native_event().wParam : nc_hit_result; 246 WPARAM target = client_area ? event->native_event().wParam : nc_hit_result;
244 LPARAM window_coords = MAKELPARAM(window_x, window_y); 247 LPARAM window_coords = MAKELPARAM(window_x, window_y);
245 PostMessage(target_window, event_type, target, window_coords); 248 PostMessage(target_window, event_type, target, window_coords);
246 return; 249 return;
247 } 250 }
248 #endif 251 #endif
249 // Non Aura window. 252 // Non Aura window.
250 if (!window) 253 if (!window)
251 return; 254 return;
252 255
253 MenuMessageLoop::RepostEventToWindow(event, window, screen_loc); 256 #if defined(USE_AURA)
257 aura::Window* root = window->GetRootWindow();
258 aura::client::ScreenPositionClient* spc =
259 aura::client::GetScreenPositionClient(root);
260 if (!spc)
261 return;
262
263 gfx::Point root_loc(screen_loc);
264 spc->ConvertPointFromScreen(root, &root_loc);
265
266 std::unique_ptr<ui::Event> clone = ui::Event::Clone(*event);
267 std::unique_ptr<ui::LocatedEvent> located_event(
268 static_cast<ui::LocatedEvent*>(clone.release()));
269 located_event->set_location(root_loc);
270 located_event->set_root_location(root_loc);
271
272 root->GetHost()->dispatcher()->RepostEvent(located_event.get());
273 #endif // defined(USE_AURA)
254 } 274 }
255 #endif // defined(OS_WIN) || defined(OS_CHROMEOS) 275 #endif // defined(OS_WIN) || defined(OS_CHROMEOS)
256 276
257 } // namespace 277 } // namespace
258 278
259 // MenuScrollTask -------------------------------------------------------------- 279 // MenuScrollTask --------------------------------------------------------------
260 280
261 // MenuScrollTask is used when the SubmenuView does not all fit on screen and 281 // MenuScrollTask is used when the SubmenuView does not all fit on screen and
262 // the mouse is over the scroll up/down buttons. MenuScrollTask schedules 282 // the mouse is over the scroll up/down buttons. MenuScrollTask schedules
263 // itself with a RepeatingTimer. When Run is invoked MenuScrollTask scrolls 283 // itself with a RepeatingTimer. When Run is invoked MenuScrollTask scrolls
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
463 return NULL; 483 return NULL;
464 } 484 }
465 485
466 if (button) 486 if (button)
467 pressed_lock_.reset(new MenuButton::PressedLock(button)); 487 pressed_lock_.reset(new MenuButton::PressedLock(button));
468 488
469 // Make sure Chrome doesn't attempt to shut down while the menu is showing. 489 // Make sure Chrome doesn't attempt to shut down while the menu is showing.
470 if (ViewsDelegate::GetInstance()) 490 if (ViewsDelegate::GetInstance())
471 ViewsDelegate::GetInstance()->AddRef(); 491 ViewsDelegate::GetInstance()->AddRef();
472 492
473 if (async_run_) 493 return nullptr;
474 return nullptr;
475
476 // We need to turn on nestable tasks as in some situations (pressing alt-f for
477 // one) the menus are run from a task. If we don't do this and are invoked
478 // from a task none of the tasks we schedule are processed and the menu
479 // appears totally broken.
480 message_loop_depth_++;
481 DCHECK_LE(message_loop_depth_, 2);
482 RunMessageLoop();
483 message_loop_depth_--;
484
485 if (ViewsDelegate::GetInstance())
486 ViewsDelegate::GetInstance()->ReleaseRef();
487
488 if (result_event_flags)
489 *result_event_flags = accept_event_flags_;
490
491 // The nested message loop could have been killed externally. Check to see if
492 // there are nested asynchronous menus to shutdown.
493 if (async_run_ && delegate_stack_.size() > 1)
494 ExitAsyncRun();
495
496 return ExitMenuRun();
497 } 494 }
498 495
499 void MenuController::Cancel(ExitType type) { 496 void MenuController::Cancel(ExitType type) {
500 // If the menu has already been destroyed, no further cancellation is 497 // If the menu has already been destroyed, no further cancellation is
501 // needed. We especially don't want to set the |exit_type_| to a lesser 498 // needed. We especially don't want to set the |exit_type_| to a lesser
502 // value. 499 // value.
503 if (exit_type_ == EXIT_DESTROYED || exit_type_ == type) 500 if (exit_type_ == EXIT_DESTROYED || exit_type_ == type)
504 return; 501 return;
505 502
506 if (!showing_) { 503 if (!showing_) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 // On Windows and Linux the destruction of this menu's Widget leads to the 538 // On Windows and Linux the destruction of this menu's Widget leads to the
542 // teardown of the platform specific drag-and-drop Widget. Do not shutdown 539 // teardown of the platform specific drag-and-drop Widget. Do not shutdown
543 // while dragging, leave the Widget hidden until drag-and-drop has completed, 540 // while dragging, leave the Widget hidden until drag-and-drop has completed,
544 // at which point all menus will be destroyed. 541 // at which point all menus will be destroyed.
545 if (!drag_in_progress_) 542 if (!drag_in_progress_)
546 ExitAsyncRun(); 543 ExitAsyncRun();
547 } 544 }
548 545
549 void MenuController::AddNestedDelegate( 546 void MenuController::AddNestedDelegate(
550 internal::MenuControllerDelegate* delegate) { 547 internal::MenuControllerDelegate* delegate) {
551 delegate_stack_.push_back(std::make_pair(delegate, async_run_)); 548 delegate_stack_.push_back(delegate);
552 delegate_ = delegate; 549 delegate_ = delegate;
553 } 550 }
554 551
555 void MenuController::SetAsyncRun(bool is_async) {
556 delegate_stack_.back().second = is_async;
557 async_run_ = is_async;
558 }
559
560 bool MenuController::OnMousePressed(SubmenuView* source, 552 bool MenuController::OnMousePressed(SubmenuView* source,
561 const ui::MouseEvent& event) { 553 const ui::MouseEvent& event) {
562 // We should either have no current_mouse_event_target_, or should have a 554 // We should either have no current_mouse_event_target_, or should have a
563 // pressed state stored. 555 // pressed state stored.
564 DCHECK(!current_mouse_event_target_ || current_mouse_pressed_state_); 556 DCHECK(!current_mouse_event_target_ || current_mouse_pressed_state_);
565 557
566 // Find the root view to check. If any buttons were previously pressed, this 558 // Find the root view to check. If any buttons were previously pressed, this
567 // is the same root view we've been forwarding to. Otherwise, it's the root 559 // is the same root view we've been forwarding to. Otherwise, it's the root
568 // view of the target. 560 // view of the target.
569 MenuHostRootView* forward_to_root = 561 MenuHostRootView* forward_to_root =
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after
1046 // We may have been canceled during the drag. If so we still need to fully 1038 // We may have been canceled during the drag. If so we still need to fully
1047 // shutdown. 1039 // shutdown.
1048 ExitAsyncRun(); 1040 ExitAsyncRun();
1049 } 1041 }
1050 } 1042 }
1051 } 1043 }
1052 1044
1053 ui::PostDispatchAction MenuController::OnWillDispatchKeyEvent( 1045 ui::PostDispatchAction MenuController::OnWillDispatchKeyEvent(
1054 ui::KeyEvent* event) { 1046 ui::KeyEvent* event) {
1055 if (exit_type() == EXIT_ALL || exit_type() == EXIT_DESTROYED) { 1047 if (exit_type() == EXIT_ALL || exit_type() == EXIT_DESTROYED) {
1056 // If the event has arrived after the menu's exit type had changed but 1048 // If the event has arrived after the menu's exit type has changed but
1057 // before its message loop terminated, the event will continue its normal 1049 // before its Widgets have been destroyed, the event will continue its
1058 // propagation for the following reason: 1050 // normal propagation for the following reason:
1059 // If the user accepts a menu item in a nested menu, the menu item action is 1051 // If the user accepts a menu item in a nested menu, and the menu item
1060 // run after the base::RunLoop for the innermost menu has quit but before 1052 // action starts a base::RunLoop; IDC_BOOKMARK_BAR_OPEN_ALL sometimes opens
1061 // the base::RunLoop for the outermost menu has quit. If the menu item 1053 // a modal dialog. The modal dialog starts a base::RunLoop and keeps the
1062 // action starts a base::RunLoop, the outermost menu's base::RunLoop will 1054 // base::RunLoop running for the duration of its lifetime.
1063 // not quit till the action's base::RunLoop ends. IDC_BOOKMARK_BAR_OPEN_ALL
1064 // sometimes opens a modal dialog. The modal dialog starts a base::RunLoop
1065 // and keeps the base::RunLoop running for the duration of its lifetime.
1066 TerminateNestedMessageLoopIfNecessary();
1067 return ui::POST_DISPATCH_PERFORM_DEFAULT; 1055 return ui::POST_DISPATCH_PERFORM_DEFAULT;
1068 } 1056 }
1069 1057
1070 event->StopPropagation(); 1058 event->StopPropagation();
1071 1059
1072 if (event->type() == ui::ET_KEY_PRESSED) { 1060 if (event->type() == ui::ET_KEY_PRESSED) {
1073 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 1061 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
1074 OnKeyDown(event->key_code()); 1062 OnKeyDown(event->key_code());
1075 // Key events can lead to this being deleted. 1063 // Key events can lead to this being deleted.
1076 if (!this_ref) 1064 if (!this_ref)
1077 return ui::POST_DISPATCH_NONE; 1065 return ui::POST_DISPATCH_NONE;
1078 1066
1079 // Do not check mnemonics if the Alt or Ctrl modifiers are pressed. For 1067 // Do not check mnemonics if the Alt or Ctrl modifiers are pressed. For
1080 // example Ctrl+<T> is an accelerator, but <T> only is a mnemonic. 1068 // example Ctrl+<T> is an accelerator, but <T> only is a mnemonic.
1081 const int kKeyFlagsMask = ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN; 1069 const int kKeyFlagsMask = ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN;
1082 const int flags = event->flags(); 1070 const int flags = event->flags();
1083 if (exit_type() == EXIT_NONE && (flags & kKeyFlagsMask) == 0) { 1071 if (exit_type() == EXIT_NONE && (flags & kKeyFlagsMask) == 0) {
1084 base::char16 c = event->GetCharacter(); 1072 base::char16 c = event->GetCharacter();
1085 SelectByChar(c); 1073 SelectByChar(c);
1086 // SelectByChar can lead to this being deleted. 1074 // SelectByChar can lead to this being deleted.
1087 if (!this_ref) 1075 if (!this_ref)
1088 return ui::POST_DISPATCH_NONE; 1076 return ui::POST_DISPATCH_NONE;
1089 } 1077 }
1090 } 1078 }
1091 1079
1092 if (!TerminateNestedMessageLoopIfNecessary()) { 1080 ui::Accelerator accelerator(*event);
1093 ui::Accelerator accelerator(*event); 1081 ViewsDelegate::ProcessMenuAcceleratorResult result =
1094 ViewsDelegate::ProcessMenuAcceleratorResult result = 1082 ViewsDelegate::GetInstance()->ProcessAcceleratorWhileMenuShowing(
1095 ViewsDelegate::GetInstance()->ProcessAcceleratorWhileMenuShowing( 1083 accelerator);
1096 accelerator); 1084 if (result == ViewsDelegate::ProcessMenuAcceleratorResult::CLOSE_MENU)
1097 if (result == ViewsDelegate::ProcessMenuAcceleratorResult::CLOSE_MENU) 1085 CancelAll();
1098 CancelAll();
1099 }
1100 return ui::POST_DISPATCH_NONE; 1086 return ui::POST_DISPATCH_NONE;
1101 } 1087 }
1102 1088
1103 void MenuController::UpdateSubmenuSelection(SubmenuView* submenu) { 1089 void MenuController::UpdateSubmenuSelection(SubmenuView* submenu) {
1104 if (submenu->IsShowing()) { 1090 if (submenu->IsShowing()) {
1105 gfx::Point point = display::Screen::GetScreen()->GetCursorScreenPoint(); 1091 gfx::Point point = display::Screen::GetScreen()->GetCursorScreenPoint();
1106 const SubmenuView* root_submenu = 1092 const SubmenuView* root_submenu =
1107 submenu->GetMenuItem()->GetRootMenuItem()->GetSubmenu(); 1093 submenu->GetMenuItem()->GetRootMenuItem()->GetSubmenu();
1108 View::ConvertPointFromScreen( 1094 View::ConvertPointFromScreen(
1109 root_submenu->GetWidget()->GetRootView(), &point); 1095 root_submenu->GetWidget()->GetRootView(), &point);
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
1260 drag_utils::SetDragImageOnDataObject(*canvas, 1246 drag_utils::SetDragImageOnDataObject(*canvas,
1261 press_loc.OffsetFromOrigin(), 1247 press_loc.OffsetFromOrigin(),
1262 &data); 1248 &data);
1263 StopScrolling(); 1249 StopScrolling();
1264 int drag_ops = item->GetDelegate()->GetDragOperations(item); 1250 int drag_ops = item->GetDelegate()->GetDragOperations(item);
1265 did_initiate_drag_ = true; 1251 did_initiate_drag_ = true;
1266 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 1252 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
1267 // TODO(varunjain): Properly determine and send DRAG_EVENT_SOURCE below. 1253 // TODO(varunjain): Properly determine and send DRAG_EVENT_SOURCE below.
1268 item->GetWidget()->RunShellDrag(NULL, data, widget_loc, drag_ops, 1254 item->GetWidget()->RunShellDrag(NULL, data, widget_loc, drag_ops,
1269 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE); 1255 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
1270 // MenuController may have been deleted if |async_run_| so check before 1256 // MenuController may have been deleted so check before accessing member
1271 // accessing member variables. 1257 // variables.
1272 if (this_ref) 1258 if (this_ref)
1273 did_initiate_drag_ = false; 1259 did_initiate_drag_ = false;
1274 } 1260 }
1275 1261
1276 void MenuController::OnKeyDown(ui::KeyboardCode key_code) { 1262 void MenuController::OnKeyDown(ui::KeyboardCode key_code) {
1277 // Do not process while performing drag-and-drop 1263 // Do not process while performing drag-and-drop
1278 if (!blocking_run_) 1264 if (!blocking_run_)
1279 return; 1265 return;
1280 1266
1281 switch (key_code) { 1267 switch (key_code) {
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
1395 owner_(NULL), 1381 owner_(NULL),
1396 possible_drag_(false), 1382 possible_drag_(false),
1397 drag_in_progress_(false), 1383 drag_in_progress_(false),
1398 did_initiate_drag_(false), 1384 did_initiate_drag_(false),
1399 valid_drop_coordinates_(false), 1385 valid_drop_coordinates_(false),
1400 last_drop_operation_(MenuDelegate::DROP_UNKNOWN), 1386 last_drop_operation_(MenuDelegate::DROP_UNKNOWN),
1401 showing_submenu_(false), 1387 showing_submenu_(false),
1402 active_mouse_view_id_(ViewStorage::GetInstance()->CreateStorageID()), 1388 active_mouse_view_id_(ViewStorage::GetInstance()->CreateStorageID()),
1403 hot_button_(nullptr), 1389 hot_button_(nullptr),
1404 delegate_(delegate), 1390 delegate_(delegate),
1405 message_loop_depth_(0),
1406 async_run_(false),
1407 is_combobox_(false), 1391 is_combobox_(false),
1408 item_selected_by_touch_(false), 1392 item_selected_by_touch_(false),
1409 current_mouse_event_target_(nullptr), 1393 current_mouse_event_target_(nullptr),
1410 current_mouse_pressed_state_(0), 1394 current_mouse_pressed_state_(0) {
1411 message_loop_(MenuMessageLoop::Create()) { 1395 delegate_stack_.push_back(delegate_);
1412 delegate_stack_.push_back(std::make_pair(delegate_, async_run_));
1413 active_instance_ = this; 1396 active_instance_ = this;
1414 } 1397 }
1415 1398
1416 MenuController::~MenuController() { 1399 MenuController::~MenuController() {
1417 DCHECK(!showing_); 1400 DCHECK(!showing_);
1418 if (owner_) 1401 if (owner_)
1419 owner_->RemoveObserver(this); 1402 owner_->RemoveObserver(this);
1420 if (active_instance_ == this) 1403 if (active_instance_ == this)
1421 active_instance_ = NULL; 1404 active_instance_ = NULL;
1422 StopShowTimer(); 1405 StopShowTimer();
1423 StopCancelAllTimer(); 1406 StopCancelAllTimer();
1424 } 1407 }
1425 1408
1426 void MenuController::RunMessageLoop() {
1427 message_loop_->Run();
1428 }
1429
1430 bool MenuController::SendAcceleratorToHotTrackedView() { 1409 bool MenuController::SendAcceleratorToHotTrackedView() {
1431 CustomButton* hot_view = GetFirstHotTrackedView(pending_state_.item); 1410 CustomButton* hot_view = GetFirstHotTrackedView(pending_state_.item);
1432 if (!hot_view) 1411 if (!hot_view)
1433 return false; 1412 return false;
1434 1413
1435 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 1414 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
1436 ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE); 1415 ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE);
1437 hot_view->AcceleratorPressed(accelerator); 1416 hot_view->AcceleratorPressed(accelerator);
1438 // An accelerator may have canceled the menu after activation. 1417 // An accelerator may have canceled the menu after activation.
1439 if (this_ref) { 1418 if (this_ref) {
(...skipping 956 matching lines...) Expand 10 before | Expand all | Expand 10 after
2396 gfx::NativeWindow window = nullptr; 2375 gfx::NativeWindow window = nullptr;
2397 if (native_view) { 2376 if (native_view) {
2398 display::Screen* screen = display::Screen::GetScreen(); 2377 display::Screen* screen = display::Screen::GetScreen();
2399 window = screen->GetWindowAtScreenPoint(screen_loc); 2378 window = screen->GetWindowAtScreenPoint(screen_loc);
2400 } 2379 }
2401 #endif 2380 #endif
2402 2381
2403 #if defined(OS_WIN) 2382 #if defined(OS_WIN)
2404 if (event->IsMouseEvent() || event->IsTouchEvent()) { 2383 if (event->IsMouseEvent() || event->IsTouchEvent()) {
2405 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 2384 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
2406 bool async_run = async_run_;
2407 if (state_.item) { 2385 if (state_.item) {
2408 state_.item->GetRootMenuItem()->GetSubmenu()->ReleaseCapture(); 2386 state_.item->GetRootMenuItem()->GetSubmenu()->ReleaseCapture();
2409 // We're going to close and we own the event capture. We need to repost 2387 // We're going to close and we own the event capture. We need to repost
2410 // the event, otherwise the window the user clicked on won't get the 2388 // the event, otherwise the window the user clicked on won't get the
2411 // event. 2389 // event.
2412 RepostEventImpl(event, screen_loc, native_view, window); 2390 RepostEventImpl(event, screen_loc, native_view, window);
2413 } else { 2391 } else {
2414 // We some times get an event after closing all the menus. Ignore it. Make 2392 // We some times get an event after closing all the menus. Ignore it. Make
2415 // sure the menu is in fact not visible. If the menu is visible, then 2393 // sure the menu is in fact not visible. If the menu is visible, then
2416 // we're in a bad state where we think the menu isn't visibile but it is. 2394 // we're in a bad state where we think the menu isn't visibile but it is.
2417 DCHECK(!source->GetWidget()->IsVisible()); 2395 DCHECK(!source->GetWidget()->IsVisible());
2418 } 2396 }
2419 2397
2420 // Reposting the event may have deleted this, if so exit. 2398 // Reposting the event may have deleted this, if so exit.
2421 if (!this_ref) { 2399 if (!this_ref)
2422 DCHECK(async_run);
2423 return; 2400 return;
2424 }
2425 } 2401 }
2426 #endif 2402 #endif
2427 2403
2428 // Determine target to see if a complete or partial close of the menu should 2404 // Determine target to see if a complete or partial close of the menu should
2429 // occur. 2405 // occur.
2430 ExitType exit_type = EXIT_ALL; 2406 ExitType exit_type = EXIT_ALL;
2431 if (!menu_stack_.empty()) { 2407 if (!menu_stack_.empty()) {
2432 // We're running nested menus. Only exit all if the mouse wasn't over one 2408 // We're running nested menus. Only exit all if the mouse wasn't over one
2433 // of the menus from the last run. 2409 // of the menus from the last run.
2434 MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu( 2410 MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu(
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
2562 else 2538 else
2563 ViewStorage::GetInstance()->RemoveView(active_mouse_view_id_); 2539 ViewStorage::GetInstance()->RemoveView(active_mouse_view_id_);
2564 } 2540 }
2565 2541
2566 View* MenuController::GetActiveMouseView() { 2542 View* MenuController::GetActiveMouseView() {
2567 return ViewStorage::GetInstance()->RetrieveView(active_mouse_view_id_); 2543 return ViewStorage::GetInstance()->RetrieveView(active_mouse_view_id_);
2568 } 2544 }
2569 2545
2570 void MenuController::SetExitType(ExitType type) { 2546 void MenuController::SetExitType(ExitType type) {
2571 exit_type_ = type; 2547 exit_type_ = type;
2572 // Exit nested message loops as soon as possible. We do this as
2573 // it's entirely possible for a Widget::CloseNow() task to be processed before
2574 // the next native message. We quite the nested message loop as soon as
2575 // possible to avoid having deleted views classes (such as widgets and
2576 // rootviews) on the stack when the nested message loop stops.
2577 TerminateNestedMessageLoopIfNecessary();
2578 }
2579
2580 bool MenuController::TerminateNestedMessageLoopIfNecessary() {
2581 // It is necessary to check both |async_run_| and |message_loop_depth_|
2582 // because the topmost async menu could be nested in a sync parent menu.
2583 bool quit_now = !async_run_ && exit_type_ != EXIT_NONE && message_loop_depth_;
2584 if (quit_now)
2585 message_loop_->QuitNow();
2586 return quit_now;
2587 } 2548 }
2588 2549
2589 void MenuController::ExitAsyncRun() { 2550 void MenuController::ExitAsyncRun() {
2590 if (!async_run_)
2591 return;
2592 bool nested = delegate_stack_.size() > 1; 2551 bool nested = delegate_stack_.size() > 1;
2593 // ExitMenuRun unwinds nested delegates 2552 // ExitMenuRun unwinds nested delegates
2594 internal::MenuControllerDelegate* delegate = delegate_; 2553 internal::MenuControllerDelegate* delegate = delegate_;
2595 // MenuController may have been deleted when releasing ViewsDelegate ref. 2554 // MenuController may have been deleted when releasing ViewsDelegate ref.
2596 // However as |delegate| can outlive this, it must still be notified of the 2555 // However as |delegate| can outlive this, it must still be notified of the
2597 // menu closing so that it can perform teardown. 2556 // menu closing so that it can perform teardown.
2598 int accept_event_flags = accept_event_flags_; 2557 int accept_event_flags = accept_event_flags_;
2599 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 2558 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
2600 MenuItemView* result = ExitMenuRun(); 2559 MenuItemView* result = ExitMenuRun();
2601 delegate->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE, 2560 delegate->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
2602 result, accept_event_flags); 2561 result, accept_event_flags);
2603 // |delegate| may have deleted this. 2562 // |delegate| may have deleted this.
2604 if (this_ref && nested && exit_type_ == EXIT_ALL) 2563 if (this_ref && nested && exit_type_ == EXIT_ALL)
2605 ExitAsyncRun(); 2564 ExitAsyncRun();
2606 } 2565 }
2607 2566
2608 MenuItemView* MenuController::ExitMenuRun() { 2567 MenuItemView* MenuController::ExitMenuRun() {
2609 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 2568 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
2610 2569
2611 // Release the lock which prevents Chrome from shutting down while the menu is 2570 // Release the lock which prevents Chrome from shutting down while the menu is
2612 // showing. 2571 // showing.
2613 if (async_run_ && ViewsDelegate::GetInstance()) 2572 if (ViewsDelegate::GetInstance())
2614 ViewsDelegate::GetInstance()->ReleaseRef(); 2573 ViewsDelegate::GetInstance()->ReleaseRef();
2615 2574
2616 // Releasing the lock can result in Chrome shutting down, deleting this. 2575 // Releasing the lock can result in Chrome shutting down, deleting this.
2617 if (!this_ref) 2576 if (!this_ref)
2618 return nullptr; 2577 return nullptr;
2619 2578
2620 // Close any open menus. 2579 // Close any open menus.
2621 SetSelection(nullptr, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT); 2580 SetSelection(nullptr, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
2622 2581
2623 #if defined(OS_WIN) 2582 #if defined(OS_WIN)
(...skipping 23 matching lines...) Expand all
2647 // We're running from within a menu, restore the previous state. 2606 // We're running from within a menu, restore the previous state.
2648 // The menus are already showing, so we don't have to show them. 2607 // The menus are already showing, so we don't have to show them.
2649 state_ = menu_stack_.back().first; 2608 state_ = menu_stack_.back().first;
2650 pending_state_ = menu_stack_.back().first; 2609 pending_state_ = menu_stack_.back().first;
2651 hot_button_ = state_.hot_button; 2610 hot_button_ = state_.hot_button;
2652 nested_pressed_lock = std::move(menu_stack_.back().second); 2611 nested_pressed_lock = std::move(menu_stack_.back().second);
2653 menu_stack_.pop_back(); 2612 menu_stack_.pop_back();
2654 // Even though the menus are nested, there may not be nested delegates. 2613 // Even though the menus are nested, there may not be nested delegates.
2655 if (delegate_stack_.size() > 1) { 2614 if (delegate_stack_.size() > 1) {
2656 delegate_stack_.pop_back(); 2615 delegate_stack_.pop_back();
2657 delegate_ = delegate_stack_.back().first; 2616 delegate_ = delegate_stack_.back();
2658 async_run_ = delegate_stack_.back().second;
2659 } 2617 }
2660 } else { 2618 } else {
2661 #if defined(USE_AURA) 2619 #if defined(USE_AURA)
2662 menu_pre_target_handler_.reset(); 2620 menu_pre_target_handler_.reset();
2663 #endif 2621 #endif
2664 2622
2665 showing_ = false; 2623 showing_ = false;
2666 did_capture_ = false; 2624 did_capture_ = false;
2667 } 2625 }
2668 2626
2669 MenuItemView* result = result_; 2627 MenuItemView* result = result_;
2670 // In case we're nested, reset |result_|. 2628 // In case we're nested, reset |result_|.
2671 result_ = nullptr; 2629 result_ = nullptr;
2672 2630
2673 if (exit_type_ == EXIT_OUTERMOST) { 2631 if (exit_type_ == EXIT_OUTERMOST) {
2674 SetExitType(EXIT_NONE); 2632 SetExitType(EXIT_NONE);
2675 } else { 2633 } else if (nested_menu && result) {
2676 if (nested_menu && result) { 2634 // We're nested and about to return a value. The caller might enter
2677 // We're nested and about to return a value. The caller might enter 2635 // another blocking loop. We need to make sure all menus are hidden
2678 // another blocking loop. We need to make sure all menus are hidden 2636 // before that happens otherwise the menus will stay on screen.
2679 // before that happens otherwise the menus will stay on screen. 2637 CloseAllNestedMenus();
2680 CloseAllNestedMenus(); 2638 SetSelection(nullptr, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
2681 SetSelection(nullptr, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
2682 2639
2683 // Set exit_all_, which makes sure all nested loops exit immediately. 2640 // Set exit_all_, which makes sure all nested loops exit immediately.
2684 if (exit_type_ != EXIT_DESTROYED) 2641 if (exit_type_ != EXIT_DESTROYED)
2685 SetExitType(EXIT_ALL); 2642 SetExitType(EXIT_ALL);
2686 } else {
2687 TerminateNestedMessageLoopIfNecessary();
2688 }
2689 } 2643 }
2690 2644
2691 // Reset our pressed lock and hot-tracked state to the previous state's, if 2645 // Reset our pressed lock and hot-tracked state to the previous state's, if
2692 // they were active. The lock handles the case if the button was destroyed. 2646 // they were active. The lock handles the case if the button was destroyed.
2693 pressed_lock_ = std::move(nested_pressed_lock); 2647 pressed_lock_ = std::move(nested_pressed_lock);
2694 if (hot_button_) 2648 if (hot_button_)
2695 hot_button_->SetHotTracked(true); 2649 hot_button_->SetHotTracked(true);
2696 2650
2697 return result; 2651 return result;
2698 } 2652 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
2752 if (hot_button_) 2706 if (hot_button_)
2753 hot_button_->SetHotTracked(false); 2707 hot_button_->SetHotTracked(false);
2754 hot_button_ = hot_button; 2708 hot_button_ = hot_button;
2755 if (hot_button) { 2709 if (hot_button) {
2756 hot_button->SetHotTracked(true); 2710 hot_button->SetHotTracked(true);
2757 hot_button->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); 2711 hot_button->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true);
2758 } 2712 }
2759 } 2713 }
2760 2714
2761 } // namespace views 2715 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/menu/menu_controller.h ('k') | ui/views/controls/menu/menu_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698