Chromium Code Reviews| 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 |