1 // Copyright (c) 2011 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 "chrome/browser/ui/views/tab_contents/native_tab_contents_view_win.h"
6
7 #include "chrome/browser/renderer_host/render_widget_host_view_win.h"
8 #include "chrome/browser/tab_contents/web_drop_target_win.h"
9 #include "chrome/browser/ui/views/tab_contents/tab_contents_drag_win.h"
10 #include "chrome/browser/ui/views/tab_contents/native_tab_contents_view_delegate.h"
11 #include "content/browser/tab_contents/tab_contents.h"
12 #include "content/browser/tab_contents/tab_contents_view.h"
13
14 namespace {
15
16 // Tabs must be created as child widgets, otherwise they will be given
17 // a FocusManager which will conflict with the FocusManager of the
18 // window they eventually end up attached to.
19 //
20 // A tab will not have a parent HWND whenever it is not active in its
21 // host window - for example at creation time and when it's in the
22 // background, so we provide a default widget to host them.
23 //
24 // It may be tempting to use GetDesktopWindow() instead, but this is
25 // problematic as the shell sends messages to children of the desktop
26 // window that interact poorly with us.
27 //
28 // See: http://crbug.com/16476
GetHiddenTabHostWindow()29 HWND GetHiddenTabHostWindow() {
30 static views::Widget* widget = NULL;
31
32 if (!widget) {
33 views::Widget::CreateParams params(views::Widget::CreateParams::TYPE_POPUP);
34 widget = views::Widget::CreateWidget(params);
35 widget->Init(NULL, gfx::Rect());
36 // If a background window requests focus, the hidden tab host will
37 // be activated to focus the tab. Use WS_DISABLED to prevent
38 // this.
39 EnableWindow(widget->GetNativeView(), FALSE);
40 }
41
42 return widget->GetNativeView();
43 }
44
45 } // namespace
46
47 ////////////////////////////////////////////////////////////////////////////////
48 // NativeTabContentsViewWin, public:
49
NativeTabContentsViewWin(internal::NativeTabContentsViewDelegate * delegate)50 NativeTabContentsViewWin::NativeTabContentsViewWin(
51 internal::NativeTabContentsViewDelegate* delegate)
52 : delegate_(delegate),
53 focus_manager_(NULL) {
54 }
55
~NativeTabContentsViewWin()56 NativeTabContentsViewWin::~NativeTabContentsViewWin() {
57 CloseNow();
58 }
59
GetTabContents() const60 TabContents* NativeTabContentsViewWin::GetTabContents() const {
61 return delegate_->GetTabContents();
62 }
63
EndDragging()64 void NativeTabContentsViewWin::EndDragging() {
65 delegate_->OnNativeTabContentsViewDraggingEnded();
66 drag_handler_ = NULL;
67 }
68
69 ////////////////////////////////////////////////////////////////////////////////
70 // NativeTabContentsViewWin, NativeTabContentsView implementation:
71
InitNativeTabContentsView()72 void NativeTabContentsViewWin::InitNativeTabContentsView() {
73 views::Widget::CreateParams params(views::Widget::CreateParams::TYPE_CONTROL);
74 params.delete_on_destroy = false;
75 SetCreateParams(params);
76 WidgetWin::Init(GetHiddenTabHostWindow(), gfx::Rect());
77
78 // Remove the root view drop target so we can register our own.
79 RevokeDragDrop(GetNativeView());
80 drop_target_ = new WebDropTarget(GetNativeView(),
81 delegate_->GetTabContents());
82 }
83
Unparent()84 void NativeTabContentsViewWin::Unparent() {
85 // Remember who our FocusManager is, we won't be able to access it once
86 // unparented.
87 focus_manager_ = views::WidgetWin::GetFocusManager();
88 // Note that we do not DCHECK on focus_manager_ as it may be NULL when used
89 // with an external tab container.
90 NativeWidget::ReparentNativeView(GetNativeView(), GetHiddenTabHostWindow());
91 }
92
CreateRenderWidgetHostView(RenderWidgetHost * render_widget_host)93 RenderWidgetHostView* NativeTabContentsViewWin::CreateRenderWidgetHostView(
94 RenderWidgetHost* render_widget_host) {
95 RenderWidgetHostViewWin* view =
96 new RenderWidgetHostViewWin(render_widget_host);
97 view->CreateWnd(GetNativeView());
98 view->ShowWindow(SW_SHOW);
99 return view;
100 }
101
GetTopLevelNativeWindow() const102 gfx::NativeWindow NativeTabContentsViewWin::GetTopLevelNativeWindow() const {
103 return ::GetAncestor(GetNativeView(), GA_ROOT);
104 }
105
SetPageTitle(const std::wstring & title)106 void NativeTabContentsViewWin::SetPageTitle(const std::wstring& title) {
107 // It's possible to get this after the hwnd has been destroyed.
108 if (GetNativeView())
109 ::SetWindowText(GetNativeView(), title.c_str());
110 }
111
StartDragging(const WebDropData & drop_data,WebKit::WebDragOperationsMask ops,const SkBitmap & image,const gfx::Point & image_offset)112 void NativeTabContentsViewWin::StartDragging(const WebDropData& drop_data,
113 WebKit::WebDragOperationsMask ops,
114 const SkBitmap& image,
115 const gfx::Point& image_offset) {
116 drag_handler_ = new TabContentsDragWin(this);
117 drag_handler_->StartDragging(drop_data, ops, image, image_offset);
118 }
119
CancelDrag()120 void NativeTabContentsViewWin::CancelDrag() {
121 drag_handler_->CancelDrag();
122 }
123
IsDoingDrag() const124 bool NativeTabContentsViewWin::IsDoingDrag() const {
125 return drag_handler_.get() != NULL;
126 }
127
SetDragCursor(WebKit::WebDragOperation operation)128 void NativeTabContentsViewWin::SetDragCursor(
129 WebKit::WebDragOperation operation) {
130 drop_target_->set_drag_cursor(operation);
131 }
132
AsNativeWidget()133 views::NativeWidget* NativeTabContentsViewWin::AsNativeWidget() {
134 return this;
135 }
136
137 ////////////////////////////////////////////////////////////////////////////////
138 // NativeTabContentsViewWin, views::WidgetWin overrides:
139
OnDestroy()140 void NativeTabContentsViewWin::OnDestroy() {
141 if (drop_target_.get()) {
142 RevokeDragDrop(GetNativeView());
143 drop_target_ = NULL;
144 }
145
146 WidgetWin::OnDestroy();
147 }
148
OnHScroll(int scroll_type,short position,HWND scrollbar)149 void NativeTabContentsViewWin::OnHScroll(int scroll_type,
150 short position,
151 HWND scrollbar) {
152 ScrollCommon(WM_HSCROLL, scroll_type, position, scrollbar);
153 }
154
OnMouseRange(UINT msg,WPARAM w_param,LPARAM l_param)155 LRESULT NativeTabContentsViewWin::OnMouseRange(UINT msg,
156 WPARAM w_param,
157 LPARAM l_param) {
158 if (delegate_->IsShowingSadTab())
159 return WidgetWin::OnMouseRange(msg, w_param, l_param);
160
161 switch (msg) {
162 case WM_LBUTTONDOWN:
163 case WM_MBUTTONDOWN:
164 case WM_RBUTTONDOWN: {
165 delegate_->OnNativeTabContentsViewMouseDown();
166 break;
167 }
168 case WM_MOUSEMOVE:
169 delegate_->OnNativeTabContentsViewMouseMove();
170 break;
171 default:
172 break;
173 }
174 return 0;
175 }
176
177 // A message is reflected here from view().
178 // Return non-zero to indicate that it is handled here.
179 // Return 0 to allow view() to further process it.
OnReflectedMessage(UINT msg,WPARAM w_param,LPARAM l_param)180 LRESULT NativeTabContentsViewWin::OnReflectedMessage(UINT msg,
181 WPARAM w_param,
182 LPARAM l_param) {
183 MSG* message = reinterpret_cast<MSG*>(l_param);
184 switch (message->message) {
185 case WM_MOUSEWHEEL:
186 // This message is reflected from the view() to this window.
187 if (GET_KEYSTATE_WPARAM(message->wParam) & MK_CONTROL) {
188 delegate_->OnNativeTabContentsViewWheelZoom(
189 GET_WHEEL_DELTA_WPARAM(message->wParam));
190 return 1;
191 }
192 break;
193 case WM_HSCROLL:
194 case WM_VSCROLL:
195 if (ScrollZoom(LOWORD(message->wParam)))
196 return 1;
197 default:
198 break;
199 }
200
201 return 0;
202 }
203
OnVScroll(int scroll_type,short position,HWND scrollbar)204 void NativeTabContentsViewWin::OnVScroll(int scroll_type,
205 short position,
206 HWND scrollbar) {
207 ScrollCommon(WM_VSCROLL, scroll_type, position, scrollbar);
208 }
209
OnWindowPosChanged(WINDOWPOS * window_pos)210 void NativeTabContentsViewWin::OnWindowPosChanged(WINDOWPOS* window_pos) {
211 if (window_pos->flags & SWP_HIDEWINDOW) {
212 delegate_->OnNativeTabContentsViewHidden();
213 } else {
214 // The TabContents was shown by a means other than the user selecting a
215 // Tab, e.g. the window was minimized then restored.
216 if (window_pos->flags & SWP_SHOWWINDOW)
217 delegate_->OnNativeTabContentsViewShown();
218
219 // Unless we were specifically told not to size, cause the renderer to be
220 // sized to the new bounds, which forces a repaint. Not required for the
221 // simple minimize-restore case described above, for example, since the
222 // size hasn't changed.
223 if (!(window_pos->flags & SWP_NOSIZE)) {
224 delegate_->OnNativeTabContentsViewSized(
225 gfx::Size(window_pos->cx, window_pos->cy));
226 }
227 }
228 WidgetWin::OnWindowPosChanged(window_pos);
229 }
230
OnSize(UINT param,const CSize & size)231 void NativeTabContentsViewWin::OnSize(UINT param, const CSize& size) {
232 // NOTE: Because TabContentsViewViews handles OnWindowPosChanged without
233 // calling DefWindowProc, OnSize is NOT called on window resize. This handler
234 // is called only once when the window is created.
235
236 // Don't call base class OnSize to avoid useless layout for 0x0 size.
237 // We will get OnWindowPosChanged later and layout root view in WasSized.
238
239 // Hack for ThinkPad touch-pad driver.
240 // Set fake scrollbars so that we can get scroll messages,
241 SCROLLINFO si = {0};
242 si.cbSize = sizeof(si);
243 si.fMask = SIF_ALL;
244
245 si.nMin = 1;
246 si.nMax = 100;
247 si.nPage = 10;
248 si.nPos = 50;
249
250 ::SetScrollInfo(GetNativeView(), SB_HORZ, &si, FALSE);
251 ::SetScrollInfo(GetNativeView(), SB_VERT, &si, FALSE);
252 }
253
OnNCCalcSize(BOOL w_param,LPARAM l_param)254 LRESULT NativeTabContentsViewWin::OnNCCalcSize(BOOL w_param, LPARAM l_param) {
255 // Hack for ThinkPad mouse wheel driver. We have set the fake scroll bars
256 // to receive scroll messages from ThinkPad touch-pad driver. Suppress
257 // painting of scrollbars by returning 0 size for them.
258 return 0;
259 }
260
OnNCPaint(HRGN rgn)261 void NativeTabContentsViewWin::OnNCPaint(HRGN rgn) {
262 // Suppress default WM_NCPAINT handling. We don't need to do anything
263 // here since the view will draw everything correctly.
264 }
265
GetFocusManager()266 views::FocusManager* NativeTabContentsViewWin::GetFocusManager() {
267 views::FocusManager* focus_manager = WidgetWin::GetFocusManager();
268 if (focus_manager) {
269 // If focus_manager_ is non NULL, it means we have been reparented, in which
270 // case its value may not be valid anymore.
271 focus_manager_ = NULL;
272 return focus_manager;
273 }
274 // TODO(jcampan): we should DCHECK on focus_manager_, as it should not be
275 // NULL. We are not doing it as it breaks some unit-tests. We should
276 // probably have an empty TabContentView implementation for the unit-tests,
277 // that would prevent that code being executed in the unit-test case.
278 // DCHECK(focus_manager_);
279 return focus_manager_;
280 }
281
282 ////////////////////////////////////////////////////////////////////////////////
283 // NativeTabContentsViewWin, private:
284
ScrollCommon(UINT message,int scroll_type,short position,HWND scrollbar)285 void NativeTabContentsViewWin::ScrollCommon(UINT message, int scroll_type,
286 short position, HWND scrollbar) {
287 // This window can receive scroll events as a result of the ThinkPad's
288 // touch-pad scroll wheel emulation.
289 if (!ScrollZoom(scroll_type)) {
290 // Reflect scroll message to the view() to give it a chance
291 // to process scrolling.
292 SendMessage(delegate_->GetTabContents()->view()->GetContentNativeView(),
293 message, MAKELONG(scroll_type, position),
294 reinterpret_cast<LPARAM>(scrollbar));
295 }
296 }
297
ScrollZoom(int scroll_type)298 bool NativeTabContentsViewWin::ScrollZoom(int scroll_type) {
299 // If ctrl is held, zoom the UI. There are three issues with this:
300 // 1) Should the event be eaten or forwarded to content? We eat the event,
301 // which is like Firefox and unlike IE.
302 // 2) Should wheel up zoom in or out? We zoom in (increase font size), which
303 // is like IE and Google maps, but unlike Firefox.
304 // 3) Should the mouse have to be over the content area? We zoom as long as
305 // content has focus, although FF and IE require that the mouse is over
306 // content. This is because all events get forwarded when content has
307 // focus.
308 if (GetAsyncKeyState(VK_CONTROL) & 0x8000) {
309 int distance = 0;
310 switch (scroll_type) {
311 case SB_LINEUP:
312 distance = WHEEL_DELTA;
313 break;
314 case SB_LINEDOWN:
315 distance = -WHEEL_DELTA;
316 break;
317 // TODO(joshia): Handle SB_PAGEUP, SB_PAGEDOWN, SB_THUMBPOSITION,
318 // and SB_THUMBTRACK for completeness
319 default:
320 break;
321 }
322
323 delegate_->OnNativeTabContentsViewWheelZoom(distance);
324 return true;
325 }
326 return false;
327 }
328
329 ////////////////////////////////////////////////////////////////////////////////
330 // NativeTabContentsView, public:
331
332 // static
CreateNativeTabContentsView(internal::NativeTabContentsViewDelegate * delegate)333 NativeTabContentsView* NativeTabContentsView::CreateNativeTabContentsView(
334 internal::NativeTabContentsViewDelegate* delegate) {
335 return new NativeTabContentsViewWin(delegate);
336 }
337