Home | History | Annotate | Download | only in tab_contents
      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/browser_shutdown.h"
      8 #include "chrome/browser/ui/sad_tab_helper.h"
      9 #include "chrome/browser/ui/tab_contents/chrome_web_contents_view_delegate.h"
     10 #include "chrome/browser/ui/views/sad_tab_view.h"
     11 #include "chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h"
     12 #include "chrome/common/chrome_switches.h"
     13 #include "components/web_modal/web_contents_modal_dialog_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 "content/public/browser/web_contents_view.h"
     20 #include "ui/views/focus/focus_manager.h"
     21 #include "ui/views/focus/view_storage.h"
     22 #include "ui/views/widget/widget.h"
     23 
     24 #if defined(USE_AURA)
     25 #include "chrome/browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.h"
     26 #include "ui/aura/client/screen_position_client.h"
     27 #include "ui/aura/root_window.h"
     28 #include "ui/aura/window.h"
     29 #else
     30 #include "chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.h"
     31 #endif
     32 
     33 using web_modal::WebContentsModalDialogManager;
     34 
     35 ChromeWebContentsViewDelegateViews::ChromeWebContentsViewDelegateViews(
     36     content::WebContents* web_contents)
     37     : web_contents_(web_contents) {
     38   last_focused_view_storage_id_ =
     39       views::ViewStorage::GetInstance()->CreateStorageID();
     40 }
     41 
     42 ChromeWebContentsViewDelegateViews::~ChromeWebContentsViewDelegateViews() {
     43   // Makes sure to remove any stored view we may still have in the ViewStorage.
     44   //
     45   // It is possible the view went away before us, so we only do this if the
     46   // view is registered.
     47   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
     48   if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
     49     view_storage->RemoveView(last_focused_view_storage_id_);
     50 }
     51 
     52 content::WebDragDestDelegate*
     53     ChromeWebContentsViewDelegateViews::GetDragDestDelegate() {
     54   // We install a chrome specific handler to intercept bookmark drags for the
     55   // bookmark manager/extension API.
     56 #if defined(USE_AURA)
     57   bookmark_handler_.reset(new WebDragBookmarkHandlerAura);
     58 #else
     59   bookmark_handler_.reset(new WebDragBookmarkHandlerWin);
     60 #endif
     61   return bookmark_handler_.get();
     62 }
     63 
     64 bool ChromeWebContentsViewDelegateViews::Focus() {
     65   SadTabHelper* sad_tab_helper = SadTabHelper::FromWebContents(web_contents_);
     66   if (sad_tab_helper) {
     67     SadTabView* sad_tab = static_cast<SadTabView*>(sad_tab_helper->sad_tab());
     68     if (sad_tab) {
     69       sad_tab->RequestFocus();
     70       return true;
     71     }
     72   }
     73 
     74   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
     75       WebContentsModalDialogManager::FromWebContents(web_contents_);
     76   if (web_contents_modal_dialog_manager) {
     77     // TODO(erg): WebContents used to own web contents modal dialogs, which is
     78     // why this is here. Eventually this should be ported to a containing view
     79     // specializing in web contents modal dialog management.
     80     if (web_contents_modal_dialog_manager->IsShowingDialog()) {
     81       web_contents_modal_dialog_manager->FocusTopmostDialog();
     82       return true;
     83     }
     84   }
     85 
     86   return false;
     87 }
     88 
     89 void ChromeWebContentsViewDelegateViews::TakeFocus(bool reverse) {
     90   views::FocusManager* focus_manager = GetFocusManager();
     91   if (focus_manager)
     92     focus_manager->AdvanceFocus(reverse);
     93 }
     94 
     95 void ChromeWebContentsViewDelegateViews::StoreFocus() {
     96   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
     97 
     98   if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
     99     view_storage->RemoveView(last_focused_view_storage_id_);
    100 
    101   if (!GetFocusManager())
    102     return;
    103   views::View* focused_view = GetFocusManager()->GetFocusedView();
    104   if (focused_view)
    105     view_storage->StoreView(last_focused_view_storage_id_, focused_view);
    106 }
    107 
    108 void ChromeWebContentsViewDelegateViews::RestoreFocus() {
    109   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
    110   views::View* last_focused_view =
    111       view_storage->RetrieveView(last_focused_view_storage_id_);
    112 
    113   if (!last_focused_view) {
    114     SetInitialFocus();
    115   } else {
    116     if (last_focused_view->IsFocusable() &&
    117         GetFocusManager()->ContainsView(last_focused_view)) {
    118       last_focused_view->RequestFocus();
    119     } else {
    120       // The focused view may not belong to the same window hierarchy (e.g.
    121       // if the location bar was focused and the tab is dragged out), or it may
    122       // no longer be focusable (e.g. if the location bar was focused and then
    123       // we switched to fullscreen mode).  In that case we default to the
    124       // default focus.
    125       SetInitialFocus();
    126     }
    127     view_storage->RemoveView(last_focused_view_storage_id_);
    128   }
    129 }
    130 
    131 void ChromeWebContentsViewDelegateViews::ShowContextMenu(
    132     const content::ContextMenuParams& params) {
    133   // Menus need a Widget to work. If we're not the active tab we won't
    134   // necessarily be in a widget.
    135   views::Widget* top_level_widget = GetTopLevelWidget();
    136   if (!top_level_widget)
    137     return;
    138 
    139   context_menu_.reset(
    140       RenderViewContextMenuViews::Create(web_contents_, params));
    141   context_menu_->Init();
    142 
    143   // Don't show empty menus.
    144   if (context_menu_->menu_model().GetItemCount() == 0)
    145     return;
    146 
    147   gfx::Point screen_point(params.x, params.y);
    148 
    149 #if defined(USE_AURA)
    150   // Convert from content coordinates to window coordinates.
    151   aura::Window* web_contents_window =
    152       web_contents_->GetView()->GetNativeView();
    153   aura::RootWindow* root_window = web_contents_window->GetRootWindow();
    154   aura::client::ScreenPositionClient* screen_position_client =
    155       aura::client::GetScreenPositionClient(root_window);
    156   if (screen_position_client) {
    157     screen_position_client->ConvertPointToScreen(web_contents_window,
    158                                                  &screen_point);
    159   }
    160 #else
    161   POINT temp = screen_point.ToPOINT();
    162   ClientToScreen(web_contents_->GetView()->GetNativeView(), &temp);
    163   screen_point = temp;
    164 #endif
    165 
    166   // Enable recursive tasks on the message loop so we can get updates while
    167   // the context menu is being displayed.
    168   base::MessageLoop::ScopedNestableTaskAllower allow(
    169       base::MessageLoop::current());
    170   context_menu_->RunMenuAt(top_level_widget, screen_point, params.source_type);
    171 }
    172 
    173 void ChromeWebContentsViewDelegateViews::SizeChanged(const gfx::Size& size) {
    174   SadTabHelper* sad_tab_helper = SadTabHelper::FromWebContents(web_contents_);
    175   if (!sad_tab_helper)
    176     return;
    177   SadTabView* sad_tab = static_cast<SadTabView*>(sad_tab_helper->sad_tab());
    178   if (sad_tab)
    179     sad_tab->GetWidget()->SetBounds(gfx::Rect(size));
    180 }
    181 
    182 views::Widget* ChromeWebContentsViewDelegateViews::GetTopLevelWidget() {
    183   return views::Widget::GetTopLevelWidgetForNativeView(
    184       web_contents_->GetView()->GetNativeView());
    185 }
    186 
    187 views::FocusManager*
    188     ChromeWebContentsViewDelegateViews::GetFocusManager() {
    189   views::Widget* toplevel_widget = GetTopLevelWidget();
    190   return toplevel_widget ? toplevel_widget->GetFocusManager() : NULL;
    191 }
    192 
    193 void ChromeWebContentsViewDelegateViews::SetInitialFocus() {
    194   if (web_contents_->FocusLocationBarByDefault()) {
    195     if (web_contents_->GetDelegate())
    196       web_contents_->GetDelegate()->SetFocusToLocationBar(false);
    197   } else {
    198     web_contents_->GetView()->Focus();
    199   }
    200 }
    201 
    202 namespace chrome {
    203 
    204 content::WebContentsViewDelegate* CreateWebContentsViewDelegate(
    205     content::WebContents* web_contents) {
    206   return new ChromeWebContentsViewDelegateViews(web_contents);
    207 }
    208 
    209 }  // namespace chrome
    210