• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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