Index: ui/views/controls/menu/menu_controller.cc |
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc |
index d16553b880d9fa4d0f36645ab2febab82ef4366f..10b2cd914e768af579dec903fc6996c741838c10 100644 |
--- a/ui/views/controls/menu/menu_controller.cc |
+++ b/ui/views/controls/menu/menu_controller.cc |
@@ -679,7 +679,7 @@ void MenuController::OnTouchEvent(SubmenuView* source, ui::TouchEvent* event) { |
if (event->type() == ui::ET_TOUCH_PRESSED) { |
MenuPart part = GetMenuPart(source, event->location()); |
if (part.type == MenuPart::NONE) { |
- RepostEvent(source, event); |
+ RepostEventAndCancel(source, event); |
event->SetHandled(); |
} |
} |
@@ -1001,36 +1001,8 @@ void MenuController::SetSelectionOnPointerDown(SubmenuView* source, |
// then use this to figure out if this menu was finished with the same click |
// which is sent to it thereafter. |
closing_event_time_ = event->time_stamp(); |
- |
- // Mouse wasn't pressed over any menu, or the active menu, cancel. |
- |
-#if defined(OS_WIN) |
- // We're going to close and we own the mouse capture. We need to repost the |
- // mouse down, otherwise the window the user clicked on won't get the event. |
- RepostEvent(source, event); |
-#endif |
- |
- // And close. |
- ExitType exit_type = EXIT_ALL; |
- if (!menu_stack_.empty()) { |
- // We're running nested menus. Only exit all if the mouse wasn't over one |
- // of the menus from the last run. |
- gfx::Point screen_loc(event->location()); |
- View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); |
- MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu( |
- menu_stack_.back().first.item, screen_loc); |
- if (last_part.type != MenuPart::NONE) |
- exit_type = EXIT_OUTERMOST; |
- } |
- Cancel(exit_type); |
- |
-#if defined(OS_CHROMEOS) |
- // We're going to exit the menu and want to repost the event so that is |
- // is handled normally after the context menu has exited. We call |
- // RepostEvent after Cancel so that mouse capture has been released so |
- // that finding the event target is unaffected by the current capture. |
- RepostEvent(source, event); |
-#endif |
+ // Event wasn't pressed over any menu, or the active menu, cancel. |
+ RepostEventAndCancel(source, event); |
// Do not repost events for Linux Aura because this behavior is more |
// consistent with the behavior of other Linux apps. |
return; |
@@ -2188,7 +2160,10 @@ void MenuController::SelectByChar(base::char16 character) { |
} |
void MenuController::RepostEvent(SubmenuView* source, |
- const ui::LocatedEvent* event) { |
+ const ui::LocatedEvent* event, |
+ const gfx::Point& screen_loc, |
+ gfx::NativeView native_view, |
+ gfx::NativeWindow window) { |
if (!event->IsMouseEvent() && !event->IsTouchEvent()) { |
// TODO(rbyers): Gesture event repost is tricky to get right |
// crbug.com/170987. |
@@ -2208,15 +2183,9 @@ void MenuController::RepostEvent(SubmenuView* source, |
state_.item->GetRootMenuItem()->GetSubmenu()->ReleaseCapture(); |
#endif |
- gfx::Point screen_loc(event->location()); |
- View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); |
- gfx::NativeView native_view = source->GetWidget()->GetNativeView(); |
if (!native_view) |
return; |
- gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); |
- gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc); |
- |
#if defined(OS_WIN) |
gfx::Point screen_loc_pixels = gfx::win::DIPToScreenPoint(screen_loc); |
HWND target_window = ::WindowFromPoint(screen_loc_pixels.ToPOINT()); |
@@ -2294,6 +2263,47 @@ void MenuController::RepostEvent(SubmenuView* source, |
MenuMessageLoop::RepostEventToWindow(event, window, screen_loc); |
} |
+void MenuController::RepostEventAndCancel(SubmenuView* source, |
+ const ui::LocatedEvent* event) { |
+ // Cancel can lead to the deletion |source| so we save the view and window to |
+ // be used when reposting the event. |
+ gfx::Point screen_loc(event->location()); |
+ View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); |
+ gfx::NativeView native_view = source->GetWidget()->GetNativeView(); |
+ gfx::NativeWindow window = nullptr; |
+ if (native_view) { |
+ gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); |
+ window = screen->GetWindowAtScreenPoint(screen_loc); |
+ } |
+ |
+#if defined(OS_WIN) |
+ // We're going to close and we own the event capture. We need to repost the |
+ // event, otherwise the window the user clicked on won't get the event. |
+ RepostEvent(source, event, screen_loc, native_view, window); |
+#endif |
+ |
+ // Determine target to see if a complete or partial close of the menu should |
+ // occur. |
+ ExitType exit_type = EXIT_ALL; |
+ if (!menu_stack_.empty()) { |
+ // We're running nested menus. Only exit all if the mouse wasn't over one |
+ // of the menus from the last run. |
+ MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu( |
+ menu_stack_.back().first.item, screen_loc); |
+ if (last_part.type != MenuPart::NONE) |
+ exit_type = EXIT_OUTERMOST; |
+ } |
+ Cancel(exit_type); |
+ |
+#if defined(OS_CHROMEOS) |
+ // We're going to exit the menu and want to repost the event so that is |
+ // is handled normally after the context menu has exited. We call |
+ // RepostEvent after Cancel so that event capture has been released so |
+ // that finding the event target is unaffected by the current capture. |
+ RepostEvent(source, event, screen_loc, native_view, window); |
+#endif |
+} |
+ |
void MenuController::SetDropMenuItem( |
MenuItemView* new_target, |
MenuDelegate::DropPosition new_position) { |