Commit b9f658bc authored by ananta@chromium.org's avatar ananta@chromium.org

Don't track mouse events in HWNDMessageHandler when they are forwarded by the...

Don't track mouse events in HWNDMessageHandler when they are forwarded by the LegacyRenderWidgetHostHWND class.

We use the TrackMouseEvent API in HWNDMessageHandler when we receive a WM_MOUSEMOVE message. This is to ensure that Windows sends us a WM_MOUSELEAVE
message when the cursor leaves our window bounds. Tooltips use this message to dismiss the tooltip for e.g.

Technically when the mouse enters the child window (LegacyRenderWidgetHostHWND) it has left the parent window. We end up getting WM_MOUSELEAVE messages
for WM_MOUSEMOVES which are sent to the parent window by the LegacyRenderWidgetHostHWND class causing tooltips to not show up and some other bugs.

Fixes as below:-
1. Add a special marker in the hiword of the WPARAM in WM_MOUSEMOVE messages sent by the LegacyRenderWidgetHostHWND class. This is to indicate to the parent
   that it should not track these mouse moves.
2. When we lose activation in HWNDMessageHandler we post a dummy WM_MOUSELEAVE message. This is enable tooltips if they were visible to be dismissed for e.g
   Based on code inspection a WM_MOUSELEAVE message should not cause any issues.
3. Forward WM_MOUSEWHEEL and WM_MOUSEHWHEEL messages via SendMessage to the parent without mucking with the parameters. The offsets are in screen coordinates in
   these messages.
4. Reposting events today fails when we click on the (LegacyRenderWidgetHostHWND) HWND. This is because the current code attempts to find an aura Window at the
   location which fails. I changed the RepostLocatedEvent function to allow a NULL window parameter on Windows. We attempt to forward the event to the HWND at the
   current location if it is on the same thread.

BUG=342323,342298,342299,341879,343246
R=cpu@chromium.org, sky@chromium.org, sky

