tab_contents_view_views.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
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_views.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_view_host.h" 11#include "chrome/browser/renderer_host/render_view_host_factory.h" 12#include "chrome/browser/renderer_host/render_widget_host_view_views.h" 13#include "chrome/browser/tab_contents/interstitial_page.h" 14#include "chrome/browser/tab_contents/tab_contents.h" 15#include "chrome/browser/tab_contents/tab_contents_delegate.h" 16#include "chrome/browser/ui/views/sad_tab_view.h" 17#include "chrome/browser/ui/views/tab_contents/render_view_context_menu_views.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 29using WebKit::WebDragOperation; 30using WebKit::WebDragOperationsMask; 31using WebKit::WebInputEvent; 32 33// static 34TabContentsView* TabContentsView::Create(TabContents* tab_contents) { 35 return new TabContentsViewViews(tab_contents); 36} 37 38TabContentsViewViews::TabContentsViewViews(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 47TabContentsViewViews::~TabContentsViewViews() { 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 57void TabContentsViewViews::AttachConstrainedWindow( 58 ConstrainedWindowGtk* constrained_window) { 59 // TODO(anicolao): reimplement all dialogs as WebUI 60 NOTIMPLEMENTED(); 61} 62 63void TabContentsViewViews::RemoveConstrainedWindow( 64 ConstrainedWindowGtk* constrained_window) { 65 // TODO(anicolao): reimplement all dialogs as WebUI 66 NOTIMPLEMENTED(); 67} 68 69void TabContentsViewViews::CreateView(const gfx::Size& initial_size) { 70 SetBoundsRect(gfx::Rect(bounds().origin(), initial_size)); 71} 72 73RenderWidgetHostView* TabContentsViewViews::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 102gfx::NativeView TabContentsViewViews::GetNativeView() const { 103 return GetWidget()->GetNativeView(); 104} 105 106gfx::NativeView TabContentsViewViews::GetContentNativeView() const { 107 RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView(); 108 if (!rwhv) 109 return NULL; 110 return rwhv->GetNativeView(); 111} 112 113gfx::NativeWindow TabContentsViewViews::GetTopLevelNativeWindow() const { 114 GtkWidget* window = gtk_widget_get_ancestor(GetNativeView(), GTK_TYPE_WINDOW); 115 return window ? GTK_WINDOW(window) : NULL; 116} 117 118void TabContentsViewViews::GetContainerBounds(gfx::Rect* out) const { 119 *out = bounds(); 120} 121 122void TabContentsViewViews::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 129void TabContentsViewViews::SetPageTitle(const std::wstring& title) { 130 // TODO(anicolao): figure out if there's anything useful to do here 131} 132 133void TabContentsViewViews::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 147void TabContentsViewViews::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 156void TabContentsViewViews::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 172void TabContentsViewViews::SetInitialFocus() { 173 if (tab_contents()->FocusLocationBarByDefault()) 174 tab_contents()->SetFocusToLocationBar(false); 175 else 176 Focus(); 177} 178 179void TabContentsViewViews::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 196void TabContentsViewViews::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 224void TabContentsViewViews::GetViewBounds(gfx::Rect* out) const { 225 out->SetRect(x(), y(), width(), height()); 226} 227 228void TabContentsViewViews::OnBoundsChanged() { 229 if (IsVisibleInRootView()) 230 WasSized(size()); 231} 232 233void TabContentsViewViews::Paint(gfx::Canvas* canvas) { 234} 235 236void TabContentsViewViews::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 242void TabContentsViewViews::GotFocus() { 243 if (tab_contents()->delegate()) 244 tab_contents()->delegate()->TabContentsFocused(tab_contents()); 245} 246 247void TabContentsViewViews::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 261void TabContentsViewViews::VisibilityChanged(views::View *, bool is_visible) { 262 if (is_visible) { 263 WasShown(); 264 } else { 265 WasHidden(); 266 } 267} 268 269void TabContentsViewViews::ShowContextMenu(const ContextMenuParams& params) { 270 // Allow delegates to handle the context menu operation first. 271 if (tab_contents()->delegate()->HandleContextMenu(params)) 272 return; 273 274 context_menu_.reset(new RenderViewContextMenuViews(tab_contents(), params)); 275 context_menu_->Init(); 276 277 gfx::Point screen_point(params.x, params.y); 278 RenderWidgetHostViewViews* rwhv = static_cast<RenderWidgetHostViewViews*> 279 (tab_contents()->GetRenderWidgetHostView()); 280 if (rwhv) { 281 views::View::ConvertPointToScreen(rwhv, &screen_point); 282 } 283 284 // Enable recursive tasks on the message loop so we can get updates while 285 // the context menu is being displayed. 286 bool old_state = MessageLoop::current()->NestableTasksAllowed(); 287 MessageLoop::current()->SetNestableTasksAllowed(true); 288 context_menu_->RunMenuAt(screen_point.x(), screen_point.y()); 289 MessageLoop::current()->SetNestableTasksAllowed(old_state); 290} 291 292void TabContentsViewViews::ShowPopupMenu(const gfx::Rect& bounds, 293 int item_height, 294 double item_font_size, 295 int selected_item, 296 const std::vector<WebMenuItem>& items, 297 bool right_aligned) { 298 // External popup menus are only used on Mac. 299 NOTREACHED(); 300} 301 302void TabContentsViewViews::WasHidden() { 303 tab_contents()->HideContents(); 304} 305 306void TabContentsViewViews::WasShown() { 307 tab_contents()->ShowContents(); 308} 309 310void TabContentsViewViews::WasSized(const gfx::Size& size) { 311 // We have to check that the RenderWidgetHostView is the proper size. 312 // It can be wrong in cases where the renderer has died and the host 313 // view needed to be recreated. 314 bool needs_resize = size != size_; 315 316 if (needs_resize) { 317 size_ = size; 318 if (tab_contents()->interstitial_page()) 319 tab_contents()->interstitial_page()->SetSize(size); 320 } 321 322 RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView(); 323 if (rwhv && rwhv->GetViewBounds().size() != size) 324 rwhv->SetSize(size); 325 326 if (needs_resize) 327 SetFloatingPosition(size); 328} 329 330void TabContentsViewViews::SetFloatingPosition(const gfx::Size& size) { 331 // TODO(anicolao): rework this once we have WebUI views for dialogs 332 SetBounds(x(), y(), size.width(), size.height()); 333} 334