| 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 1861724d21d6488bc51f379ac0ff14cacb753f35..a63448d679b1d8715e1550f65095e324cc1624cc 100644
|
| --- a/ui/views/controls/menu/menu_controller.cc
|
| +++ b/ui/views/controls/menu/menu_controller.cc
|
| @@ -13,18 +13,21 @@
|
| #include "base/run_loop.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/time/time.h"
|
| +#include "ui/aura/client/screen_position_client.h"
|
| #include "ui/aura/env.h"
|
| #include "ui/aura/window.h"
|
| #include "ui/aura/window_event_dispatcher.h"
|
| +#include "ui/aura/window_tree_host.h"
|
| #include "ui/base/dragdrop/drag_utils.h"
|
| #include "ui/base/dragdrop/os_exchange_data.h"
|
| #include "ui/base/l10n/l10n_util.h"
|
| -#include "ui/events/event_constants.h"
|
| +#include "ui/events/event.h"
|
| #include "ui/events/event_utils.h"
|
| #include "ui/events/platform/platform_event_source.h"
|
| #include "ui/events/platform/scoped_event_dispatcher.h"
|
| #include "ui/gfx/canvas.h"
|
| #include "ui/gfx/native_widget_types.h"
|
| +#include "ui/gfx/point.h"
|
| #include "ui/gfx/screen.h"
|
| #include "ui/gfx/vector2d.h"
|
| #include "ui/native_theme/native_theme.h"
|
| @@ -35,9 +38,9 @@
|
| #include "ui/views/controls/menu/menu_scroll_view_container.h"
|
| #include "ui/views/controls/menu/submenu_view.h"
|
| #include "ui/views/drag_utils.h"
|
| -#include "ui/views/event_utils.h"
|
| #include "ui/views/focus/view_storage.h"
|
| #include "ui/views/mouse_constants.h"
|
| +#include "ui/views/view.h"
|
| #include "ui/views/view_constants.h"
|
| #include "ui/views/views_delegate.h"
|
| #include "ui/views/widget/root_view.h"
|
| @@ -56,6 +59,7 @@
|
| #include "ui/views/controls/menu/menu_event_dispatcher_linux.h"
|
| #endif
|
|
|
| +using aura::client::ScreenPositionClient;
|
| using base::Time;
|
| using base::TimeDelta;
|
| using ui::OSExchangeData;
|
| @@ -973,14 +977,7 @@ void MenuController::SetSelectionOnPointerDown(SubmenuView* source,
|
| #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.
|
| - if (!state_.item) {
|
| - // We some times get an event after closing all the menus. Ignore it. Make
|
| - // sure the menu is in fact not visible. If the menu is visible, then
|
| - // we're in a bad state where we think the menu isn't visibile but it is.
|
| - DCHECK(!source->GetWidget()->IsVisible());
|
| - } else {
|
| - RepostEvent(source, event);
|
| - }
|
| + RepostEvent(source, event);
|
| #endif
|
|
|
| // And close.
|
| @@ -2145,52 +2142,106 @@ bool MenuController::SelectByChar(base::char16 character) {
|
|
|
| void MenuController::RepostEvent(SubmenuView* source,
|
| const ui::LocatedEvent& event) {
|
| + if (!event.IsMouseEvent()) {
|
| + // TODO(rbyers): Gesture event repost is tricky to get right
|
| + // crbug.com/170987.
|
| + DCHECK(event.IsGestureEvent());
|
| + return;
|
| + }
|
| +
|
| +#if defined(OS_WIN)
|
| + if (!state_.item) {
|
| + // We some times get an event after closing all the menus. Ignore it. Make
|
| + // sure the menu is in fact not visible. If the menu is visible, then
|
| + // we're in a bad state where we think the menu isn't visibile but it is.
|
| + DCHECK(!source->GetWidget()->IsVisible());
|
| + return;
|
| + }
|
| +
|
| + 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);
|
|
|
| - // On Windows, it is ok for window to be NULL. Please refer to the
|
| - // RepostLocatedEvent function for more information.
|
| #if defined(OS_WIN)
|
| - // Release the capture.
|
| - SubmenuView* submenu = state_.item->GetRootMenuItem()->GetSubmenu();
|
| - submenu->ReleaseCapture();
|
| -
|
| - gfx::NativeView view = submenu->GetWidget()->GetNativeView();
|
| - if (view && window) {
|
| - DWORD view_tid = GetWindowThreadProcessId(HWNDForNativeView(view), NULL);
|
| - if (view_tid != GetWindowThreadProcessId(HWNDForNativeView(window), NULL)) {
|
| + // PostMessage() to metro windows isn't allowed (access will be denied). Don't
|
| + // try to repost with Win32 if the window under the mouse press is in metro.
|
| + if (!ViewsDelegate::views_delegate ||
|
| + !ViewsDelegate::views_delegate->IsWindowInMetro(window)) {
|
| + HWND target_window = window ? HWNDForNativeWindow(window) :
|
| + WindowFromPoint(screen_loc.ToPOINT());
|
| + HWND source_window = HWNDForNativeView(native_view);
|
| + if (!target_window || !source_window ||
|
| + GetWindowThreadProcessId(source_window, NULL) !=
|
| + GetWindowThreadProcessId(target_window, NULL)) {
|
| // Even though we have mouse capture, windows generates a mouse event if
|
| // the other window is in a separate thread. Only repost an event if
|
| - // |view| was created on the same thread, else the target window can get
|
| - // double events leading to bad behavior.
|
| + // |target_window| and |source_window| were created on the same thread,
|
| + // else double events can occur and lead to bad behavior.
|
| return;
|
| }
|
| +
|
| + // Determine whether the click was in the client area or not.
|
| + // NOTE: WM_NCHITTEST coordinates are relative to the screen.
|
| + LPARAM coords = MAKELPARAM(screen_loc.x(), screen_loc.y());
|
| + LRESULT nc_hit_result = SendMessage(target_window, WM_NCHITTEST, 0, coords);
|
| + const bool client_area = nc_hit_result == HTCLIENT;
|
| +
|
| + // TODO(sky): this isn't right. The event to generate should correspond with
|
| + // the event we just got. MouseEvent only tells us what is down, which may
|
| + // differ. Need to add ability to get changed button from MouseEvent.
|
| + int event_type;
|
| + int flags = event.flags();
|
| + if (flags & ui::EF_LEFT_MOUSE_BUTTON) {
|
| + event_type = client_area ? WM_LBUTTONDOWN : WM_NCLBUTTONDOWN;
|
| + } else if (flags & ui::EF_MIDDLE_MOUSE_BUTTON) {
|
| + event_type = client_area ? WM_MBUTTONDOWN : WM_NCMBUTTONDOWN;
|
| + } else if (flags & ui::EF_RIGHT_MOUSE_BUTTON) {
|
| + event_type = client_area ? WM_RBUTTONDOWN : WM_NCRBUTTONDOWN;
|
| + } else {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| +
|
| + int window_x = screen_loc.x();
|
| + int window_y = screen_loc.y();
|
| + if (client_area) {
|
| + POINT pt = { window_x, window_y };
|
| + ScreenToClient(target_window, &pt);
|
| + window_x = pt.x;
|
| + window_y = pt.y;
|
| + }
|
| +
|
| + WPARAM target = client_area ? event.native_event().wParam : nc_hit_result;
|
| + LPARAM window_coords = MAKELPARAM(window_x, window_y);
|
| + PostMessage(target_window, event_type, target, window_coords);
|
| + return;
|
| }
|
| -#else
|
| +#endif
|
| + // Non-Windows Aura or |window| is in metro mode.
|
| if (!window)
|
| return;
|
| -#endif
|
|
|
| - scoped_ptr<ui::LocatedEvent> clone;
|
| - if (event.IsMouseEvent()) {
|
| - clone.reset(new ui::MouseEvent(static_cast<const ui::MouseEvent&>(event)));
|
| - } else if (event.IsGestureEvent()) {
|
| - // TODO(rbyers): Gesture event repost is tricky to get right
|
| - // crbug.com/170987.
|
| + aura::Window* root = window->GetRootWindow();
|
| + ScreenPositionClient* spc = aura::client::GetScreenPositionClient(root);
|
| + if (!spc)
|
| return;
|
| - } else {
|
| - NOTREACHED();
|
| - return;
|
| - }
|
| - clone->set_location(screen_loc);
|
|
|
| - RepostLocatedEvent(window, *clone);
|
| -}
|
| + gfx::Point root_loc(screen_loc);
|
| + spc->ConvertPointFromScreen(root, &root_loc);
|
|
|
| + ui::MouseEvent clone(static_cast<const ui::MouseEvent&>(event));
|
| + clone.set_location(root_loc);
|
| + clone.set_root_location(root_loc);
|
| + root->GetHost()->dispatcher()->RepostEvent(clone);
|
| +}
|
|
|
| void MenuController::SetDropMenuItem(
|
| MenuItemView* new_target,
|
|
|