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 |