| 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" |
| (...skipping 504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 515 SendMouseCaptureLostToActiveView(); | 515 SendMouseCaptureLostToActiveView(); |
| 516 | 516 |
| 517 // Hide windows immediately. | 517 // Hide windows immediately. |
| 518 SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT); | 518 SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT); |
| 519 | 519 |
| 520 if (!blocking_run_) { | 520 if (!blocking_run_) { |
| 521 // If we didn't block the caller we need to notify the menu, which | 521 // If we didn't block the caller we need to notify the menu, which |
| 522 // triggers deleting us. | 522 // triggers deleting us. |
| 523 DCHECK(selected); | 523 DCHECK(selected); |
| 524 showing_ = false; | 524 showing_ = false; |
| 525 delegate_->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE, | 525 // Verify that the delegate was not destroyed. |
| 526 selected->GetRootMenuItem(), accept_event_flags_); | 526 if (delegate_) { |
| 527 delegate_->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE, |
| 528 selected->GetRootMenuItem(), accept_event_flags_); |
| 529 } |
| 527 // WARNING: the call to MenuClosed deletes us. | 530 // WARNING: the call to MenuClosed deletes us. |
| 528 return; | 531 return; |
| 529 } | 532 } |
| 530 | 533 |
| 531 // On Windows and Linux the destruction of this menu's Widget leads to the | 534 // On Windows and Linux the destruction of this menu's Widget leads to the |
| 532 // teardown of the platform specific drag-and-drop Widget. Do not shutdown | 535 // teardown of the platform specific drag-and-drop Widget. Do not shutdown |
| 533 // while dragging, leave the Widget hidden until drag-and-drop has completed, | 536 // while dragging, leave the Widget hidden until drag-and-drop has completed, |
| 534 // at which point all menus will be destroyed. | 537 // at which point all menus will be destroyed. |
| 535 // | 538 // |
| 536 // If |type| is EXIT_ALL we update the state of the menu to not showing. So | 539 // If |type| is EXIT_ALL we update the state of the menu to not showing. So |
| 537 // that during the completion of a drag we are not incorrectly reporting the | 540 // that during the completion of a drag we are not incorrectly reporting the |
| 538 // visual state. | 541 // visual state. |
| 539 if (!drag_in_progress_) | 542 if (!drag_in_progress_) |
| 540 ExitAsyncRun(); | 543 ExitAsyncRun(); |
| 541 else if (type == EXIT_ALL) | 544 else if (type == EXIT_ALL) |
| 542 showing_ = false; | 545 showing_ = false; |
| 543 } | 546 } |
| 544 | 547 |
| 545 void MenuController::AddNestedDelegate( | 548 void MenuController::AddNestedDelegate( |
| 546 internal::MenuControllerDelegate* delegate) { | 549 internal::MenuControllerDelegate* delegate) { |
| 547 delegate_stack_.push_back(std::make_pair(delegate, async_run_)); | 550 delegate_stack_.push_back(std::make_pair(delegate->AsWeakPtr(), async_run_)); |
| 548 delegate_ = delegate; | 551 delegate_ = delegate->AsWeakPtr(); |
| 549 } | 552 } |
| 550 | 553 |
| 551 void MenuController::SetAsyncRun(bool is_async) { | 554 void MenuController::SetAsyncRun(bool is_async) { |
| 552 delegate_stack_.back().second = is_async; | 555 delegate_stack_.back().second = is_async; |
| 553 async_run_ = is_async; | 556 async_run_ = is_async; |
| 554 } | 557 } |
| 555 | 558 |
| 556 bool MenuController::OnMousePressed(SubmenuView* source, | 559 bool MenuController::OnMousePressed(SubmenuView* source, |
| 557 const ui::MouseEvent& event) { | 560 const ui::MouseEvent& event) { |
| 558 // We should either have no current_mouse_event_target_, or should have a | 561 // We should either have no current_mouse_event_target_, or should have a |
| (...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 971 CloseAllNestedMenus(); | 974 CloseAllNestedMenus(); |
| 972 | 975 |
| 973 // Set state such that we exit. | 976 // Set state such that we exit. |
| 974 showing_ = false; | 977 showing_ = false; |
| 975 SetExitType(EXIT_ALL); | 978 SetExitType(EXIT_ALL); |
| 976 | 979 |
| 977 // If over an empty menu item, drop occurs on the parent. | 980 // If over an empty menu item, drop occurs on the parent. |
| 978 if (drop_target->id() == MenuItemView::kEmptyMenuItemViewID) | 981 if (drop_target->id() == MenuItemView::kEmptyMenuItemViewID) |
| 979 drop_target = drop_target->GetParentMenuItem(); | 982 drop_target = drop_target->GetParentMenuItem(); |
| 980 | 983 |
| 981 if (!IsBlockingRun()) { | 984 if (!IsBlockingRun() && delegate_) { |
| 982 delegate_->OnMenuClosed( | 985 delegate_->OnMenuClosed( |
| 983 internal::MenuControllerDelegate::DONT_NOTIFY_DELEGATE, | 986 internal::MenuControllerDelegate::DONT_NOTIFY_DELEGATE, |
| 984 item->GetRootMenuItem(), accept_event_flags_); | 987 item->GetRootMenuItem(), accept_event_flags_); |
| 985 } | 988 } |
| 986 | 989 |
| 987 // WARNING: the call to MenuClosed deletes us. | 990 // WARNING: the call to MenuClosed deletes us. |
| 988 | 991 |
| 989 return drop_target->GetDelegate()->OnPerformDrop( | 992 return drop_target->GetDelegate()->OnPerformDrop( |
| 990 drop_target, drop_position, event); | 993 drop_target, drop_position, event); |
| 991 } | 994 } |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1388 drop_position_(MenuDelegate::DROP_UNKNOWN), | 1391 drop_position_(MenuDelegate::DROP_UNKNOWN), |
| 1389 owner_(NULL), | 1392 owner_(NULL), |
| 1390 possible_drag_(false), | 1393 possible_drag_(false), |
| 1391 drag_in_progress_(false), | 1394 drag_in_progress_(false), |
| 1392 did_initiate_drag_(false), | 1395 did_initiate_drag_(false), |
| 1393 valid_drop_coordinates_(false), | 1396 valid_drop_coordinates_(false), |
| 1394 last_drop_operation_(MenuDelegate::DROP_UNKNOWN), | 1397 last_drop_operation_(MenuDelegate::DROP_UNKNOWN), |
| 1395 showing_submenu_(false), | 1398 showing_submenu_(false), |
| 1396 active_mouse_view_id_(ViewStorage::GetInstance()->CreateStorageID()), | 1399 active_mouse_view_id_(ViewStorage::GetInstance()->CreateStorageID()), |
| 1397 hot_button_(nullptr), | 1400 hot_button_(nullptr), |
| 1398 delegate_(delegate), | 1401 delegate_(delegate->AsWeakPtr()), |
| 1399 message_loop_depth_(0), | 1402 message_loop_depth_(0), |
| 1400 async_run_(false), | 1403 async_run_(false), |
| 1401 is_combobox_(false), | 1404 is_combobox_(false), |
| 1402 item_selected_by_touch_(false), | 1405 item_selected_by_touch_(false), |
| 1403 current_mouse_event_target_(nullptr), | 1406 current_mouse_event_target_(nullptr), |
| 1404 current_mouse_pressed_state_(0), | 1407 current_mouse_pressed_state_(0), |
| 1405 message_loop_(MenuMessageLoop::Create()) { | 1408 message_loop_(MenuMessageLoop::Create()) { |
| 1406 delegate_stack_.push_back(std::make_pair(delegate_, async_run_)); | 1409 delegate_stack_.push_back(std::make_pair(delegate_, async_run_)); |
| 1407 active_instance_ = this; | 1410 active_instance_ = this; |
| 1408 } | 1411 } |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1515 View::ConvertPointToScreen(source_view, &screen_point); | 1518 View::ConvertPointToScreen(source_view, &screen_point); |
| 1516 MenuAnchorPosition anchor; | 1519 MenuAnchorPosition anchor; |
| 1517 bool has_mnemonics; | 1520 bool has_mnemonics; |
| 1518 MenuButton* button = NULL; | 1521 MenuButton* button = NULL; |
| 1519 MenuItemView* alt_menu = source->GetMenuItem()->GetDelegate()-> | 1522 MenuItemView* alt_menu = source->GetMenuItem()->GetDelegate()-> |
| 1520 GetSiblingMenu(source->GetMenuItem()->GetRootMenuItem(), | 1523 GetSiblingMenu(source->GetMenuItem()->GetRootMenuItem(), |
| 1521 screen_point, &anchor, &has_mnemonics, &button); | 1524 screen_point, &anchor, &has_mnemonics, &button); |
| 1522 if (!alt_menu || (state_.item && state_.item->GetRootMenuItem() == alt_menu)) | 1525 if (!alt_menu || (state_.item && state_.item->GetRootMenuItem() == alt_menu)) |
| 1523 return false; | 1526 return false; |
| 1524 | 1527 |
| 1525 delegate_->SiblingMenuCreated(alt_menu); | 1528 if (delegate_) |
| 1529 delegate_->SiblingMenuCreated(alt_menu); |
| 1526 | 1530 |
| 1527 if (!button) { | 1531 if (!button) { |
| 1528 // If the delegate returns a menu, they must also return a button. | 1532 // If the delegate returns a menu, they must also return a button. |
| 1529 NOTREACHED(); | 1533 NOTREACHED(); |
| 1530 return false; | 1534 return false; |
| 1531 } | 1535 } |
| 1532 | 1536 |
| 1533 // There is a sibling menu, update the button state, hide the current menu | 1537 // There is a sibling menu, update the button state, hide the current menu |
| 1534 // and show the new one. | 1538 // and show the new one. |
| 1535 pressed_lock_.reset( | 1539 pressed_lock_.reset( |
| (...skipping 1042 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2578 if (quit_now) | 2582 if (quit_now) |
| 2579 message_loop_->QuitNow(); | 2583 message_loop_->QuitNow(); |
| 2580 return quit_now; | 2584 return quit_now; |
| 2581 } | 2585 } |
| 2582 | 2586 |
| 2583 void MenuController::ExitAsyncRun() { | 2587 void MenuController::ExitAsyncRun() { |
| 2584 if (!async_run_) | 2588 if (!async_run_) |
| 2585 return; | 2589 return; |
| 2586 bool nested = delegate_stack_.size() > 1; | 2590 bool nested = delegate_stack_.size() > 1; |
| 2587 // ExitMenuRun unwinds nested delegates | 2591 // ExitMenuRun unwinds nested delegates |
| 2588 internal::MenuControllerDelegate* delegate = delegate_; | 2592 base::WeakPtr<internal::MenuControllerDelegate> delegate = delegate_; |
| 2589 // MenuController may have been deleted when releasing ViewsDelegate ref. | 2593 // MenuController may have been deleted when releasing ViewsDelegate ref. |
| 2590 // However as |delegate| can outlive this, it must still be notified of the | 2594 // However as |delegate| can outlive this, it must still be notified of the |
| 2591 // menu closing so that it can perform teardown. | 2595 // menu closing so that it can perform teardown. |
| 2592 int accept_event_flags = accept_event_flags_; | 2596 int accept_event_flags = accept_event_flags_; |
| 2593 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); | 2597 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); |
| 2594 MenuItemView* result = ExitMenuRun(); | 2598 MenuItemView* result = ExitMenuRun(); |
| 2595 delegate->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE, | 2599 // The delegate may have been deleted. |
| 2596 result, accept_event_flags); | 2600 if (delegate) { |
| 2601 delegate->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE, |
| 2602 result, accept_event_flags); |
| 2603 } |
| 2597 // |delegate| may have deleted this. | 2604 // |delegate| may have deleted this. |
| 2598 if (this_ref && nested && exit_type_ == EXIT_ALL) | 2605 if (this_ref && nested && exit_type_ == EXIT_ALL) |
| 2599 ExitAsyncRun(); | 2606 ExitAsyncRun(); |
| 2600 } | 2607 } |
| 2601 | 2608 |
| 2602 MenuItemView* MenuController::ExitMenuRun() { | 2609 MenuItemView* MenuController::ExitMenuRun() { |
| 2603 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); | 2610 base::WeakPtr<MenuController> this_ref = AsWeakPtr(); |
| 2604 | 2611 |
| 2605 // Release the lock which prevents Chrome from shutting down while the menu is | 2612 // Release the lock which prevents Chrome from shutting down while the menu is |
| 2606 // showing. | 2613 // showing. |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2746 if (hot_button_) | 2753 if (hot_button_) |
| 2747 hot_button_->SetHotTracked(false); | 2754 hot_button_->SetHotTracked(false); |
| 2748 hot_button_ = hot_button; | 2755 hot_button_ = hot_button; |
| 2749 if (hot_button) { | 2756 if (hot_button) { |
| 2750 hot_button->SetHotTracked(true); | 2757 hot_button->SetHotTracked(true); |
| 2751 hot_button->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); | 2758 hot_button->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); |
| 2752 } | 2759 } |
| 2753 } | 2760 } |
| 2754 | 2761 |
| 2755 } // namespace views | 2762 } // namespace views |
| OLD | NEW |