1// Copyright (c) 2012 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/chrome_web_contents_view_delegate_views.h" 6 7#include "chrome/browser/defaults.h" 8#include "chrome/browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.h" 9#include "chrome/browser/ui/sad_tab_helper.h" 10#include "chrome/browser/ui/tab_contents/chrome_web_contents_view_delegate.h" 11#include "chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.h" 12#include "chrome/browser/ui/views/sad_tab_view.h" 13#include "components/web_modal/popup_manager.h" 14#include "content/public/browser/render_process_host.h" 15#include "content/public/browser/render_view_host.h" 16#include "content/public/browser/render_widget_host_view.h" 17#include "content/public/browser/web_contents.h" 18#include "content/public/browser/web_contents_delegate.h" 19#include "ui/aura/client/screen_position_client.h" 20#include "ui/aura/window.h" 21#include "ui/views/focus/focus_manager.h" 22#include "ui/views/focus/view_storage.h" 23#include "ui/views/widget/widget.h" 24 25#if defined(USE_AURA) 26#include "chrome/browser/ui/views/link_disambiguation/link_disambiguation_popup.h" 27#endif 28 29ChromeWebContentsViewDelegateViews::ChromeWebContentsViewDelegateViews( 30 content::WebContents* web_contents) 31 : ContextMenuDelegate(web_contents), 32 web_contents_(web_contents) { 33 last_focused_view_storage_id_ = 34 views::ViewStorage::GetInstance()->CreateStorageID(); 35} 36 37ChromeWebContentsViewDelegateViews::~ChromeWebContentsViewDelegateViews() { 38 // Makes sure to remove any stored view we may still have in the ViewStorage. 39 // 40 // It is possible the view went away before us, so we only do this if the 41 // view is registered. 42 views::ViewStorage* view_storage = views::ViewStorage::GetInstance(); 43 if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL) 44 view_storage->RemoveView(last_focused_view_storage_id_); 45} 46 47content::WebDragDestDelegate* 48 ChromeWebContentsViewDelegateViews::GetDragDestDelegate() { 49 // We install a chrome specific handler to intercept bookmark drags for the 50 // bookmark manager/extension API. 51 bookmark_handler_.reset(new WebDragBookmarkHandlerAura); 52 return bookmark_handler_.get(); 53} 54 55bool ChromeWebContentsViewDelegateViews::Focus() { 56 SadTabHelper* sad_tab_helper = SadTabHelper::FromWebContents(web_contents_); 57 if (sad_tab_helper) { 58 SadTabView* sad_tab = static_cast<SadTabView*>(sad_tab_helper->sad_tab()); 59 if (sad_tab) { 60 sad_tab->RequestFocus(); 61 return true; 62 } 63 } 64 65 web_modal::PopupManager* popup_manager = 66 web_modal::PopupManager::FromWebContents(web_contents_); 67 if (popup_manager) 68 popup_manager->WasFocused(web_contents_); 69 70 return false; 71} 72 73void ChromeWebContentsViewDelegateViews::TakeFocus(bool reverse) { 74 views::FocusManager* focus_manager = GetFocusManager(); 75 if (focus_manager) 76 focus_manager->AdvanceFocus(reverse); 77} 78 79void ChromeWebContentsViewDelegateViews::StoreFocus() { 80 views::ViewStorage* view_storage = views::ViewStorage::GetInstance(); 81 82 if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL) 83 view_storage->RemoveView(last_focused_view_storage_id_); 84 85 if (!GetFocusManager()) 86 return; 87 views::View* focused_view = GetFocusManager()->GetFocusedView(); 88 if (focused_view) 89 view_storage->StoreView(last_focused_view_storage_id_, focused_view); 90} 91 92void ChromeWebContentsViewDelegateViews::RestoreFocus() { 93 views::ViewStorage* view_storage = views::ViewStorage::GetInstance(); 94 views::View* last_focused_view = 95 view_storage->RetrieveView(last_focused_view_storage_id_); 96 97 if (!last_focused_view) { 98 SetInitialFocus(); 99 } else { 100 if (last_focused_view->IsFocusable() && 101 GetFocusManager()->ContainsView(last_focused_view)) { 102 last_focused_view->RequestFocus(); 103 } else { 104 // The focused view may not belong to the same window hierarchy (e.g. 105 // if the location bar was focused and the tab is dragged out), or it may 106 // no longer be focusable (e.g. if the location bar was focused and then 107 // we switched to fullscreen mode). In that case we default to the 108 // default focus. 109 SetInitialFocus(); 110 } 111 view_storage->RemoveView(last_focused_view_storage_id_); 112 } 113} 114 115scoped_ptr<RenderViewContextMenu> ChromeWebContentsViewDelegateViews::BuildMenu( 116 content::WebContents* web_contents, 117 const content::ContextMenuParams& params) { 118 scoped_ptr<RenderViewContextMenu> menu; 119 content::RenderFrameHost* focused_frame = web_contents->GetFocusedFrame(); 120 // If the frame tree does not have a focused frame at this point, do not 121 // bother creating RenderViewContextMenuViews. 122 // This happens if the frame has navigated to a different page before 123 // ContextMenu message was received by the current RenderFrameHost. 124 if (focused_frame) { 125 menu.reset(RenderViewContextMenuViews::Create(focused_frame, params)); 126 menu->Init(); 127 } 128 return menu.Pass(); 129} 130 131void ChromeWebContentsViewDelegateViews::ShowMenu( 132 scoped_ptr<RenderViewContextMenu> menu) { 133 context_menu_.reset(static_cast<RenderViewContextMenuViews*>(menu.release())); 134 if (!context_menu_.get()) 135 return; 136 137 // Menus need a Widget to work. If we're not the active tab we won't 138 // necessarily be in a widget. 139 views::Widget* top_level_widget = GetTopLevelWidget(); 140 if (!top_level_widget) 141 return; 142 143 const content::ContextMenuParams& params = context_menu_->params(); 144 // Don't show empty menus. 145 if (context_menu_->menu_model().GetItemCount() == 0) 146 return; 147 148 gfx::Point screen_point(params.x, params.y); 149 150 // Convert from target window coordinates to root window coordinates. 151 aura::Window* target_window = GetActiveNativeView(); 152 aura::Window* root_window = target_window->GetRootWindow(); 153 aura::client::ScreenPositionClient* screen_position_client = 154 aura::client::GetScreenPositionClient(root_window); 155 if (screen_position_client) { 156 screen_position_client->ConvertPointToScreen(target_window, 157 &screen_point); 158 } 159 // Enable recursive tasks on the message loop so we can get updates while 160 // the context menu is being displayed. 161 base::MessageLoop::ScopedNestableTaskAllower allow( 162 base::MessageLoop::current()); 163 context_menu_->RunMenuAt(top_level_widget, screen_point, params.source_type); 164} 165 166void ChromeWebContentsViewDelegateViews::ShowContextMenu( 167 content::RenderFrameHost* render_frame_host, 168 const content::ContextMenuParams& params) { 169 ShowMenu( 170 BuildMenu(content::WebContents::FromRenderFrameHost(render_frame_host), 171 params)); 172} 173 174void ChromeWebContentsViewDelegateViews::ShowDisambiguationPopup( 175 const gfx::Rect& target_rect, 176 const SkBitmap& zoomed_bitmap, 177 const gfx::NativeView content, 178 const base::Callback<void(ui::GestureEvent*)>& gesture_cb, 179 const base::Callback<void(ui::MouseEvent*)>& mouse_cb) { 180#if defined(USE_AURA) 181 link_disambiguation_popup_.reset(new LinkDisambiguationPopup); 182 link_disambiguation_popup_->Show( 183 zoomed_bitmap, target_rect, content, gesture_cb, mouse_cb); 184#endif 185} 186 187void ChromeWebContentsViewDelegateViews::HideDisambiguationPopup() { 188 link_disambiguation_popup_.reset(); 189} 190 191void ChromeWebContentsViewDelegateViews::SizeChanged(const gfx::Size& size) { 192 SadTabHelper* sad_tab_helper = SadTabHelper::FromWebContents(web_contents_); 193 if (!sad_tab_helper) 194 return; 195 SadTabView* sad_tab = static_cast<SadTabView*>(sad_tab_helper->sad_tab()); 196 if (sad_tab) 197 sad_tab->GetWidget()->SetBounds(gfx::Rect(size)); 198} 199 200aura::Window* ChromeWebContentsViewDelegateViews::GetActiveNativeView() { 201 return web_contents_->GetFullscreenRenderWidgetHostView() ? 202 web_contents_->GetFullscreenRenderWidgetHostView()->GetNativeView() : 203 web_contents_->GetNativeView(); 204} 205 206views::Widget* ChromeWebContentsViewDelegateViews::GetTopLevelWidget() { 207 return views::Widget::GetTopLevelWidgetForNativeView(GetActiveNativeView()); 208} 209 210views::FocusManager* 211 ChromeWebContentsViewDelegateViews::GetFocusManager() { 212 views::Widget* toplevel_widget = GetTopLevelWidget(); 213 return toplevel_widget ? toplevel_widget->GetFocusManager() : NULL; 214} 215 216void ChromeWebContentsViewDelegateViews::SetInitialFocus() { 217 if (web_contents_->FocusLocationBarByDefault()) { 218 if (web_contents_->GetDelegate()) 219 web_contents_->GetDelegate()->SetFocusToLocationBar(false); 220 } else { 221 web_contents_->Focus(); 222 } 223} 224 225namespace chrome { 226 227content::WebContentsViewDelegate* CreateWebContentsViewDelegate( 228 content::WebContents* web_contents) { 229 return new ChromeWebContentsViewDelegateViews(web_contents); 230} 231 232} // namespace chrome 233