Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 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 "content/browser/renderer_host/legacy_render_widget_host_win.h" | 5 #include "content/browser/renderer_host/legacy_render_widget_host_win.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/win/windows_version.h" | 9 #include "base/win/windows_version.h" |
| 10 #include "content/browser/accessibility/browser_accessibility_manager_win.h" | 10 #include "content/browser/accessibility/browser_accessibility_manager_win.h" |
| 11 #include "content/browser/accessibility/browser_accessibility_win.h" | 11 #include "content/browser/accessibility/browser_accessibility_win.h" |
| 12 #include "content/public/common/content_switches.h" | 12 #include "content/public/common/content_switches.h" |
| 13 #include "ui/base/touch/touch_enabled.h" | 13 #include "ui/base/touch/touch_enabled.h" |
| 14 #include "ui/gfx/geometry/rect.h" | 14 #include "ui/gfx/geometry/rect.h" |
| 15 | 15 |
| 16 namespace { | |
| 17 | |
| 18 // This property is set on the parent window when we set capture on it. This | |
| 19 // is used to retrieve the child window whose bounds we are tracking. | |
| 20 const wchar_t kCaptureForcedOnParentByTrackingWindow[] = | |
| 21 L"CaptureForcedByTrackingWindow"; | |
| 22 | |
| 23 } // namespace | |
| 24 | |
| 16 namespace content { | 25 namespace content { |
| 17 | 26 |
| 27 WNDPROC LegacyRenderWidgetHostHWND::g_parent_original_class_proc = NULL; | |
| 28 | |
| 18 LegacyRenderWidgetHostHWND::~LegacyRenderWidgetHostHWND() { | 29 LegacyRenderWidgetHostHWND::~LegacyRenderWidgetHostHWND() { |
| 19 ::DestroyWindow(hwnd()); | 30 ::DestroyWindow(hwnd()); |
| 20 } | 31 } |
| 21 | 32 |
| 22 // static | 33 // static |
| 23 scoped_ptr<LegacyRenderWidgetHostHWND> LegacyRenderWidgetHostHWND::Create( | 34 scoped_ptr<LegacyRenderWidgetHostHWND> LegacyRenderWidgetHostHWND::Create( |
| 24 HWND parent) { | 35 HWND parent) { |
| 36 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 37 switches::kDisableLegacyIntermediateWindow)) | |
| 38 return scoped_ptr<LegacyRenderWidgetHostHWND>(); | |
| 39 | |
| 25 scoped_ptr<LegacyRenderWidgetHostHWND> legacy_window_instance; | 40 scoped_ptr<LegacyRenderWidgetHostHWND> legacy_window_instance; |
| 26 legacy_window_instance.reset(new LegacyRenderWidgetHostHWND(parent)); | 41 legacy_window_instance.reset(new LegacyRenderWidgetHostHWND(parent)); |
| 27 // If we failed to create the child, or if the switch to disable the legacy | 42 // If we failed to create the child, or if the switch to disable the legacy |
| 28 // window is passed in, then return NULL. | 43 // window is passed in, then return NULL. |
| 29 if (!::IsWindow(legacy_window_instance->hwnd()) || | 44 if (!::IsWindow(legacy_window_instance->hwnd())) |
| 30 CommandLine::ForCurrentProcess()->HasSwitch( | |
| 31 switches::kDisableLegacyIntermediateWindow)) | |
| 32 return scoped_ptr<LegacyRenderWidgetHostHWND>(); | 45 return scoped_ptr<LegacyRenderWidgetHostHWND>(); |
| 33 | 46 |
| 34 legacy_window_instance->Init(); | 47 legacy_window_instance->Init(); |
| 35 return legacy_window_instance.Pass(); | 48 return legacy_window_instance.Pass(); |
| 36 } | 49 } |
| 37 | 50 |
| 38 void LegacyRenderWidgetHostHWND::UpdateParent(HWND parent) { | 51 void LegacyRenderWidgetHostHWND::UpdateParent(HWND parent) { |
| 39 ::SetParent(hwnd(), parent); | 52 ::SetParent(hwnd(), parent); |
| 40 // If the new parent is the desktop Window, then we disable the child window | 53 // If the new parent is the desktop Window, then we disable the child window |
| 41 // to ensure that it does not receive any input events. It should not because | 54 // to ensure that it does not receive any input events. It should not because |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 Base::Create(parent, rect, L"Chrome Legacy Window", | 92 Base::Create(parent, rect, L"Chrome Legacy Window", |
| 80 WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, | 93 WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, |
| 81 WS_EX_TRANSPARENT); | 94 WS_EX_TRANSPARENT); |
| 82 } | 95 } |
| 83 | 96 |
| 84 bool LegacyRenderWidgetHostHWND::Init() { | 97 bool LegacyRenderWidgetHostHWND::Init() { |
| 85 if (base::win::GetVersion() >= base::win::VERSION_WIN7 && | 98 if (base::win::GetVersion() >= base::win::VERSION_WIN7 && |
| 86 ui::AreTouchEventsEnabled()) | 99 ui::AreTouchEventsEnabled()) |
| 87 RegisterTouchWindow(hwnd(), TWF_WANTPALM); | 100 RegisterTouchWindow(hwnd(), TWF_WANTPALM); |
| 88 | 101 |
| 102 // We superclass the parent window class. This is to ensure that we avoid | |
| 103 // messy code tracking if the window was subclassed or not. Superclassing | |
| 104 // the parent ensures that we can windows subsequently created. | |
| 105 // Note: We never unsubclass. This should be safe. | |
| 106 if (!g_parent_original_class_proc) { | |
|
sky
2014/02/12 14:36:31
Doesn't this assume the legacy hwnd always has a p
| |
| 107 g_parent_original_class_proc = reinterpret_cast<WNDPROC>( | |
| 108 ::SetClassLong(GetParent(), GCL_WNDPROC, | |
| 109 reinterpret_cast<long>(ParentWindowSuperClassProc))); | |
| 110 DCHECK(g_parent_original_class_proc); | |
| 111 // We need to subclass the first window as the super class does not take | |
| 112 // effect until a new window is created. | |
| 113 ::SetWindowLong(GetParent(), GWL_WNDPROC, | |
| 114 reinterpret_cast<long>(ParentWindowSuperClassProc)); | |
| 115 } | |
| 116 | |
| 89 HRESULT hr = ::CreateStdAccessibleObject( | 117 HRESULT hr = ::CreateStdAccessibleObject( |
| 90 hwnd(), OBJID_WINDOW, IID_IAccessible, | 118 hwnd(), OBJID_WINDOW, IID_IAccessible, |
| 91 reinterpret_cast<void **>(window_accessible_.Receive())); | 119 reinterpret_cast<void **>(window_accessible_.Receive())); |
| 92 DCHECK(SUCCEEDED(hr)); | 120 DCHECK(SUCCEEDED(hr)); |
| 93 return !!SUCCEEDED(hr); | 121 return !!SUCCEEDED(hr); |
| 94 } | 122 } |
| 95 | 123 |
| 96 LRESULT LegacyRenderWidgetHostHWND::OnEraseBkGnd(UINT message, | 124 LRESULT LegacyRenderWidgetHostHWND::OnEraseBkGnd(UINT message, |
| 97 WPARAM w_param, | 125 WPARAM w_param, |
| 98 LPARAM l_param) { | 126 LPARAM l_param) { |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 123 WPARAM w_param, | 151 WPARAM w_param, |
| 124 LPARAM l_param, | 152 LPARAM l_param, |
| 125 BOOL& handled) { | 153 BOOL& handled) { |
| 126 return ::SendMessage(GetParent(), message, w_param, l_param); | 154 return ::SendMessage(GetParent(), message, w_param, l_param); |
| 127 } | 155 } |
| 128 | 156 |
| 129 LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message, | 157 LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message, |
| 130 WPARAM w_param, | 158 WPARAM w_param, |
| 131 LPARAM l_param, | 159 LPARAM l_param, |
| 132 BOOL& handled) { | 160 BOOL& handled) { |
| 133 POINT mouse_coords; | 161 // We won't receive mouse messages when capture is with the parent window. |
| 134 mouse_coords.x = GET_X_LPARAM(l_param); | 162 // If we receive a mouse move then it means that parent capture was released. |
| 135 mouse_coords.y = GET_Y_LPARAM(l_param); | 163 // This would happen if we lost focus or if the mouse left our window bounds |
| 136 ::MapWindowPoints(hwnd(), GetParent(), &mouse_coords, 1); | 164 // and we released capture. |
| 137 return ::SendMessage(GetParent(), message, w_param, | 165 if (message == WM_MOUSEMOVE) { |
| 138 MAKELPARAM(mouse_coords.x, mouse_coords.y)); | 166 if (::GetCapture() != GetParent()) { |
| 167 ::SetCapture(GetParent()); | |
| 168 ::SetProp(GetParent(), kCaptureForcedOnParentByTrackingWindow, hwnd()); | |
| 169 } | |
| 170 } else if (message == WM_MOUSEWHEEL || message == WM_MOUSEHWHEEL) { | |
| 171 return ::SendMessage(GetParent(), message, w_param, l_param); | |
| 172 } else { | |
| 173 NOTREACHED() << "Unexpected mouse message received: " << message; | |
| 174 } | |
| 175 return 0; | |
| 139 } | 176 } |
| 140 | 177 |
| 141 LRESULT LegacyRenderWidgetHostHWND::OnMouseActivate(UINT message, | 178 LRESULT LegacyRenderWidgetHostHWND::OnMouseActivate(UINT message, |
| 142 WPARAM w_param, | 179 WPARAM w_param, |
| 143 LPARAM l_param) { | 180 LPARAM l_param) { |
| 144 // Don't pass this to DefWindowProc. That results in the WM_MOUSEACTIVATE | 181 // Don't pass this to DefWindowProc. That results in the WM_MOUSEACTIVATE |
| 145 // message going all the way to the parent which then messes up state | 182 // message going all the way to the parent which then messes up state |
| 146 // related to focused views, etc. This is because it treats this as if | 183 // related to focused views, etc. This is because it treats this as if |
| 147 // it lost activation. | 184 // it lost activation. |
| 148 // Our dummy window should not interfere with focus and activation in | 185 // Our dummy window should not interfere with focus and activation in |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 174 ::EndPaint(hwnd(), &ps); | 211 ::EndPaint(hwnd(), &ps); |
| 175 return 0; | 212 return 0; |
| 176 } | 213 } |
| 177 | 214 |
| 178 LRESULT LegacyRenderWidgetHostHWND::OnSetCursor(UINT message, | 215 LRESULT LegacyRenderWidgetHostHWND::OnSetCursor(UINT message, |
| 179 WPARAM w_param, | 216 WPARAM w_param, |
| 180 LPARAM l_param) { | 217 LPARAM l_param) { |
| 181 return 0; | 218 return 0; |
| 182 } | 219 } |
| 183 | 220 |
| 221 // static | |
| 222 LRESULT CALLBACK LegacyRenderWidgetHostHWND::ParentWindowSuperClassProc( | |
| 223 HWND window, UINT message, WPARAM w_param, LPARAM l_param) { | |
| 224 // To ensure that the LegacyRenderWidgetHostHWND is as less intrusive as | |
| 225 // possible, we set capture on the parent window when we receive a | |
| 226 // mouse move message for the LegacyRenderWidgetHostHWND hwnd. This ensures | |
| 227 // that subsequent mouse messages go to the parent. We need to release this | |
| 228 // forced capture on the parent when the mouse cursor leaves the bounds of | |
| 229 // the LegacyRenderWidgetHostHWND window which is identified by the | |
| 230 // tracking_window local variable below. We only do this when no mouse | |
| 231 // buttons are down as in that case capture is released by code in the | |
| 232 // default parent mouse event handling. | |
| 233 const int mouse_down_flags = | |
| 234 MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | MK_XBUTTON1 | MK_XBUTTON2; | |
| 235 if (message == WM_MOUSEMOVE && ::GetCapture() == window && | |
| 236 !(w_param & mouse_down_flags)) { | |
| 237 HWND tracking_window = reinterpret_cast<HWND>(::GetProp(window, | |
| 238 kCaptureForcedOnParentByTrackingWindow)); | |
| 239 if (::IsWindow(tracking_window)) { | |
| 240 POINT pt = {0}; | |
| 241 pt.x = GET_X_LPARAM(l_param); | |
| 242 pt.y = GET_Y_LPARAM(l_param); | |
| 243 ::ClientToScreen(window, &pt); | |
| 244 | |
| 245 RECT window_rect = {0}; | |
| 246 ::GetWindowRect(tracking_window, &window_rect); | |
| 247 if (!::PtInRect(&window_rect, pt) || | |
| 248 ::WindowFromPoint(pt) != tracking_window) { | |
| 249 ::ReleaseCapture(); | |
| 250 ::RemoveProp(window, kCaptureForcedOnParentByTrackingWindow); | |
| 251 } | |
| 252 } | |
| 253 } | |
| 254 DCHECK(g_parent_original_class_proc); | |
| 255 return ::CallWindowProc(g_parent_original_class_proc, window, message, | |
| 256 w_param, l_param); | |
| 257 } | |
| 258 | |
| 184 } // namespace content | 259 } // namespace content |
| OLD | NEW |