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 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 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 29 matching lines...) Expand all Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |