OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |