Home | History | Annotate | Download | only in tab_contents
      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
     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 
     50 NativeTabContentsViewWin::NativeTabContentsViewWin(
     51     internal::NativeTabContentsViewDelegate* delegate)
     52     : delegate_(delegate),
     53       focus_manager_(NULL) {
     54 }
     55 
     56 NativeTabContentsViewWin::~NativeTabContentsViewWin() {
     57   CloseNow();
     58 }
     59 
     60 TabContents* NativeTabContentsViewWin::GetTabContents() const {
     61   return delegate_->GetTabContents();
     62 }
     63 
     64 void NativeTabContentsViewWin::EndDragging() {
     65   delegate_->OnNativeTabContentsViewDraggingEnded();
     66   drag_handler_ = NULL;
     67 }
     68 
     69 ////////////////////////////////////////////////////////////////////////////////
     70 // NativeTabContentsViewWin, NativeTabContentsView implementation:
     71 
     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 
     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 
     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 
    102 gfx::NativeWindow NativeTabContentsViewWin::GetTopLevelNativeWindow() const {
    103   return ::GetAncestor(GetNativeView(), GA_ROOT);
    104 }
    105 
    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 
    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 
    120 void NativeTabContentsViewWin::CancelDrag() {
    121   drag_handler_->CancelDrag();
    122 }
    123 
    124 bool NativeTabContentsViewWin::IsDoingDrag() const {
    125   return drag_handler_.get() != NULL;
    126 }
    127 
    128 void NativeTabContentsViewWin::SetDragCursor(
    129     WebKit::WebDragOperation operation) {
    130   drop_target_->set_drag_cursor(operation);
    131 }
    132 
    133 views::NativeWidget* NativeTabContentsViewWin::AsNativeWidget() {
    134   return this;
    135 }
    136 
    137 ////////////////////////////////////////////////////////////////////////////////
    138 // NativeTabContentsViewWin, views::WidgetWin overrides:
    139 
    140 void NativeTabContentsViewWin::OnDestroy() {
    141   if (drop_target_.get()) {
    142     RevokeDragDrop(GetNativeView());
    143     drop_target_ = NULL;
    144   }
    145 
    146   WidgetWin::OnDestroy();
    147 }
    148 
    149 void NativeTabContentsViewWin::OnHScroll(int scroll_type,
    150                                          short position,
    151                                          HWND scrollbar) {
    152   ScrollCommon(WM_HSCROLL, scroll_type, position, scrollbar);
    153 }
    154 
    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.
    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 
    204 void NativeTabContentsViewWin::OnVScroll(int scroll_type,
    205                                          short position,
    206                                          HWND scrollbar) {
    207   ScrollCommon(WM_VSCROLL, scroll_type, position, scrollbar);
    208 }
    209 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    333 NativeTabContentsView* NativeTabContentsView::CreateNativeTabContentsView(
    334     internal::NativeTabContentsViewDelegate* delegate) {
    335   return new NativeTabContentsViewWin(delegate);
    336 }
    337