Review URL: https://codereview.chromium.org/159713012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@251190 0039d316-1c4b-4281-b951-d872f2087c98
parent 54ddea47
......@@ -129,6 +129,9 @@ BASE_EXPORT bool DismissVirtualKeyboard();
// Returns true if the machine is enrolled to a domain.
BASE_EXPORT bool IsEnrolledToDomain();
// Marker added to certain WM_MOUSEMOVE messages.
#define SPECIAL_MOUSEMOVE_NOT_TO_BE_TRACKED 0xbeef
} // namespace win
} // namespace base
......
......@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/win/windows_version.h"
#include "base/win/win_util.h"
#include "content/browser/accessibility/browser_accessibility_manager_win.h"
#include "content/browser/accessibility/browser_accessibility_win.h"
#include "content/public/common/content_switches.h"
......@@ -22,13 +23,15 @@ LegacyRenderWidgetHostHWND::~LegacyRenderWidgetHostHWND() {
// static
scoped_ptr<LegacyRenderWidgetHostHWND> LegacyRenderWidgetHostHWND::Create(
HWND parent) {
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableLegacyIntermediateWindow))
return scoped_ptr<LegacyRenderWidgetHostHWND>();
scoped_ptr<LegacyRenderWidgetHostHWND> legacy_window_instance;
legacy_window_instance.reset(new LegacyRenderWidgetHostHWND(parent));
// If we failed to create the child, or if the switch to disable the legacy
// window is passed in, then return NULL.
if (!::IsWindow(legacy_window_instance->hwnd()) ||
CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableLegacyIntermediateWindow))
if (!::IsWindow(legacy_window_instance->hwnd()))
return scoped_ptr<LegacyRenderWidgetHostHWND>();
legacy_window_instance->Init();
......@@ -74,7 +77,8 @@ void LegacyRenderWidgetHostHWND::OnFinalMessage(HWND hwnd) {
}
LegacyRenderWidgetHostHWND::LegacyRenderWidgetHostHWND(HWND parent)
: manager_(NULL) {
: manager_(NULL),
mouse_tracking_enabled_(false) {
RECT rect = {0};
Base::Create(parent, rect, L"Chrome Legacy Window",
WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
......@@ -130,12 +134,50 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
WPARAM w_param,
LPARAM l_param,
BOOL& handled) {
POINT mouse_coords;
mouse_coords.x = GET_X_LPARAM(l_param);
mouse_coords.y = GET_Y_LPARAM(l_param);
::MapWindowPoints(hwnd(), GetParent(), &mouse_coords, 1);
return ::SendMessage(GetParent(), message, w_param,
MAKELPARAM(mouse_coords.x, mouse_coords.y));
// Mark the WM_MOUSEMOVE message with a special flag in the high word of
// the WPARAM.
// The parent window has code to track mouse events, i.e to detect if the
// cursor left the bounds of the parent window. Technically entering a child
// window indicates that the cursor left the parent window.
// To ensure that the parent does not turn on tracking for the WM_MOUSEMOVE
// messages sent from us, we flag this in the WPARAM and track the mouse for
// our window to send the WM_MOUSELEAVE if needed to the parent.
if (message == WM_MOUSEMOVE) {
if (!mouse_tracking_enabled_) {
mouse_tracking_enabled_ = true;
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hwnd();
tme.dwHoverTime = 0;
TrackMouseEvent(&tme);
}
w_param = MAKEWPARAM(LOWORD(w_param), SPECIAL_MOUSEMOVE_NOT_TO_BE_TRACKED);
}
// The offsets in mouse wheel messages are in screen coordinates. We should
// not be converting them to parent coordinates.
if (message != WM_MOUSEWHEEL && message != WM_MOUSEHWHEEL) {
POINT mouse_coords;
mouse_coords.x = GET_X_LPARAM(l_param);
mouse_coords.y = GET_Y_LPARAM(l_param);
::MapWindowPoints(hwnd(), GetParent(), &mouse_coords, 1);
l_param = MAKELPARAM(mouse_coords.x, mouse_coords.y);
}
return ::SendMessage(GetParent(), message, w_param, l_param);
}
LRESULT LegacyRenderWidgetHostHWND::OnMouseLeave(UINT message,
WPARAM w_param,
LPARAM l_param) {
mouse_tracking_enabled_ = false;
// We should send a WM_MOUSELEAVE to the parent window only if the mouse has
// moved outside the bounds of the parent.
POINT cursor_pos;
::GetCursorPos(&cursor_pos);
if (::WindowFromPoint(cursor_pos) != GetParent())
return ::SendMessage(GetParent(), message, w_param, l_param);
return 0;
}
LRESULT LegacyRenderWidgetHostHWND::OnMouseActivate(UINT message,
......
......@@ -67,6 +67,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
MESSAGE_HANDLER_EX(WM_NCPAINT, OnNCPaint)
MESSAGE_HANDLER_EX(WM_ERASEBKGND, OnEraseBkGnd)
MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
MESSAGE_HANDLER_EX(WM_MOUSELEAVE, OnMouseLeave)
MESSAGE_HANDLER_EX(WM_MOUSEACTIVATE, OnMouseActivate)
MESSAGE_HANDLER_EX(WM_SETCURSOR, OnSetCursor)
MESSAGE_HANDLER_EX(WM_TOUCH, OnTouch)
......@@ -107,6 +108,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
LRESULT OnGetObject(UINT message, WPARAM w_param, LPARAM l_param);
LRESULT OnKeyboardRange(UINT message, WPARAM w_param, LPARAM l_param,
BOOL& handled);
LRESULT OnMouseLeave(UINT message, WPARAM w_param, LPARAM l_param);
LRESULT OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param,
BOOL& handled);
LRESULT OnMouseActivate(UINT message, WPARAM w_param, LPARAM l_param);
......@@ -119,6 +121,9 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
content::BrowserAccessibilityManagerWin* manager_;
base::win::ScopedComPtr<IAccessible> window_accessible_;
// Set to true if we turned on mouse tracking.
bool mouse_tracking_enabled_;
DISALLOW_COPY_AND_ASSIGN(LegacyRenderWidgetHostHWND);
};
......
......@@ -2130,16 +2130,15 @@ void MenuController::RepostEvent(SubmenuView* source,
gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view);
gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc);
if (!window)
return;
// 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) {
if (view && window) {
DWORD view_tid = GetWindowThreadProcessId(HWNDForNativeView(view), NULL);
if (view_tid != GetWindowThreadProcessId(HWNDForNativeView(window), NULL)) {
// Even though we have mouse capture, windows generates a mouse event if
......@@ -2149,6 +2148,9 @@ void MenuController::RepostEvent(SubmenuView* source,
return;
}
}
#else
if (!window)
return;
#endif
scoped_ptr<ui::LocatedEvent> clone;
......
......@@ -17,6 +17,8 @@ namespace views {
// Reposts a located event natively. Returns false when |event| could not be
// reposted. |event| should be in screen coordinates. |window| is the target
// window that the event will be forwarded to. Only some events are supported.
// On Windows |window| can be NULL, in which case the event is forwarded to
// the HWND at the current location if it is on the same thread.
VIEWS_EXPORT bool RepostLocatedEvent(gfx::NativeWindow window,
const ui::LocatedEvent& event);
......
......@@ -18,16 +18,26 @@ namespace views {
bool RepostLocatedEvent(gfx::NativeWindow window,
const ui::LocatedEvent& event) {
if (!window)
return false;
#if defined(OS_WIN)
if (ViewsDelegate::views_delegate &&
!ViewsDelegate::views_delegate->IsWindowInMetro(window)) {
return RepostLocatedEventWin(
window->GetDispatcher()->host()->GetAcceleratedWidget(), event);
// On Windows, if the |window| parameter is NULL, then we attempt to repost
// the event to the window at the current location, if it is on the current
// thread.
HWND target_window = NULL;
if (!window) {
target_window = ::WindowFromPoint(event.location().ToPOINT());
if (::GetWindowThreadProcessId(target_window, NULL) !=
::GetCurrentThreadId())
return false;
} else {
if (ViewsDelegate::views_delegate &&
!ViewsDelegate::views_delegate->IsWindowInMetro(window))
target_window = window->GetDispatcher()->host()->GetAcceleratedWidget();
}
return RepostLocatedEventWin(target_window, event);
#endif
if (!window)
return false;
aura::Window* root_window = window->GetRootWindow();
gfx::Point root_loc(event.location());
......
......@@ -1628,7 +1628,6 @@ LRESULT HWNDMessageHandler::OnMouseRange(UINT message,
// be WM_RBUTTONUP instead of WM_NCRBUTTONUP.
SetCapture();
}
MSG msg = { hwnd(), message, w_param, l_param, GetMessageTime(),
{ CR_GET_X_LPARAM(l_param), CR_GET_Y_LPARAM(l_param) } };
ui::MouseEvent event(msg);
......@@ -1638,7 +1637,10 @@ LRESULT HWNDMessageHandler::OnMouseRange(UINT message,
if (!(event.flags() & ui::EF_IS_NON_CLIENT))
delegate_->HandleTooltipMouseMove(message, w_param, l_param);
if (event.type() == ui::ET_MOUSE_MOVED && !HasCapture()) {
// Certain child windows forward mouse events to us. We don't want to track
// these mouse moves as the child window will also send us a WM_MOUSELEAVE.
if (event.type() == ui::ET_MOUSE_MOVED && !HasCapture() &&
HIWORD(w_param) != SPECIAL_MOUSEMOVE_NOT_TO_BE_TRACKED) {
// Windows only fires WM_MOUSELEAVE events if the application begins
// "tracking" mouse events for a given HWND during WM_MOUSEMOVE events.
// We need to call |TrackMouseEvents| to listen for WM_MOUSELEAVE.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment