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/tab_contents_view_touch.h"
      6 
      7 #include "base/string_util.h"
      8 #include "build/build_config.h"
      9 #include "chrome/browser/download/download_shelf.h"
     10 #include "chrome/browser/renderer_host/render_widget_host_view_views.h"
     11 #include "chrome/browser/ui/views/sad_tab_view.h"
     12 #include "chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h"
     13 #include "content/browser/renderer_host/render_view_host.h"
     14 #include "content/browser/renderer_host/render_view_host_factory.h"
     15 #include "content/browser/tab_contents/interstitial_page.h"
     16 #include "content/browser/tab_contents/tab_contents.h"
     17 #include "content/browser/tab_contents/tab_contents_delegate.h"
     18 #include "ui/gfx/canvas_skia_paint.h"
     19 #include "ui/gfx/point.h"
     20 #include "ui/gfx/rect.h"
     21 #include "ui/gfx/size.h"
     22 #include "views/controls/native/native_view_host.h"
     23 #include "views/focus/focus_manager.h"
     24 #include "views/focus/view_storage.h"
     25 #include "views/layout/fill_layout.h"
     26 #include "views/screen.h"
     27 #include "views/widget/widget.h"
     28 
     29 using WebKit::WebDragOperation;
     30 using WebKit::WebDragOperationsMask;
     31 using WebKit::WebInputEvent;
     32 
     33 // static
     34 TabContentsView* TabContentsView::Create(TabContents* tab_contents) {
     35   return new TabContentsViewTouch(tab_contents);
     36 }
     37 
     38 TabContentsViewTouch::TabContentsViewTouch(TabContents* tab_contents)
     39     : TabContentsView(tab_contents),
     40       sad_tab_(NULL),
     41       ignore_next_char_event_(false) {
     42   last_focused_view_storage_id_ =
     43       views::ViewStorage::GetInstance()->CreateStorageID();
     44   SetLayoutManager(new views::FillLayout());
     45 }
     46 
     47 TabContentsViewTouch::~TabContentsViewTouch() {
     48   // Make sure to remove any stored view we may still have in the ViewStorage.
     49   //
     50   // It is possible the view went away before us, so we only do this if the
     51   // view is registered.
     52   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
     53   if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
     54     view_storage->RemoveView(last_focused_view_storage_id_);
     55 }
     56 
     57 void TabContentsViewTouch::AttachConstrainedWindow(
     58     ConstrainedWindowGtk* constrained_window) {
     59   // TODO(anicolao): reimplement all dialogs as WebUI
     60   NOTIMPLEMENTED();
     61 }
     62 
     63 void TabContentsViewTouch::RemoveConstrainedWindow(
     64     ConstrainedWindowGtk* constrained_window) {
     65   // TODO(anicolao): reimplement all dialogs as WebUI
     66   NOTIMPLEMENTED();
     67 }
     68 
     69 void TabContentsViewTouch::CreateView(const gfx::Size& initial_size) {
     70   SetBoundsRect(gfx::Rect(bounds().origin(), initial_size));
     71 }
     72 
     73 RenderWidgetHostView* TabContentsViewTouch::CreateViewForWidget(
     74     RenderWidgetHost* render_widget_host) {
     75   if (render_widget_host->view()) {
     76     // During testing, the view will already be set up in most cases to the
     77     // test view, so we don't want to clobber it with a real one. To verify that
     78     // this actually is happening (and somebody isn't accidentally creating the
     79     // view twice), we check for the RVH Factory, which will be set when we're
     80     // making special ones (which go along with the special views).
     81     DCHECK(RenderViewHostFactory::has_factory());
     82     return render_widget_host->view();
     83   }
     84 
     85   // If we were showing sad tab, remove it now.
     86   if (sad_tab_ != NULL) {
     87     RemoveChildView(sad_tab_.get());
     88     sad_tab_.reset();
     89   }
     90 
     91   RenderWidgetHostViewViews* view =
     92       new RenderWidgetHostViewViews(render_widget_host);
     93   AddChildView(view);
     94   view->Show();
     95   view->InitAsChild();
     96 
     97   // TODO(anicolao): implement drag'n'drop hooks if needed
     98 
     99   return view;
    100 }
    101 
    102 gfx::NativeView TabContentsViewTouch::GetNativeView() const {
    103   return GetWidget()->GetNativeView();
    104 }
    105 
    106 gfx::NativeView TabContentsViewTouch::GetContentNativeView() const {
    107   RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView();
    108   if (!rwhv)
    109     return NULL;
    110   return rwhv->GetNativeView();
    111 }
    112 
    113 gfx::NativeWindow TabContentsViewTouch::GetTopLevelNativeWindow() const {
    114   GtkWidget* window = gtk_widget_get_ancestor(GetNativeView(), GTK_TYPE_WINDOW);
    115   return window ? GTK_WINDOW(window) : NULL;
    116 }
    117 
    118 void TabContentsViewTouch::GetContainerBounds(gfx::Rect* out) const {
    119   *out = bounds();
    120 }
    121 
    122 void TabContentsViewTouch::StartDragging(const WebDropData& drop_data,
    123                                          WebDragOperationsMask ops,
    124                                          const SkBitmap& image,
    125                                          const gfx::Point& image_offset) {
    126   // TODO(anicolao): implement dragging
    127 }
    128 
    129 void TabContentsViewTouch::SetPageTitle(const std::wstring& title) {
    130   // TODO(anicolao): figure out if there's anything useful to do here
    131 }
    132 
    133 void TabContentsViewTouch::OnTabCrashed(base::TerminationStatus status,
    134                                         int /* error_code */) {
    135   if (sad_tab_ != NULL)
    136     return;
    137 
    138   sad_tab_.reset(new SadTabView(
    139       tab_contents(),
    140       status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ?
    141           SadTabView::KILLED : SadTabView::CRASHED));
    142   RemoveAllChildViews(true);
    143   AddChildView(sad_tab_.get());
    144   Layout();
    145 }
    146 
    147 void TabContentsViewTouch::SizeContents(const gfx::Size& size) {
    148   WasSized(size);
    149 
    150   // We need to send this immediately.
    151   RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView();
    152   if (rwhv)
    153     rwhv->SetSize(size);
    154 }
    155 
    156 void TabContentsViewTouch::Focus() {
    157   if (tab_contents()->interstitial_page()) {
    158     tab_contents()->interstitial_page()->Focus();
    159     return;
    160   }
    161 
    162   if (tab_contents()->is_crashed() && sad_tab_ != NULL) {
    163     sad_tab_->RequestFocus();
    164     return;
    165   }
    166 
    167   RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView();
    168   if (rwhv)
    169     rwhv->Focus();
    170 }
    171 
    172 void TabContentsViewTouch::SetInitialFocus() {
    173   if (tab_contents()->FocusLocationBarByDefault())
    174     tab_contents()->SetFocusToLocationBar(false);
    175   else
    176     Focus();
    177 }
    178 
    179 void TabContentsViewTouch::StoreFocus() {
    180   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
    181 
    182   if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
    183     view_storage->RemoveView(last_focused_view_storage_id_);
    184 
    185   views::FocusManager* focus_manager =
    186       views::FocusManager::GetFocusManagerForNativeView(GetNativeView());
    187   if (focus_manager) {
    188     // |focus_manager| can be NULL if the tab has been detached but still
    189     // exists.
    190     views::View* focused_view = focus_manager->GetFocusedView();
    191     if (focused_view)
    192       view_storage->StoreView(last_focused_view_storage_id_, focused_view);
    193   }
    194 }
    195 
    196 void TabContentsViewTouch::RestoreFocus() {
    197   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
    198   views::View* last_focused_view =
    199       view_storage->RetrieveView(last_focused_view_storage_id_);
    200   if (!last_focused_view) {
    201     SetInitialFocus();
    202   } else {
    203     views::FocusManager* focus_manager =
    204         views::FocusManager::GetFocusManagerForNativeView(GetNativeView());
    205 
    206     // If you hit this DCHECK, please report it to Jay (jcampan).
    207     DCHECK(focus_manager != NULL) << "No focus manager when restoring focus.";
    208 
    209     if (last_focused_view->IsFocusableInRootView() && focus_manager &&
    210         focus_manager->ContainsView(last_focused_view)) {
    211       last_focused_view->RequestFocus();
    212     } else {
    213       // The focused view may not belong to the same window hierarchy (e.g.
    214       // if the location bar was focused and the tab is dragged out), or it may
    215       // no longer be focusable (e.g. if the location bar was focused and then
    216       // we switched to fullscreen mode).  In that case we default to the
    217       // default focus.
    218       SetInitialFocus();
    219     }
    220     view_storage->RemoveView(last_focused_view_storage_id_);
    221   }
    222 }
    223 
    224 void TabContentsViewTouch::GetViewBounds(gfx::Rect* out) const {
    225   out->SetRect(x(), y(), width(), height());
    226 }
    227 
    228 void TabContentsViewTouch::OnBoundsChanged(const gfx::Rect& previous_bounds) {
    229   if (IsVisibleInRootView())
    230     WasSized(size());
    231 }
    232 
    233 void TabContentsViewTouch::OnPaint(gfx::Canvas* canvas) {
    234 }
    235 
    236 void TabContentsViewTouch::UpdateDragCursor(WebDragOperation operation) {
    237   NOTIMPLEMENTED();
    238   // It's not even clear a drag cursor will make sense for touch.
    239   // TODO(anicolao): implement dragging
    240 }
    241 
    242 void TabContentsViewTouch::GotFocus() {
    243   if (tab_contents()->delegate())
    244     tab_contents()->delegate()->TabContentsFocused(tab_contents());
    245 }
    246 
    247 void TabContentsViewTouch::TakeFocus(bool reverse) {
    248   if (tab_contents()->delegate() &&
    249       !tab_contents()->delegate()->TakeFocus(reverse)) {
    250 
    251     views::FocusManager* focus_manager =
    252         views::FocusManager::GetFocusManagerForNativeView(GetNativeView());
    253 
    254     // We may not have a focus manager if the tab has been switched before this
    255     // message arrived.
    256     if (focus_manager)
    257       focus_manager->AdvanceFocus(reverse);
    258   }
    259 }
    260 
    261 void TabContentsViewTouch::VisibilityChanged(views::View *, bool is_visible) {
    262   if (is_visible) {
    263     WasShown();
    264   } else {
    265     WasHidden();
    266   }
    267 }
    268 
    269 void TabContentsViewTouch::ShowContextMenu(const ContextMenuParams& params) {
    270   // Allow delegates to handle the context menu operation first.
    271   if (tab_contents()->delegate() &&
    272       tab_contents()->delegate()->HandleContextMenu(params))
    273     return;
    274 
    275   context_menu_.reset(new RenderViewContextMenuViews(tab_contents(), params));
    276   context_menu_->Init();
    277 
    278   gfx::Point screen_point(params.x, params.y);
    279   RenderWidgetHostViewViews* rwhv = static_cast<RenderWidgetHostViewViews*>
    280       (tab_contents()->GetRenderWidgetHostView());
    281   if (rwhv) {
    282     views::View::ConvertPointToScreen(rwhv, &screen_point);
    283   }
    284 
    285   // Enable recursive tasks on the message loop so we can get updates while
    286   // the context menu is being displayed.
    287   bool old_state = MessageLoop::current()->NestableTasksAllowed();
    288   MessageLoop::current()->SetNestableTasksAllowed(true);
    289   context_menu_->RunMenuAt(screen_point.x(), screen_point.y());
    290   MessageLoop::current()->SetNestableTasksAllowed(old_state);
    291 }
    292 
    293 void TabContentsViewTouch::ShowPopupMenu(const gfx::Rect& bounds,
    294                                          int item_height,
    295                                          double item_font_size,
    296                                          int selected_item,
    297                                          const std::vector<WebMenuItem>& items,
    298                                          bool right_aligned) {
    299   // External popup menus are only used on Mac.
    300   NOTREACHED();
    301 }
    302 
    303 void TabContentsViewTouch::WasHidden() {
    304   tab_contents()->HideContents();
    305 }
    306 
    307 void TabContentsViewTouch::WasShown() {
    308   tab_contents()->ShowContents();
    309 }
    310 
    311 void TabContentsViewTouch::WasSized(const gfx::Size& size) {
    312   // We have to check that the RenderWidgetHostView is the proper size.
    313   // It can be wrong in cases where the renderer has died and the host
    314   // view needed to be recreated.
    315   bool needs_resize = size != size_;
    316 
    317   if (needs_resize) {
    318     size_ = size;
    319     if (tab_contents()->interstitial_page())
    320       tab_contents()->interstitial_page()->SetSize(size);
    321   }
    322 
    323   RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView();
    324   if (rwhv && rwhv->GetViewBounds().size() != size)
    325     rwhv->SetSize(size);
    326 
    327   if (needs_resize)
    328     SetFloatingPosition(size);
    329 }
    330 
    331 void TabContentsViewTouch::SetFloatingPosition(const gfx::Size& size) {
    332   // TODO(anicolao): rework this once we have WebUI views for dialogs
    333   SetBounds(x(), y(), size.width(), size.height());
    334 }
    335