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

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

Issue 2779373002: Remove Nested Message Loop from MenuController (Closed)
Patch Set: unneeded runloop Created 3 years, 8 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 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 window_x = pt.x; 242 window_x = pt.x;
240 window_y = pt.y; 243 window_y = pt.y;
241 } 244 }
242 245
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
253 #if defined(USE_AURA)
250 if (!window) 254 if (!window)
251 return; 255 return;
252 256
253 MenuMessageLoop::RepostEventToWindow(event, window, screen_loc); 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 29 matching lines...) Expand all
536 // nested calls to Cancel. We want to reject these to prevent attempting a 533 // nested calls to Cancel. We want to reject these to prevent attempting a
537 // nested tear down of this and |delegate_|. 534 // nested tear down of this and |delegate_|.
538 if (type == EXIT_ALL) 535 if (type == EXIT_ALL)
539 showing_ = false; 536 showing_ = false;
540 537
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 ExitMenu();
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 468 matching lines...) Expand 10 before | Expand all | Expand 10 after
1038 // During a drag operation there are several ways in which this can be 1030 // During a drag operation there are several ways in which this can be
1039 // canceled and deleted. Verify that this is still active before closing 1031 // canceled and deleted. Verify that this is still active before closing
1040 // the widgets. 1032 // the widgets.
1041 if (GetActiveInstance() == this) { 1033 if (GetActiveInstance() == this) {
1042 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 1034 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
1043 CloseAllNestedMenus(); 1035 CloseAllNestedMenus();
1044 Cancel(EXIT_ALL); 1036 Cancel(EXIT_ALL);
1045 // The above may have deleted us. If not perform a full shutdown. 1037 // The above may have deleted us. If not perform a full shutdown.
1046 if (!this_ref) 1038 if (!this_ref)
1047 return; 1039 return;
1048 ExitAsyncRun(); 1040 ExitMenu();
1049 } 1041 }
1050 } else if (exit_type_ == EXIT_ALL) { 1042 } else if (exit_type_ == EXIT_ALL) {
1051 // We may have been canceled during the drag. If so we still need to fully 1043 // We may have been canceled during the drag. If so we still need to fully
1052 // shutdown. 1044 // shutdown.
1053 ExitAsyncRun(); 1045 ExitMenu();
1054 } 1046 }
1055 } 1047 }
1056 } 1048 }
1057 1049
1058 ui::PostDispatchAction MenuController::OnWillDispatchKeyEvent( 1050 ui::PostDispatchAction MenuController::OnWillDispatchKeyEvent(
1059 ui::KeyEvent* event) { 1051 ui::KeyEvent* event) {
1060 if (exit_type() == EXIT_ALL || exit_type() == EXIT_DESTROYED) { 1052 if (exit_type() == EXIT_ALL || exit_type() == EXIT_DESTROYED) {
1061 // If the event has arrived after the menu's exit type had changed but 1053 // If the event has arrived after the menu's exit type has changed but
1062 // before its message loop terminated, the event will continue its normal 1054 // before its Widgets have been destroyed, the event will continue its
1063 // propagation for the following reason: 1055 // normal propagation for the following reason:
1064 // If the user accepts a menu item in a nested menu, the menu item action is 1056 // If the user accepts a menu item in a nested menu, and the menu item
1065 // run after the base::RunLoop for the innermost menu has quit but before 1057 // action starts a base::RunLoop; IDC_BOOKMARK_BAR_OPEN_ALL sometimes opens
1066 // the base::RunLoop for the outermost menu has quit. If the menu item 1058 // a modal dialog. The modal dialog starts a base::RunLoop and keeps the
1067 // action starts a base::RunLoop, the outermost menu's base::RunLoop will 1059 // base::RunLoop running for the duration of its lifetime.
1068 // not quit till the action's base::RunLoop ends. IDC_BOOKMARK_BAR_OPEN_ALL
1069 // sometimes opens a modal dialog. The modal dialog starts a base::RunLoop
1070 // and keeps the base::RunLoop running for the duration of its lifetime.
1071 TerminateNestedMessageLoopIfNecessary();
1072 return ui::POST_DISPATCH_PERFORM_DEFAULT; 1060 return ui::POST_DISPATCH_PERFORM_DEFAULT;
1073 } 1061 }
1074 1062
1075 event->StopPropagation(); 1063 event->StopPropagation();
1076 1064
1077 if (event->type() == ui::ET_KEY_PRESSED) { 1065 if (event->type() == ui::ET_KEY_PRESSED) {
1078 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 1066 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
1079 OnKeyDown(event->key_code()); 1067 OnKeyDown(event->key_code());
1080 // Key events can lead to this being deleted. 1068 // Key events can lead to this being deleted.
1081 if (!this_ref) 1069 if (!this_ref)
1082 return ui::POST_DISPATCH_NONE; 1070 return ui::POST_DISPATCH_NONE;
1083 1071
1084 // Do not check mnemonics if the Alt or Ctrl modifiers are pressed. For 1072 // Do not check mnemonics if the Alt or Ctrl modifiers are pressed. For
1085 // example Ctrl+<T> is an accelerator, but <T> only is a mnemonic. 1073 // example Ctrl+<T> is an accelerator, but <T> only is a mnemonic.
1086 const int kKeyFlagsMask = ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN; 1074 const int kKeyFlagsMask = ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN;
1087 const int flags = event->flags(); 1075 const int flags = event->flags();
1088 if (exit_type() == EXIT_NONE && (flags & kKeyFlagsMask) == 0) { 1076 if (exit_type() == EXIT_NONE && (flags & kKeyFlagsMask) == 0) {
1089 base::char16 c = event->GetCharacter(); 1077 base::char16 c = event->GetCharacter();
1090 SelectByChar(c); 1078 SelectByChar(c);
1091 // SelectByChar can lead to this being deleted. 1079 // SelectByChar can lead to this being deleted.
1092 if (!this_ref) 1080 if (!this_ref)
1093 return ui::POST_DISPATCH_NONE; 1081 return ui::POST_DISPATCH_NONE;
1094 } 1082 }
1095 } 1083 }
1096 1084
1097 if (!TerminateNestedMessageLoopIfNecessary()) { 1085 ui::Accelerator accelerator(*event);
1098 ui::Accelerator accelerator(*event); 1086 ViewsDelegate::ProcessMenuAcceleratorResult result =
1099 ViewsDelegate::ProcessMenuAcceleratorResult result = 1087 ViewsDelegate::GetInstance()->ProcessAcceleratorWhileMenuShowing(
1100 ViewsDelegate::GetInstance()->ProcessAcceleratorWhileMenuShowing( 1088 accelerator);
1101 accelerator); 1089 if (result == ViewsDelegate::ProcessMenuAcceleratorResult::CLOSE_MENU)
1102 if (result == ViewsDelegate::ProcessMenuAcceleratorResult::CLOSE_MENU) 1090 CancelAll();
1103 CancelAll();
1104 }
1105 return ui::POST_DISPATCH_NONE; 1091 return ui::POST_DISPATCH_NONE;
1106 } 1092 }
1107 1093
1108 void MenuController::UpdateSubmenuSelection(SubmenuView* submenu) { 1094 void MenuController::UpdateSubmenuSelection(SubmenuView* submenu) {
1109 if (submenu->IsShowing()) { 1095 if (submenu->IsShowing()) {
1110 gfx::Point point = display::Screen::GetScreen()->GetCursorScreenPoint(); 1096 gfx::Point point = display::Screen::GetScreen()->GetCursorScreenPoint();
1111 const SubmenuView* root_submenu = 1097 const SubmenuView* root_submenu =
1112 submenu->GetMenuItem()->GetRootMenuItem()->GetSubmenu(); 1098 submenu->GetMenuItem()->GetRootMenuItem()->GetSubmenu();
1113 View::ConvertPointFromScreen( 1099 View::ConvertPointFromScreen(
1114 root_submenu->GetWidget()->GetRootView(), &point); 1100 root_submenu->GetWidget()->GetRootView(), &point);
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
1265 drag_utils::SetDragImageOnDataObject(*canvas, 1251 drag_utils::SetDragImageOnDataObject(*canvas,
1266 press_loc.OffsetFromOrigin(), 1252 press_loc.OffsetFromOrigin(),
1267 &data); 1253 &data);
1268 StopScrolling(); 1254 StopScrolling();
1269 int drag_ops = item->GetDelegate()->GetDragOperations(item); 1255 int drag_ops = item->GetDelegate()->GetDragOperations(item);
1270 did_initiate_drag_ = true; 1256 did_initiate_drag_ = true;
1271 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 1257 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
1272 // TODO(varunjain): Properly determine and send DRAG_EVENT_SOURCE below. 1258 // TODO(varunjain): Properly determine and send DRAG_EVENT_SOURCE below.
1273 item->GetWidget()->RunShellDrag(NULL, data, widget_loc, drag_ops, 1259 item->GetWidget()->RunShellDrag(NULL, data, widget_loc, drag_ops,
1274 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE); 1260 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
1275 // MenuController may have been deleted if |async_run_| so check before 1261 // MenuController may have been deleted so check before accessing member
1276 // accessing member variables. 1262 // variables.
1277 if (this_ref) 1263 if (this_ref)
1278 did_initiate_drag_ = false; 1264 did_initiate_drag_ = false;
1279 } 1265 }
1280 1266
1281 void MenuController::OnKeyDown(ui::KeyboardCode key_code) { 1267 void MenuController::OnKeyDown(ui::KeyboardCode key_code) {
1282 // Do not process while performing drag-and-drop 1268 // Do not process while performing drag-and-drop
1283 if (!blocking_run_) 1269 if (!blocking_run_)
1284 return; 1270 return;
1285 1271
1286 switch (key_code) { 1272 switch (key_code) {
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
1400 owner_(NULL), 1386 owner_(NULL),
1401 possible_drag_(false), 1387 possible_drag_(false),
1402 drag_in_progress_(false), 1388 drag_in_progress_(false),
1403 did_initiate_drag_(false), 1389 did_initiate_drag_(false),
1404 valid_drop_coordinates_(false), 1390 valid_drop_coordinates_(false),
1405 last_drop_operation_(MenuDelegate::DROP_UNKNOWN), 1391 last_drop_operation_(MenuDelegate::DROP_UNKNOWN),
1406 showing_submenu_(false), 1392 showing_submenu_(false),
1407 active_mouse_view_id_(ViewStorage::GetInstance()->CreateStorageID()), 1393 active_mouse_view_id_(ViewStorage::GetInstance()->CreateStorageID()),
1408 hot_button_(nullptr), 1394 hot_button_(nullptr),
1409 delegate_(delegate), 1395 delegate_(delegate),
1410 message_loop_depth_(0),
1411 async_run_(false),
1412 is_combobox_(false), 1396 is_combobox_(false),
1413 item_selected_by_touch_(false), 1397 item_selected_by_touch_(false),
1414 current_mouse_event_target_(nullptr), 1398 current_mouse_event_target_(nullptr),
1415 current_mouse_pressed_state_(0), 1399 current_mouse_pressed_state_(0) {
1416 message_loop_(MenuMessageLoop::Create()) { 1400 delegate_stack_.push_back(delegate_);
1417 delegate_stack_.push_back(std::make_pair(delegate_, async_run_));
1418 active_instance_ = this; 1401 active_instance_ = this;
1419 } 1402 }
1420 1403
1421 MenuController::~MenuController() { 1404 MenuController::~MenuController() {
1422 DCHECK(!showing_); 1405 DCHECK(!showing_);
1423 if (owner_) 1406 if (owner_)
1424 owner_->RemoveObserver(this); 1407 owner_->RemoveObserver(this);
1425 if (active_instance_ == this) 1408 if (active_instance_ == this)
1426 active_instance_ = NULL; 1409 active_instance_ = NULL;
1427 StopShowTimer(); 1410 StopShowTimer();
1428 StopCancelAllTimer(); 1411 StopCancelAllTimer();
1429 } 1412 }
1430 1413
1431 void MenuController::RunMessageLoop() {
1432 message_loop_->Run();
1433 }
1434
1435 bool MenuController::SendAcceleratorToHotTrackedView() { 1414 bool MenuController::SendAcceleratorToHotTrackedView() {
1436 CustomButton* hot_view = GetFirstHotTrackedView(pending_state_.item); 1415 CustomButton* hot_view = GetFirstHotTrackedView(pending_state_.item);
1437 if (!hot_view) 1416 if (!hot_view)
1438 return false; 1417 return false;
1439 1418
1440 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 1419 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
1441 ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE); 1420 ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE);
1442 hot_view->AcceleratorPressed(accelerator); 1421 hot_view->AcceleratorPressed(accelerator);
1443 // An accelerator may have canceled the menu after activation. 1422 // An accelerator may have canceled the menu after activation.
1444 if (this_ref) { 1423 if (this_ref) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1489 void MenuController::Accept(MenuItemView* item, int event_flags) { 1468 void MenuController::Accept(MenuItemView* item, int event_flags) {
1490 DCHECK(IsBlockingRun()); 1469 DCHECK(IsBlockingRun());
1491 result_ = item; 1470 result_ = item;
1492 if (item && !menu_stack_.empty() && 1471 if (item && !menu_stack_.empty() &&
1493 !item->GetDelegate()->ShouldCloseAllMenusOnExecute(item->GetCommand())) { 1472 !item->GetDelegate()->ShouldCloseAllMenusOnExecute(item->GetCommand())) {
1494 SetExitType(EXIT_OUTERMOST); 1473 SetExitType(EXIT_OUTERMOST);
1495 } else { 1474 } else {
1496 SetExitType(EXIT_ALL); 1475 SetExitType(EXIT_ALL);
1497 } 1476 }
1498 accept_event_flags_ = event_flags; 1477 accept_event_flags_ = event_flags;
1499 ExitAsyncRun(); 1478 ExitMenu();
1500 } 1479 }
1501 1480
1502 bool MenuController::ShowSiblingMenu(SubmenuView* source, 1481 bool MenuController::ShowSiblingMenu(SubmenuView* source,
1503 const gfx::Point& mouse_location) { 1482 const gfx::Point& mouse_location) {
1504 if (!menu_stack_.empty() || !pressed_lock_.get()) 1483 if (!menu_stack_.empty() || !pressed_lock_.get())
1505 return false; 1484 return false;
1506 1485
1507 View* source_view = source->GetScrollViewContainer(); 1486 View* source_view = source->GetScrollViewContainer();
1508 if (mouse_location.x() >= 0 && 1487 if (mouse_location.x() >= 0 &&
1509 mouse_location.x() < source_view->width() && 1488 mouse_location.x() < source_view->width() &&
(...skipping 891 matching lines...) Expand 10 before | Expand all | Expand 10 after
2401 gfx::NativeWindow window = nullptr; 2380 gfx::NativeWindow window = nullptr;
2402 if (native_view) { 2381 if (native_view) {
2403 display::Screen* screen = display::Screen::GetScreen(); 2382 display::Screen* screen = display::Screen::GetScreen();
2404 window = screen->GetWindowAtScreenPoint(screen_loc); 2383 window = screen->GetWindowAtScreenPoint(screen_loc);
2405 } 2384 }
2406 #endif 2385 #endif
2407 2386
2408 #if defined(OS_WIN) 2387 #if defined(OS_WIN)
2409 if (event->IsMouseEvent() || event->IsTouchEvent()) { 2388 if (event->IsMouseEvent() || event->IsTouchEvent()) {
2410 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 2389 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
2411 bool async_run = async_run_;
2412 if (state_.item) { 2390 if (state_.item) {
2413 state_.item->GetRootMenuItem()->GetSubmenu()->ReleaseCapture(); 2391 state_.item->GetRootMenuItem()->GetSubmenu()->ReleaseCapture();
2414 // We're going to close and we own the event capture. We need to repost 2392 // We're going to close and we own the event capture. We need to repost
2415 // the event, otherwise the window the user clicked on won't get the 2393 // the event, otherwise the window the user clicked on won't get the
2416 // event. 2394 // event.
2417 RepostEventImpl(event, screen_loc, native_view, window); 2395 RepostEventImpl(event, screen_loc, native_view, window);
2418 } else { 2396 } else {
2419 // We some times get an event after closing all the menus. Ignore it. Make 2397 // We some times get an event after closing all the menus. Ignore it. Make
2420 // sure the menu is in fact not visible. If the menu is visible, then 2398 // sure the menu is in fact not visible. If the menu is visible, then
2421 // we're in a bad state where we think the menu isn't visibile but it is. 2399 // we're in a bad state where we think the menu isn't visibile but it is.
2422 DCHECK(!source->GetWidget()->IsVisible()); 2400 DCHECK(!source->GetWidget()->IsVisible());
2423 } 2401 }
2424 2402
2425 // Reposting the event may have deleted this, if so exit. 2403 // Reposting the event may have deleted this, if so exit.
2426 if (!this_ref) { 2404 if (!this_ref)
2427 DCHECK(async_run);
2428 return; 2405 return;
2429 }
2430 } 2406 }
2431 #endif 2407 #endif
2432 2408
2433 // Determine target to see if a complete or partial close of the menu should 2409 // Determine target to see if a complete or partial close of the menu should
2434 // occur. 2410 // occur.
2435 ExitType exit_type = EXIT_ALL; 2411 ExitType exit_type = EXIT_ALL;
2436 if (!menu_stack_.empty()) { 2412 if (!menu_stack_.empty()) {
2437 // We're running nested menus. Only exit all if the mouse wasn't over one 2413 // We're running nested menus. Only exit all if the mouse wasn't over one
2438 // of the menus from the last run. 2414 // of the menus from the last run.
2439 MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu( 2415 MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu(
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
2567 else 2543 else
2568 ViewStorage::GetInstance()->RemoveView(active_mouse_view_id_); 2544 ViewStorage::GetInstance()->RemoveView(active_mouse_view_id_);
2569 } 2545 }
2570 2546
2571 View* MenuController::GetActiveMouseView() { 2547 View* MenuController::GetActiveMouseView() {
2572 return ViewStorage::GetInstance()->RetrieveView(active_mouse_view_id_); 2548 return ViewStorage::GetInstance()->RetrieveView(active_mouse_view_id_);
2573 } 2549 }
2574 2550
2575 void MenuController::SetExitType(ExitType type) { 2551 void MenuController::SetExitType(ExitType type) {
2576 exit_type_ = type; 2552 exit_type_ = type;
2577 // Exit nested message loops as soon as possible. We do this as
2578 // it's entirely possible for a Widget::CloseNow() task to be processed before
2579 // the next native message. We quite the nested message loop as soon as
2580 // possible to avoid having deleted views classes (such as widgets and
2581 // rootviews) on the stack when the nested message loop stops.
2582 TerminateNestedMessageLoopIfNecessary();
2583 } 2553 }
2584 2554
2585 bool MenuController::TerminateNestedMessageLoopIfNecessary() { 2555 void MenuController::ExitMenu() {
2586 // It is necessary to check both |async_run_| and |message_loop_depth_|
2587 // because the topmost async menu could be nested in a sync parent menu.
2588 bool quit_now = !async_run_ && exit_type_ != EXIT_NONE && message_loop_depth_;
2589 if (quit_now)
2590 message_loop_->QuitNow();
2591 return quit_now;
2592 }
2593
2594 void MenuController::ExitAsyncRun() {
2595 if (!async_run_)
2596 return;
2597 bool nested = delegate_stack_.size() > 1; 2556 bool nested = delegate_stack_.size() > 1;
2598 // ExitMenuRun unwinds nested delegates 2557 // ExitTopMostMenu unwinds nested delegates
2599 internal::MenuControllerDelegate* delegate = delegate_; 2558 internal::MenuControllerDelegate* delegate = delegate_;
2600 // MenuController may have been deleted when releasing ViewsDelegate ref. 2559 // MenuController may have been deleted when releasing ViewsDelegate ref.
2601 // However as |delegate| can outlive this, it must still be notified of the 2560 // However as |delegate| can outlive this, it must still be notified of the
2602 // menu closing so that it can perform teardown. 2561 // menu closing so that it can perform teardown.
2603 int accept_event_flags = accept_event_flags_; 2562 int accept_event_flags = accept_event_flags_;
2604 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 2563 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
2605 MenuItemView* result = ExitMenuRun(); 2564 MenuItemView* result = ExitTopMostMenu();
2606 delegate->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE, 2565 delegate->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
2607 result, accept_event_flags); 2566 result, accept_event_flags);
2608 // |delegate| may have deleted this. 2567 // |delegate| may have deleted this.
2609 if (this_ref && nested && exit_type_ == EXIT_ALL) 2568 if (this_ref && nested && exit_type_ == EXIT_ALL)
2610 ExitAsyncRun(); 2569 ExitMenu();
2611 } 2570 }
2612 2571
2613 MenuItemView* MenuController::ExitMenuRun() { 2572 MenuItemView* MenuController::ExitTopMostMenu() {
2614 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); 2573 base::WeakPtr<MenuController> this_ref = AsWeakPtr();
2615 2574
2616 // Release the lock which prevents Chrome from shutting down while the menu is 2575 // Release the lock which prevents Chrome from shutting down while the menu is
2617 // showing. 2576 // showing.
2618 if (async_run_ && ViewsDelegate::GetInstance()) 2577 if (ViewsDelegate::GetInstance())
2619 ViewsDelegate::GetInstance()->ReleaseRef(); 2578 ViewsDelegate::GetInstance()->ReleaseRef();
2620 2579
2621 // Releasing the lock can result in Chrome shutting down, deleting this. 2580 // Releasing the lock can result in Chrome shutting down, deleting this.
2622 if (!this_ref) 2581 if (!this_ref)
2623 return nullptr; 2582 return nullptr;
2624 2583
2625 // Close any open menus. 2584 // Close any open menus.
2626 SetSelection(nullptr, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT); 2585 SetSelection(nullptr, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
2627 2586
2628 #if defined(OS_WIN) 2587 #if defined(OS_WIN)
(...skipping 23 matching lines...) Expand all
2652 // We're running from within a menu, restore the previous state. 2611 // We're running from within a menu, restore the previous state.
2653 // The menus are already showing, so we don't have to show them. 2612 // The menus are already showing, so we don't have to show them.
2654 state_ = menu_stack_.back().first; 2613 state_ = menu_stack_.back().first;
2655 pending_state_ = menu_stack_.back().first; 2614 pending_state_ = menu_stack_.back().first;
2656 hot_button_ = state_.hot_button; 2615 hot_button_ = state_.hot_button;
2657 nested_pressed_lock = std::move(menu_stack_.back().second); 2616 nested_pressed_lock = std::move(menu_stack_.back().second);
2658 menu_stack_.pop_back(); 2617 menu_stack_.pop_back();
2659 // Even though the menus are nested, there may not be nested delegates. 2618 // Even though the menus are nested, there may not be nested delegates.
2660 if (delegate_stack_.size() > 1) { 2619 if (delegate_stack_.size() > 1) {
2661 delegate_stack_.pop_back(); 2620 delegate_stack_.pop_back();
2662 delegate_ = delegate_stack_.back().first; 2621 delegate_ = delegate_stack_.back();
2663 async_run_ = delegate_stack_.back().second;
2664 } 2622 }
2665 } else { 2623 } else {
2666 #if defined(USE_AURA) 2624 #if defined(USE_AURA)
2667 menu_pre_target_handler_.reset(); 2625 menu_pre_target_handler_.reset();
2668 #endif 2626 #endif
2669 2627
2670 showing_ = false; 2628 showing_ = false;
2671 did_capture_ = false; 2629 did_capture_ = false;
2672 } 2630 }
2673 2631
2674 MenuItemView* result = result_; 2632 MenuItemView* result = result_;
2675 // In case we're nested, reset |result_|. 2633 // In case we're nested, reset |result_|.
2676 result_ = nullptr; 2634 result_ = nullptr;
2677 2635
2678 if (exit_type_ == EXIT_OUTERMOST) { 2636 if (exit_type_ == EXIT_OUTERMOST) {
2679 SetExitType(EXIT_NONE); 2637 SetExitType(EXIT_NONE);
2680 } else { 2638 } else if (nested_menu && result) {
2681 if (nested_menu && result) { 2639 // We're nested and about to return a value. The caller might enter
2682 // We're nested and about to return a value. The caller might enter 2640 // another blocking loop. We need to make sure all menus are hidden
2683 // another blocking loop. We need to make sure all menus are hidden 2641 // before that happens otherwise the menus will stay on screen.
2684 // before that happens otherwise the menus will stay on screen. 2642 CloseAllNestedMenus();
2685 CloseAllNestedMenus(); 2643 SetSelection(nullptr, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
2686 SetSelection(nullptr, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
2687 2644
2688 // Set exit_all_, which makes sure all nested loops exit immediately. 2645 // Set exit_all_, which makes sure all nested loops exit immediately.
2689 if (exit_type_ != EXIT_DESTROYED) 2646 if (exit_type_ != EXIT_DESTROYED)
2690 SetExitType(EXIT_ALL); 2647 SetExitType(EXIT_ALL);
2691 } else {
2692 TerminateNestedMessageLoopIfNecessary();
2693 }
2694 } 2648 }
2695 2649
2696 // Reset our pressed lock and hot-tracked state to the previous state's, if 2650 // Reset our pressed lock and hot-tracked state to the previous state's, if
2697 // they were active. The lock handles the case if the button was destroyed. 2651 // they were active. The lock handles the case if the button was destroyed.
2698 pressed_lock_ = std::move(nested_pressed_lock); 2652 pressed_lock_ = std::move(nested_pressed_lock);
2699 if (hot_button_) 2653 if (hot_button_)
2700 hot_button_->SetHotTracked(true); 2654 hot_button_->SetHotTracked(true);
2701 2655
2702 return result; 2656 return result;
2703 } 2657 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
2757 if (hot_button_) 2711 if (hot_button_)
2758 hot_button_->SetHotTracked(false); 2712 hot_button_->SetHotTracked(false);
2759 hot_button_ = hot_button; 2713 hot_button_ = hot_button;
2760 if (hot_button) { 2714 if (hot_button) {
2761 hot_button->SetHotTracked(true); 2715 hot_button->SetHotTracked(true);
2762 hot_button->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); 2716 hot_button->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true);
2763 } 2717 }
2764 } 2718 }
2765 2719
2766 } // namespace views 2720 } // 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