| 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 661 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 672 | 672 |
| 673 if (!part.submenu) | 673 if (!part.submenu) |
| 674 return; | 674 return; |
| 675 part.submenu->OnGestureEvent(event); | 675 part.submenu->OnGestureEvent(event); |
| 676 } | 676 } |
| 677 | 677 |
| 678 void MenuController::OnTouchEvent(SubmenuView* source, ui::TouchEvent* event) { | 678 void MenuController::OnTouchEvent(SubmenuView* source, ui::TouchEvent* event) { |
| 679 if (event->type() == ui::ET_TOUCH_PRESSED) { | 679 if (event->type() == ui::ET_TOUCH_PRESSED) { |
| 680 MenuPart part = GetMenuPart(source, event->location()); | 680 MenuPart part = GetMenuPart(source, event->location()); |
| 681 if (part.type == MenuPart::NONE) { | 681 if (part.type == MenuPart::NONE) { |
| 682 RepostEvent(source, event); | 682 RepostEventAndCancel(source, event); |
| 683 event->SetHandled(); | 683 event->SetHandled(); |
| 684 } | 684 } |
| 685 } | 685 } |
| 686 } | 686 } |
| 687 | 687 |
| 688 View* MenuController::GetTooltipHandlerForPoint(SubmenuView* source, | 688 View* MenuController::GetTooltipHandlerForPoint(SubmenuView* source, |
| 689 const gfx::Point& point) { | 689 const gfx::Point& point) { |
| 690 MenuHostRootView* root_view = GetRootView(source, point); | 690 MenuHostRootView* root_view = GetRootView(source, point); |
| 691 return root_view ? root_view->ProcessGetTooltipHandlerForPoint(point) | 691 return root_view ? root_view->ProcessGetTooltipHandlerForPoint(point) |
| 692 : nullptr; | 692 : nullptr; |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 994 (event->flags() & ui::EF_FROM_TOUCH)) | 994 (event->flags() & ui::EF_FROM_TOUCH)) |
| 995 return; | 995 return; |
| 996 | 996 |
| 997 if (part.type == MenuPart::NONE || | 997 if (part.type == MenuPart::NONE || |
| 998 (part.type == MenuPart::MENU_ITEM && part.menu && | 998 (part.type == MenuPart::MENU_ITEM && part.menu && |
| 999 part.menu->GetRootMenuItem() != state_.item->GetRootMenuItem())) { | 999 part.menu->GetRootMenuItem() != state_.item->GetRootMenuItem())) { |
| 1000 // Remember the time stamp of the current (press down) event. The owner can | 1000 // Remember the time stamp of the current (press down) event. The owner can |
| 1001 // then use this to figure out if this menu was finished with the same click | 1001 // then use this to figure out if this menu was finished with the same click |
| 1002 // which is sent to it thereafter. | 1002 // which is sent to it thereafter. |
| 1003 closing_event_time_ = event->time_stamp(); | 1003 closing_event_time_ = event->time_stamp(); |
| 1004 | 1004 // Event wasn't pressed over any menu, or the active menu, cancel. |
| 1005 // Mouse wasn't pressed over any menu, or the active menu, cancel. | 1005 RepostEventAndCancel(source, event); |
| 1006 | |
| 1007 #if defined(OS_WIN) | |
| 1008 // We're going to close and we own the mouse capture. We need to repost the | |
| 1009 // mouse down, otherwise the window the user clicked on won't get the event. | |
| 1010 RepostEvent(source, event); | |
| 1011 #endif | |
| 1012 | |
| 1013 // And close. | |
| 1014 ExitType exit_type = EXIT_ALL; | |
| 1015 if (!menu_stack_.empty()) { | |
| 1016 // We're running nested menus. Only exit all if the mouse wasn't over one | |
| 1017 // of the menus from the last run. | |
| 1018 gfx::Point screen_loc(event->location()); | |
| 1019 View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); | |
| 1020 MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu( | |
| 1021 menu_stack_.back().first.item, screen_loc); | |
| 1022 if (last_part.type != MenuPart::NONE) | |
| 1023 exit_type = EXIT_OUTERMOST; | |
| 1024 } | |
| 1025 Cancel(exit_type); | |
| 1026 | |
| 1027 #if defined(OS_CHROMEOS) | |
| 1028 // We're going to exit the menu and want to repost the event so that is | |
| 1029 // is handled normally after the context menu has exited. We call | |
| 1030 // RepostEvent after Cancel so that mouse capture has been released so | |
| 1031 // that finding the event target is unaffected by the current capture. | |
| 1032 RepostEvent(source, event); | |
| 1033 #endif | |
| 1034 // Do not repost events for Linux Aura because this behavior is more | 1006 // Do not repost events for Linux Aura because this behavior is more |
| 1035 // consistent with the behavior of other Linux apps. | 1007 // consistent with the behavior of other Linux apps. |
| 1036 return; | 1008 return; |
| 1037 } | 1009 } |
| 1038 | 1010 |
| 1039 // On a press we immediately commit the selection, that way a submenu | 1011 // On a press we immediately commit the selection, that way a submenu |
| 1040 // pops up immediately rather than after a delay. | 1012 // pops up immediately rather than after a delay. |
| 1041 int selection_types = SELECTION_UPDATE_IMMEDIATELY; | 1013 int selection_types = SELECTION_UPDATE_IMMEDIATELY; |
| 1042 if (!part.menu) { | 1014 if (!part.menu) { |
| 1043 part.menu = part.parent; | 1015 part.menu = part.parent; |
| (...skipping 1137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2181 item->GetSubmenu()->GetPrefixSelector()->InsertText(char_array); | 2153 item->GetSubmenu()->GetPrefixSelector()->InsertText(char_array); |
| 2182 } else { | 2154 } else { |
| 2183 // If no mnemonics found, look at first character of titles. | 2155 // If no mnemonics found, look at first character of titles. |
| 2184 details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic); | 2156 details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic); |
| 2185 if (details.first_match != -1) | 2157 if (details.first_match != -1) |
| 2186 AcceptOrSelect(item, details); | 2158 AcceptOrSelect(item, details); |
| 2187 } | 2159 } |
| 2188 } | 2160 } |
| 2189 | 2161 |
| 2190 void MenuController::RepostEvent(SubmenuView* source, | 2162 void MenuController::RepostEvent(SubmenuView* source, |
| 2191 const ui::LocatedEvent* event) { | 2163 const ui::LocatedEvent* event, |
| 2164 const gfx::Point& screen_loc, |
| 2165 gfx::NativeView native_view, |
| 2166 gfx::NativeWindow window) { |
| 2192 if (!event->IsMouseEvent() && !event->IsTouchEvent()) { | 2167 if (!event->IsMouseEvent() && !event->IsTouchEvent()) { |
| 2193 // TODO(rbyers): Gesture event repost is tricky to get right | 2168 // TODO(rbyers): Gesture event repost is tricky to get right |
| 2194 // crbug.com/170987. | 2169 // crbug.com/170987. |
| 2195 DCHECK(event->IsGestureEvent()); | 2170 DCHECK(event->IsGestureEvent()); |
| 2196 return; | 2171 return; |
| 2197 } | 2172 } |
| 2198 | 2173 |
| 2199 #if defined(OS_WIN) | 2174 #if defined(OS_WIN) |
| 2200 if (!state_.item) { | 2175 if (!state_.item) { |
| 2201 // We some times get an event after closing all the menus. Ignore it. Make | 2176 // We some times get an event after closing all the menus. Ignore it. Make |
| 2202 // sure the menu is in fact not visible. If the menu is visible, then | 2177 // sure the menu is in fact not visible. If the menu is visible, then |
| 2203 // we're in a bad state where we think the menu isn't visibile but it is. | 2178 // we're in a bad state where we think the menu isn't visibile but it is. |
| 2204 DCHECK(!source->GetWidget()->IsVisible()); | 2179 DCHECK(!source->GetWidget()->IsVisible()); |
| 2205 return; | 2180 return; |
| 2206 } | 2181 } |
| 2207 | 2182 |
| 2208 state_.item->GetRootMenuItem()->GetSubmenu()->ReleaseCapture(); | 2183 state_.item->GetRootMenuItem()->GetSubmenu()->ReleaseCapture(); |
| 2209 #endif | 2184 #endif |
| 2210 | 2185 |
| 2211 gfx::Point screen_loc(event->location()); | |
| 2212 View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); | |
| 2213 gfx::NativeView native_view = source->GetWidget()->GetNativeView(); | |
| 2214 if (!native_view) | 2186 if (!native_view) |
| 2215 return; | 2187 return; |
| 2216 | 2188 |
| 2217 gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); | |
| 2218 gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc); | |
| 2219 | |
| 2220 #if defined(OS_WIN) | 2189 #if defined(OS_WIN) |
| 2221 gfx::Point screen_loc_pixels = gfx::win::DIPToScreenPoint(screen_loc); | 2190 gfx::Point screen_loc_pixels = gfx::win::DIPToScreenPoint(screen_loc); |
| 2222 HWND target_window = ::WindowFromPoint(screen_loc_pixels.ToPOINT()); | 2191 HWND target_window = ::WindowFromPoint(screen_loc_pixels.ToPOINT()); |
| 2223 // If we don't find a native window for the HWND at the current location, | 2192 // If we don't find a native window for the HWND at the current location, |
| 2224 // then attempt to find a native window from its parent if one exists. | 2193 // then attempt to find a native window from its parent if one exists. |
| 2225 // There are HWNDs created outside views, which don't have associated | 2194 // There are HWNDs created outside views, which don't have associated |
| 2226 // native windows. | 2195 // native windows. |
| 2227 if (!window) { | 2196 if (!window) { |
| 2228 HWND parent = ::GetParent(target_window); | 2197 HWND parent = ::GetParent(target_window); |
| 2229 if (parent) { | 2198 if (parent) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2287 return; | 2256 return; |
| 2288 } | 2257 } |
| 2289 #endif | 2258 #endif |
| 2290 // Non Aura window. | 2259 // Non Aura window. |
| 2291 if (!window) | 2260 if (!window) |
| 2292 return; | 2261 return; |
| 2293 | 2262 |
| 2294 MenuMessageLoop::RepostEventToWindow(event, window, screen_loc); | 2263 MenuMessageLoop::RepostEventToWindow(event, window, screen_loc); |
| 2295 } | 2264 } |
| 2296 | 2265 |
| 2266 void MenuController::RepostEventAndCancel(SubmenuView* source, |
| 2267 const ui::LocatedEvent* event) { |
| 2268 // Cancel can lead to the deletion |source| so we save the view and window to |
| 2269 // be used when reposting the event. |
| 2270 gfx::Point screen_loc(event->location()); |
| 2271 View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); |
| 2272 gfx::NativeView native_view = source->GetWidget()->GetNativeView(); |
| 2273 gfx::NativeWindow window = nullptr; |
| 2274 if (native_view) { |
| 2275 gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); |
| 2276 window = screen->GetWindowAtScreenPoint(screen_loc); |
| 2277 } |
| 2278 |
| 2279 #if defined(OS_WIN) |
| 2280 // We're going to close and we own the event capture. We need to repost the |
| 2281 // event, otherwise the window the user clicked on won't get the event. |
| 2282 RepostEvent(source, event, screen_loc, native_view, window); |
| 2283 #endif |
| 2284 |
| 2285 // Determine target to see if a complete or partial close of the menu should |
| 2286 // occur. |
| 2287 ExitType exit_type = EXIT_ALL; |
| 2288 if (!menu_stack_.empty()) { |
| 2289 // We're running nested menus. Only exit all if the mouse wasn't over one |
| 2290 // of the menus from the last run. |
| 2291 MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu( |
| 2292 menu_stack_.back().first.item, screen_loc); |
| 2293 if (last_part.type != MenuPart::NONE) |
| 2294 exit_type = EXIT_OUTERMOST; |
| 2295 } |
| 2296 Cancel(exit_type); |
| 2297 |
| 2298 #if defined(OS_CHROMEOS) |
| 2299 // We're going to exit the menu and want to repost the event so that is |
| 2300 // is handled normally after the context menu has exited. We call |
| 2301 // RepostEvent after Cancel so that event capture has been released so |
| 2302 // that finding the event target is unaffected by the current capture. |
| 2303 RepostEvent(source, event, screen_loc, native_view, window); |
| 2304 #endif |
| 2305 } |
| 2306 |
| 2297 void MenuController::SetDropMenuItem( | 2307 void MenuController::SetDropMenuItem( |
| 2298 MenuItemView* new_target, | 2308 MenuItemView* new_target, |
| 2299 MenuDelegate::DropPosition new_position) { | 2309 MenuDelegate::DropPosition new_position) { |
| 2300 if (new_target == drop_target_ && new_position == drop_position_) | 2310 if (new_target == drop_target_ && new_position == drop_position_) |
| 2301 return; | 2311 return; |
| 2302 | 2312 |
| 2303 if (drop_target_) { | 2313 if (drop_target_) { |
| 2304 drop_target_->GetParentMenuItem()->GetSubmenu()->SetDropMenuItem( | 2314 drop_target_->GetParentMenuItem()->GetSubmenu()->SetDropMenuItem( |
| 2305 NULL, MenuDelegate::DROP_NONE); | 2315 NULL, MenuDelegate::DROP_NONE); |
| 2306 } | 2316 } |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2558 } | 2568 } |
| 2559 } | 2569 } |
| 2560 | 2570 |
| 2561 gfx::Screen* MenuController::GetScreen() { | 2571 gfx::Screen* MenuController::GetScreen() { |
| 2562 Widget* root = owner_ ? owner_->GetTopLevelWidget() : NULL; | 2572 Widget* root = owner_ ? owner_->GetTopLevelWidget() : NULL; |
| 2563 return root ? gfx::Screen::GetScreenFor(root->GetNativeView()) | 2573 return root ? gfx::Screen::GetScreenFor(root->GetNativeView()) |
| 2564 : gfx::Screen::GetNativeScreen(); | 2574 : gfx::Screen::GetNativeScreen(); |
| 2565 } | 2575 } |
| 2566 | 2576 |
| 2567 } // namespace views | 2577 } // namespace views |
| OLD | NEW |