| 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 |