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
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/legacy_render_widget_host_win.h"
7 #include "base/command_line.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/win/windows_version.h"
10 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
11 #include "content/browser/accessibility/browser_accessibility_win.h"
12 #include "content/public/common/content_switches.h"
13 #include "ui/base/touch/touch_enabled.h"
14 #include "ui/base/view_prop.h"
15 #include "ui/base/win/window_event_target.h"
16 #include "ui/gfx/geometry/rect.h"
20 LegacyRenderWidgetHostHWND::~LegacyRenderWidgetHostHWND() {
21 ::DestroyWindow(hwnd());
25 scoped_ptr
<LegacyRenderWidgetHostHWND
> LegacyRenderWidgetHostHWND::Create(
27 // content_unittests passes in the desktop window as the parent. We allow
28 // the LegacyRenderWidgetHostHWND instance to be created in this case for
29 // these tests to pass.
30 if (CommandLine::ForCurrentProcess()->HasSwitch(
31 switches::kDisableLegacyIntermediateWindow
) ||
32 (!GetWindowEventTarget(parent
) && parent
!= ::GetDesktopWindow()))
33 return scoped_ptr
<LegacyRenderWidgetHostHWND
>();
35 scoped_ptr
<LegacyRenderWidgetHostHWND
> legacy_window_instance
;
36 legacy_window_instance
.reset(new LegacyRenderWidgetHostHWND(parent
));
37 // If we failed to create the child, or if the switch to disable the legacy
38 // window is passed in, then return NULL.
39 if (!::IsWindow(legacy_window_instance
->hwnd()))
40 return scoped_ptr
<LegacyRenderWidgetHostHWND
>();
42 legacy_window_instance
->Init();
43 return legacy_window_instance
.Pass();
46 void LegacyRenderWidgetHostHWND::UpdateParent(HWND parent
) {
47 ::SetParent(hwnd(), parent
);
48 // If the new parent is the desktop Window, then we disable the child window
49 // to ensure that it does not receive any input events. It should not because
50 // of WS_EX_TRANSPARENT. This is only for safety.
51 if (parent
== ::GetDesktopWindow()) {
52 ::EnableWindow(hwnd(), FALSE
);
54 ::EnableWindow(hwnd(), TRUE
);
58 HWND
LegacyRenderWidgetHostHWND::GetParent() {
59 return ::GetParent(hwnd());
62 void LegacyRenderWidgetHostHWND::OnManagerDeleted() {
66 void LegacyRenderWidgetHostHWND::Show() {
67 ::ShowWindow(hwnd(), SW_SHOW
);
70 void LegacyRenderWidgetHostHWND::Hide() {
71 ::ShowWindow(hwnd(), SW_HIDE
);
74 void LegacyRenderWidgetHostHWND::SetBounds(const gfx::Rect
& bounds
) {
75 ::SetWindowPos(hwnd(), NULL
, bounds
.x(), bounds
.y(), bounds
.width(),
79 void LegacyRenderWidgetHostHWND::OnFinalMessage(HWND hwnd
) {
81 manager_
->OnAccessibleHwndDeleted();
84 LegacyRenderWidgetHostHWND::LegacyRenderWidgetHostHWND(HWND parent
)
86 mouse_tracking_enabled_(false) {
88 Base::Create(parent
, rect
, L
"Chrome Legacy Window",
89 WS_CHILDWINDOW
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
,
93 bool LegacyRenderWidgetHostHWND::Init() {
94 if (base::win::GetVersion() >= base::win::VERSION_WIN7
&&
95 ui::AreTouchEventsEnabled())
96 RegisterTouchWindow(hwnd(), TWF_WANTPALM
);
98 HRESULT hr
= ::CreateStdAccessibleObject(
99 hwnd(), OBJID_WINDOW
, IID_IAccessible
,
100 reinterpret_cast<void **>(window_accessible_
.Receive()));
101 DCHECK(SUCCEEDED(hr
));
102 return !!SUCCEEDED(hr
);
106 ui::WindowEventTarget
* LegacyRenderWidgetHostHWND::GetWindowEventTarget(
108 return reinterpret_cast<ui::WindowEventTarget
*>(ui::ViewProp::GetValue(
109 parent
, ui::WindowEventTarget::kWin32InputEventTarget
));
112 LRESULT
LegacyRenderWidgetHostHWND::OnEraseBkGnd(UINT message
,
118 LRESULT
LegacyRenderWidgetHostHWND::OnGetObject(UINT message
,
121 if (OBJID_CLIENT
!= l_param
|| !manager_
)
122 return static_cast<LRESULT
>(0L);
124 base::win::ScopedComPtr
<IAccessible
> root(
125 manager_
->GetRoot()->ToBrowserAccessibilityWin());
126 return LresultFromObject(IID_IAccessible
, w_param
,
127 static_cast<IAccessible
*>(root
.Detach()));
130 // We send keyboard/mouse/touch messages to the parent window via SendMessage.
131 // While this works, this has the side effect of converting input messages into
132 // sent messages which changes their priority and could technically result
133 // in these messages starving other messages in the queue. Additionally
134 // keyboard/mouse hooks would not see these messages. The alternative approach
135 // is to set and release capture as needed on the parent to ensure that it
136 // receives all mouse events. However that was shelved due to possible issues
137 // with capture changes.
138 LRESULT
LegacyRenderWidgetHostHWND::OnKeyboardRange(UINT message
,
142 if (GetWindowEventTarget(GetParent())) {
143 return GetWindowEventTarget(GetParent())->HandleKeyboardMessage(
144 message
, w_param
, l_param
);
149 LRESULT
LegacyRenderWidgetHostHWND::OnMouseRange(UINT message
,
153 if (message
== WM_MOUSEMOVE
) {
154 if (!mouse_tracking_enabled_
) {
155 mouse_tracking_enabled_
= true;
157 tme
.cbSize
= sizeof(tme
);
158 tme
.dwFlags
= TME_LEAVE
;
159 tme
.hwndTrack
= hwnd();
161 TrackMouseEvent(&tme
);
164 // The offsets for WM_NCXXX and WM_MOUSEWHEEL and WM_MOUSEHWHEEL messages are
165 // in screen coordinates. We should not be converting them to parent
167 if ((message
>= WM_MOUSEFIRST
&& message
<= WM_MOUSELAST
) &&
168 (message
!= WM_MOUSEWHEEL
&& message
!= WM_MOUSEHWHEEL
)) {
170 mouse_coords
.x
= GET_X_LPARAM(l_param
);
171 mouse_coords
.y
= GET_Y_LPARAM(l_param
);
172 ::MapWindowPoints(hwnd(), GetParent(), &mouse_coords
, 1);
173 l_param
= MAKELPARAM(mouse_coords
.x
, mouse_coords
.y
);
175 if (GetWindowEventTarget(GetParent())) {
176 return GetWindowEventTarget(GetParent())->HandleMouseMessage(
177 message
, w_param
, l_param
);
182 LRESULT
LegacyRenderWidgetHostHWND::OnMouseLeave(UINT message
,
185 mouse_tracking_enabled_
= false;
186 if ((::GetCapture() != GetParent()) && GetWindowEventTarget(GetParent())) {
187 // We should send a WM_MOUSELEAVE to the parent window only if the mouse
188 // has moved outside the bounds of the parent.
190 ::GetCursorPos(&cursor_pos
);
191 if (::WindowFromPoint(cursor_pos
) != GetParent()) {
192 return GetWindowEventTarget(GetParent())->HandleMouseMessage(
193 message
, w_param
, l_param
);
199 LRESULT
LegacyRenderWidgetHostHWND::OnMouseActivate(UINT message
,
202 // Don't pass this to DefWindowProc. That results in the WM_MOUSEACTIVATE
203 // message going all the way to the parent which then messes up state
204 // related to focused views, etc. This is because it treats this as if
205 // it lost activation.
206 // Our dummy window should not interfere with focus and activation in
207 // the parent. Return MA_ACTIVATE here ensures that focus state in the parent
208 // is preserved. The only exception is if the parent was created with the
209 // WS_EX_NOACTIVATE style.
210 if (::GetWindowLong(GetParent(), GWL_EXSTYLE
) & WS_EX_NOACTIVATE
)
211 return MA_NOACTIVATE
;
215 LRESULT
LegacyRenderWidgetHostHWND::OnTouch(UINT message
,
218 if (GetWindowEventTarget(GetParent())) {
219 return GetWindowEventTarget(GetParent())->HandleTouchMessage(
220 message
, w_param
, l_param
);
225 LRESULT
LegacyRenderWidgetHostHWND::OnScroll(UINT message
,
228 if (GetWindowEventTarget(GetParent())) {
229 return GetWindowEventTarget(GetParent())->HandleScrollMessage(
230 message
, w_param
, l_param
);
235 LRESULT
LegacyRenderWidgetHostHWND::OnNCHitTest(UINT message
,
238 if (GetWindowEventTarget(GetParent())) {
239 LRESULT hit_test
= GetWindowEventTarget(
240 GetParent())->HandleNcHitTestMessage(message
, w_param
, l_param
);
241 // If the parent returns HTNOWHERE which can happen for popup windows, etc
242 // we return HTCLIENT.
243 if (hit_test
== HTNOWHERE
)
250 LRESULT
LegacyRenderWidgetHostHWND::OnNCPaint(UINT message
,
256 LRESULT
LegacyRenderWidgetHostHWND::OnPaint(UINT message
,
259 PAINTSTRUCT ps
= {0};
260 ::BeginPaint(hwnd(), &ps
);
261 ::EndPaint(hwnd(), &ps
);
265 LRESULT
LegacyRenderWidgetHostHWND::OnSetCursor(UINT message
,
271 LRESULT
LegacyRenderWidgetHostHWND::OnNCCalcSize(UINT message
,
274 // Prevent scrollbars, etc from drawing.
278 LRESULT
LegacyRenderWidgetHostHWND::OnSize(UINT message
,
281 // Certain trackpad drivers on Windows have bugs where in they don't generate
282 // WM_MOUSEWHEEL messages for the trackpoint and trackpad scrolling gestures
283 // unless there is an entry for Chrome with the class name of the Window.
284 // Additionally others check if the window WS_VSCROLL/WS_HSCROLL styles and
285 // generate the legacy WM_VSCROLL/WM_HSCROLL messages.
286 // We add these styles to ensure that trackpad/trackpoint scrolling
288 long current_style
= ::GetWindowLong(hwnd(), GWL_STYLE
);
289 ::SetWindowLong(hwnd(), GWL_STYLE
,
290 current_style
| WS_VSCROLL
| WS_HSCROLL
);
294 } // namespace content