e4f603f0feb475c100332a997c237ef4be2fdb9e
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / legacy_render_widget_host_win.cc
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.
4
5 #include "content/browser/renderer_host/legacy_render_widget_host_win.h"
6
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/internal_constants.h"
16 #include "ui/base/win/window_event_target.h"
17 #include "ui/gfx/geometry/rect.h"
18
19 namespace content {
20
21 LegacyRenderWidgetHostHWND::~LegacyRenderWidgetHostHWND() {
22   ::DestroyWindow(hwnd());
23 }
24
25 // static
26 scoped_ptr<LegacyRenderWidgetHostHWND> LegacyRenderWidgetHostHWND::Create(
27     HWND parent) {
28   // content_unittests passes in the desktop window as the parent. We allow
29   // the LegacyRenderWidgetHostHWND instance to be created in this case for
30   // these tests to pass.
31   if (CommandLine::ForCurrentProcess()->HasSwitch(
32           switches::kDisableLegacyIntermediateWindow) ||
33       (!GetWindowEventTarget(parent) && parent != ::GetDesktopWindow()))
34     return scoped_ptr<LegacyRenderWidgetHostHWND>();
35
36   scoped_ptr<LegacyRenderWidgetHostHWND> legacy_window_instance;
37   legacy_window_instance.reset(new LegacyRenderWidgetHostHWND(parent));
38   // If we failed to create the child, or if the switch to disable the legacy
39   // window is passed in, then return NULL.
40   if (!::IsWindow(legacy_window_instance->hwnd()))
41     return scoped_ptr<LegacyRenderWidgetHostHWND>();
42
43   legacy_window_instance->Init();
44   return legacy_window_instance.Pass();
45 }
46
47 void LegacyRenderWidgetHostHWND::UpdateParent(HWND parent) {
48   ::SetParent(hwnd(), parent);
49   // If the new parent is the desktop Window, then we disable the child window
50   // to ensure that it does not receive any input events. It should not because
51   // of WS_EX_TRANSPARENT. This is only for safety.
52   if (parent == ::GetDesktopWindow()) {
53     ::EnableWindow(hwnd(), FALSE);
54   } else {
55     ::EnableWindow(hwnd(), TRUE);
56   }
57 }
58
59 HWND LegacyRenderWidgetHostHWND::GetParent() {
60   return ::GetParent(hwnd());
61 }
62
63 void LegacyRenderWidgetHostHWND::OnManagerDeleted() {
64   manager_ = NULL;
65 }
66
67 void LegacyRenderWidgetHostHWND::Show() {
68   ::ShowWindow(hwnd(), SW_SHOW);
69 }
70
71 void LegacyRenderWidgetHostHWND::Hide() {
72   ::ShowWindow(hwnd(), SW_HIDE);
73 }
74
75 void LegacyRenderWidgetHostHWND::SetBounds(const gfx::Rect& bounds) {
76   ::SetWindowPos(hwnd(), NULL, bounds.x(), bounds.y(), bounds.width(),
77                   bounds.height(), 0);
78 }
79
80 void LegacyRenderWidgetHostHWND::OnFinalMessage(HWND hwnd) {
81   if (manager_)
82     manager_->OnAccessibleHwndDeleted();
83 }
84
85 LegacyRenderWidgetHostHWND::LegacyRenderWidgetHostHWND(HWND parent)
86     : manager_(NULL),
87       mouse_tracking_enabled_(false) {
88   RECT rect = {0};
89   Base::Create(parent, rect, L"Chrome Legacy Window",
90                WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
91                WS_EX_TRANSPARENT);
92 }
93
94 bool LegacyRenderWidgetHostHWND::Init() {
95   if (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
96       ui::AreTouchEventsEnabled())
97     RegisterTouchWindow(hwnd(), TWF_WANTPALM);
98
99   HRESULT hr = ::CreateStdAccessibleObject(
100       hwnd(), OBJID_WINDOW, IID_IAccessible,
101       reinterpret_cast<void **>(window_accessible_.Receive()));
102   DCHECK(SUCCEEDED(hr));
103   return !!SUCCEEDED(hr);
104 }
105
106 // static
107 ui::WindowEventTarget* LegacyRenderWidgetHostHWND::GetWindowEventTarget(
108     HWND parent) {
109   return reinterpret_cast<ui::WindowEventTarget*>(ui::ViewProp::GetValue(
110       parent, ui::WindowEventTarget::kWin32InputEventTarget));
111 }
112
113 LRESULT LegacyRenderWidgetHostHWND::OnEraseBkGnd(UINT message,
114                                                  WPARAM w_param,
115                                                  LPARAM l_param) {
116   return 1;
117 }
118
119 LRESULT LegacyRenderWidgetHostHWND::OnGetObject(UINT message,
120                                                 WPARAM w_param,
121                                                 LPARAM l_param) {
122   if (OBJID_CLIENT != l_param || !manager_)
123     return static_cast<LRESULT>(0L);
124
125   base::win::ScopedComPtr<IAccessible> root(
126       manager_->GetRoot()->ToBrowserAccessibilityWin());
127   return LresultFromObject(IID_IAccessible, w_param,
128       static_cast<IAccessible*>(root.Detach()));
129 }
130
131 // We send keyboard/mouse/touch messages to the parent window via SendMessage.
132 // While this works, this has the side effect of converting input messages into
133 // sent messages which changes their priority and could technically result
134 // in these messages starving other messages in the queue. Additionally
135 // keyboard/mouse hooks would not see these messages. The alternative approach
136 // is to set and release capture as needed on the parent to ensure that it
137 // receives all mouse events. However that was shelved due to possible issues
138 // with capture changes.
139 LRESULT LegacyRenderWidgetHostHWND::OnKeyboardRange(UINT message,
140                                                     WPARAM w_param,
141                                                     LPARAM l_param,
142                                                     BOOL& handled) {
143   if (GetWindowEventTarget(GetParent())) {
144     return GetWindowEventTarget(GetParent())->HandleKeyboardMessage(
145         message, w_param, l_param);
146   }
147   return 0;
148 }
149
150 LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
151                                                  WPARAM w_param,
152                                                  LPARAM l_param,
153                                                  BOOL& handled) {
154   if (message == WM_MOUSEMOVE) {
155     if (!mouse_tracking_enabled_) {
156       mouse_tracking_enabled_ = true;
157       TRACKMOUSEEVENT tme;
158       tme.cbSize = sizeof(tme);
159       tme.dwFlags = TME_LEAVE;
160       tme.hwndTrack = hwnd();
161       tme.dwHoverTime = 0;
162       TrackMouseEvent(&tme);
163     }
164   }
165   // The offsets for WM_NCXXX and WM_MOUSEWHEEL and WM_MOUSEHWHEEL messages are
166   // in screen coordinates. We should not be converting them to parent
167   // coordinates.
168   if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) &&
169       (message != WM_MOUSEWHEEL && message != WM_MOUSEHWHEEL)) {
170     POINT mouse_coords;
171     mouse_coords.x = GET_X_LPARAM(l_param);
172     mouse_coords.y = GET_Y_LPARAM(l_param);
173     ::MapWindowPoints(hwnd(), GetParent(), &mouse_coords, 1);
174     l_param = MAKELPARAM(mouse_coords.x, mouse_coords.y);
175   }
176   if (GetWindowEventTarget(GetParent())) {
177     return GetWindowEventTarget(GetParent())->HandleMouseMessage(
178         message, w_param, l_param);
179   }
180   return 0;
181 }
182
183 LRESULT LegacyRenderWidgetHostHWND::OnMouseLeave(UINT message,
184                                                  WPARAM w_param,
185                                                  LPARAM l_param) {
186   mouse_tracking_enabled_ = false;
187   if ((::GetCapture() != GetParent()) && GetWindowEventTarget(GetParent())) {
188     // We should send a WM_MOUSELEAVE to the parent window only if the mouse
189     // has moved outside the bounds of the parent.
190     POINT cursor_pos;
191     ::GetCursorPos(&cursor_pos);
192     if (::WindowFromPoint(cursor_pos) != GetParent()) {
193       return GetWindowEventTarget(GetParent())->HandleMouseMessage(
194           message, w_param, l_param);
195     }
196   }
197   return 0;
198 }
199
200 LRESULT LegacyRenderWidgetHostHWND::OnMouseActivate(UINT message,
201                                                     WPARAM w_param,
202                                                     LPARAM l_param) {
203   // Don't pass this to DefWindowProc. That results in the WM_MOUSEACTIVATE
204   // message going all the way to the parent which then messes up state
205   // related to focused views, etc. This is because it treats this as if
206   // it lost activation.
207   // Our dummy window should not interfere with focus and activation in
208   // the parent. Return MA_ACTIVATE here ensures that focus state in the parent
209   // is preserved. The only exception is if the parent was created with the
210   // WS_EX_NOACTIVATE style.
211   if (::GetWindowLong(GetParent(), GWL_EXSTYLE) & WS_EX_NOACTIVATE)
212     return MA_NOACTIVATE;
213   // On Windows, if we select the menu item by touch and if the window at the
214   // location is another window on the same thread, that window gets a
215   // WM_MOUSEACTIVATE message and ends up activating itself, which is not
216   // correct. We workaround this by setting a property on the window at the
217   // current cursor location. We check for this property in our
218   // WM_MOUSEACTIVATE handler and don't activate the window if the property is
219   // set.
220   if (::GetProp(hwnd(), ui::kIgnoreTouchMouseActivateForWindow)) {
221     ::RemoveProp(hwnd(), ui::kIgnoreTouchMouseActivateForWindow);
222     return MA_NOACTIVATE;
223   }
224   return MA_ACTIVATE;
225 }
226
227 LRESULT LegacyRenderWidgetHostHWND::OnTouch(UINT message,
228                                             WPARAM w_param,
229                                             LPARAM l_param) {
230   if (GetWindowEventTarget(GetParent())) {
231     return GetWindowEventTarget(GetParent())->HandleTouchMessage(
232         message, w_param, l_param);
233   }
234   return 0;
235 }
236
237 LRESULT LegacyRenderWidgetHostHWND::OnScroll(UINT message,
238                                              WPARAM w_param,
239                                              LPARAM l_param) {
240   if (GetWindowEventTarget(GetParent())) {
241     return GetWindowEventTarget(GetParent())->HandleScrollMessage(
242         message, w_param, l_param);
243   }
244   return 0;
245 }
246
247 LRESULT LegacyRenderWidgetHostHWND::OnNCHitTest(UINT message,
248                                                 WPARAM w_param,
249                                                 LPARAM l_param) {
250   if (GetWindowEventTarget(GetParent())) {
251     LRESULT hit_test = GetWindowEventTarget(
252         GetParent())->HandleNcHitTestMessage(message, w_param, l_param);
253     // If the parent returns HTNOWHERE which can happen for popup windows, etc
254     // we return HTCLIENT.
255     if (hit_test == HTNOWHERE)
256       hit_test = HTCLIENT;
257     return hit_test;
258   }
259   return HTNOWHERE;
260 }
261
262 LRESULT LegacyRenderWidgetHostHWND::OnNCPaint(UINT message,
263                                               WPARAM w_param,
264                                               LPARAM l_param) {
265   return 0;
266 }
267
268 LRESULT LegacyRenderWidgetHostHWND::OnPaint(UINT message,
269                                             WPARAM w_param,
270                                             LPARAM l_param) {
271   PAINTSTRUCT ps = {0};
272   ::BeginPaint(hwnd(), &ps);
273   ::EndPaint(hwnd(), &ps);
274   return 0;
275 }
276
277 LRESULT LegacyRenderWidgetHostHWND::OnSetCursor(UINT message,
278                                                 WPARAM w_param,
279                                                 LPARAM l_param) {
280   return 0;
281 }
282
283 LRESULT LegacyRenderWidgetHostHWND::OnNCCalcSize(UINT message,
284                                                  WPARAM w_param,
285                                                  LPARAM l_param) {
286   // Prevent scrollbars, etc from drawing.
287   return 0;
288 }
289
290 LRESULT LegacyRenderWidgetHostHWND::OnSize(UINT message,
291                                            WPARAM w_param,
292                                            LPARAM l_param) {
293   // Certain trackpad drivers on Windows have bugs where in they don't generate
294   // WM_MOUSEWHEEL messages for the trackpoint and trackpad scrolling gestures
295   // unless there is an entry for Chrome with the class name of the Window.
296   // Additionally others check if the window WS_VSCROLL/WS_HSCROLL styles and
297   // generate the legacy WM_VSCROLL/WM_HSCROLL messages.
298   // We add these styles to ensure that trackpad/trackpoint scrolling
299   // work.
300   long current_style = ::GetWindowLong(hwnd(), GWL_STYLE);
301   ::SetWindowLong(hwnd(), GWL_STYLE,
302                   current_style | WS_VSCROLL | WS_HSCROLL);
303   return 0;
304 }
305
306 }  // namespace content