Index: content/browser/renderer_host/legacy_render_widget_host_win.cc |
=================================================================== |
--- content/browser/renderer_host/legacy_render_widget_host_win.cc (revision 249762) |
+++ content/browser/renderer_host/legacy_render_widget_host_win.cc (working copy) |
@@ -13,8 +13,19 @@ |
#include "ui/base/touch/touch_enabled.h" |
#include "ui/gfx/geometry/rect.h" |
+namespace { |
+ |
+// This property is set on the parent window when we set capture on it. This |
+// is used to retrieve the child window whose bounds we are tracking. |
+const wchar_t kCaptureForcedOnParentByTrackingWindow[] = |
+ L"CaptureForcedByTrackingWindow"; |
+ |
+} // namespace |
+ |
namespace content { |
+WNDPROC LegacyRenderWidgetHostHWND::g_parent_original_class_proc = NULL; |
+ |
LegacyRenderWidgetHostHWND::~LegacyRenderWidgetHostHWND() { |
::DestroyWindow(hwnd()); |
} |
@@ -22,13 +33,15 @@ |
// 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(); |
@@ -86,6 +99,21 @@ |
ui::AreTouchEventsEnabled()) |
RegisterTouchWindow(hwnd(), TWF_WANTPALM); |
+ // We superclass the parent window class. This is to ensure that we avoid |
+ // messy code tracking if the window was subclassed or not. Superclassing |
+ // the parent ensures that we can windows subsequently created. |
+ // Note: We never unsubclass. This should be safe. |
+ if (!g_parent_original_class_proc) { |
sky
2014/02/12 14:36:31
Doesn't this assume the legacy hwnd always has a p
|
+ g_parent_original_class_proc = reinterpret_cast<WNDPROC>( |
+ ::SetClassLong(GetParent(), GCL_WNDPROC, |
+ reinterpret_cast<long>(ParentWindowSuperClassProc))); |
+ DCHECK(g_parent_original_class_proc); |
+ // We need to subclass the first window as the super class does not take |
+ // effect until a new window is created. |
+ ::SetWindowLong(GetParent(), GWL_WNDPROC, |
+ reinterpret_cast<long>(ParentWindowSuperClassProc)); |
+ } |
+ |
HRESULT hr = ::CreateStdAccessibleObject( |
hwnd(), OBJID_WINDOW, IID_IAccessible, |
reinterpret_cast<void **>(window_accessible_.Receive())); |
@@ -130,12 +158,21 @@ |
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)); |
+ // We won't receive mouse messages when capture is with the parent window. |
+ // If we receive a mouse move then it means that parent capture was released. |
+ // This would happen if we lost focus or if the mouse left our window bounds |
+ // and we released capture. |
+ if (message == WM_MOUSEMOVE) { |
+ if (::GetCapture() != GetParent()) { |
+ ::SetCapture(GetParent()); |
+ ::SetProp(GetParent(), kCaptureForcedOnParentByTrackingWindow, hwnd()); |
+ } |
+ } else if (message == WM_MOUSEWHEEL || message == WM_MOUSEHWHEEL) { |
+ return ::SendMessage(GetParent(), message, w_param, l_param); |
+ } else { |
+ NOTREACHED() << "Unexpected mouse message received: " << message; |
+ } |
+ return 0; |
} |
LRESULT LegacyRenderWidgetHostHWND::OnMouseActivate(UINT message, |
@@ -181,4 +218,42 @@ |
return 0; |
} |
+// static |
+LRESULT CALLBACK LegacyRenderWidgetHostHWND::ParentWindowSuperClassProc( |
+ HWND window, UINT message, WPARAM w_param, LPARAM l_param) { |
+ // To ensure that the LegacyRenderWidgetHostHWND is as less intrusive as |
+ // possible, we set capture on the parent window when we receive a |
+ // mouse move message for the LegacyRenderWidgetHostHWND hwnd. This ensures |
+ // that subsequent mouse messages go to the parent. We need to release this |
+ // forced capture on the parent when the mouse cursor leaves the bounds of |
+ // the LegacyRenderWidgetHostHWND window which is identified by the |
+ // tracking_window local variable below. We only do this when no mouse |
+ // buttons are down as in that case capture is released by code in the |
+ // default parent mouse event handling. |
+ const int mouse_down_flags = |
+ MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | MK_XBUTTON1 | MK_XBUTTON2; |
+ if (message == WM_MOUSEMOVE && ::GetCapture() == window && |
+ !(w_param & mouse_down_flags)) { |
+ HWND tracking_window = reinterpret_cast<HWND>(::GetProp(window, |
+ kCaptureForcedOnParentByTrackingWindow)); |
+ if (::IsWindow(tracking_window)) { |
+ POINT pt = {0}; |
+ pt.x = GET_X_LPARAM(l_param); |
+ pt.y = GET_Y_LPARAM(l_param); |
+ ::ClientToScreen(window, &pt); |
+ |
+ RECT window_rect = {0}; |
+ ::GetWindowRect(tracking_window, &window_rect); |
+ if (!::PtInRect(&window_rect, pt) || |
+ ::WindowFromPoint(pt) != tracking_window) { |
+ ::ReleaseCapture(); |
+ ::RemoveProp(window, kCaptureForcedOnParentByTrackingWindow); |
+ } |
+ } |
+ } |
+ DCHECK(g_parent_original_class_proc); |
+ return ::CallWindowProc(g_parent_original_class_proc, window, message, |
+ w_param, l_param); |
+} |
+ |
} // namespace content |