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