Home | History | Annotate | Download | only in frame
      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/frame/browser_view.h"
      6 
      7 #if defined(OS_LINUX)
      8 #include <gtk/gtk.h>
      9 #endif
     10 
     11 #include "base/auto_reset.h"
     12 #include "base/command_line.h"
     13 #include "base/i18n/rtl.h"
     14 #include "base/metrics/histogram.h"
     15 #include "base/string_number_conversions.h"
     16 #include "base/utf_string_conversions.h"
     17 #include "chrome/app/chrome_command_ids.h"
     18 #include "chrome/app/chrome_dll_resource.h"
     19 #include "chrome/browser/autocomplete/autocomplete_popup_model.h"
     20 #include "chrome/browser/autocomplete/autocomplete_popup_view.h"
     21 #include "chrome/browser/automation/ui_controls.h"
     22 #include "chrome/browser/bookmarks/bookmark_utils.h"
     23 #include "chrome/browser/browser_process.h"
     24 #include "chrome/browser/debugger/devtools_window.h"
     25 #include "chrome/browser/download/download_manager.h"
     26 #include "chrome/browser/extensions/extension_tab_helper.h"
     27 #include "chrome/browser/extensions/extension_tts_api.h"
     28 #include "chrome/browser/instant/instant_controller.h"
     29 #include "chrome/browser/metrics/user_metrics.h"
     30 #include "chrome/browser/ntp_background_util.h"
     31 #include "chrome/browser/page_info_window.h"
     32 #include "chrome/browser/prefs/pref_service.h"
     33 #include "chrome/browser/profiles/profile.h"
     34 #include "chrome/browser/sessions/tab_restore_service.h"
     35 #include "chrome/browser/sidebar/sidebar_container.h"
     36 #include "chrome/browser/sidebar/sidebar_manager.h"
     37 #include "chrome/browser/tabs/tab_strip_model.h"
     38 #include "chrome/browser/themes/theme_service.h"
     39 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
     40 #include "chrome/browser/ui/browser.h"
     41 #include "chrome/browser/ui/browser_dialogs.h"
     42 #include "chrome/browser/ui/browser_list.h"
     43 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     44 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
     45 #include "chrome/browser/ui/view_ids.h"
     46 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
     47 #include "chrome/browser/ui/views/browser_dialogs.h"
     48 #include "chrome/browser/ui/views/default_search_view.h"
     49 #include "chrome/browser/ui/views/download/download_in_progress_dialog_view.h"
     50 #include "chrome/browser/ui/views/download/download_shelf_view.h"
     51 #include "chrome/browser/ui/views/frame/browser_view_layout.h"
     52 #include "chrome/browser/ui/views/frame/contents_container.h"
     53 #include "chrome/browser/ui/views/fullscreen_exit_bubble.h"
     54 #include "chrome/browser/ui/views/infobars/infobar_container_view.h"
     55 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
     56 #include "chrome/browser/ui/views/status_bubble_views.h"
     57 #include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
     58 #include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
     59 #include "chrome/browser/ui/views/tabs/tab_strip_factory.h"
     60 #include "chrome/browser/ui/views/theme_install_bubble_view.h"
     61 #include "chrome/browser/ui/views/toolbar_view.h"
     62 #include "chrome/browser/ui/views/update_recommended_message_box.h"
     63 #include "chrome/browser/ui/views/window.h"
     64 #include "chrome/browser/ui/webui/bug_report_ui.h"
     65 #include "chrome/browser/ui/window_sizer.h"
     66 #include "chrome/common/chrome_switches.h"
     67 #include "chrome/common/extensions/extension_resource.h"
     68 #include "chrome/common/native_window_notification_source.h"
     69 #include "chrome/common/pref_names.h"
     70 #include "chrome/common/url_constants.h"
     71 #include "content/browser/renderer_host/render_widget_host_view.h"
     72 #include "content/browser/tab_contents/tab_contents.h"
     73 #include "content/browser/tab_contents/tab_contents_view.h"
     74 #include "content/common/notification_service.h"
     75 #include "grit/app_resources.h"
     76 #include "grit/chromium_strings.h"
     77 #include "grit/generated_resources.h"
     78 #include "grit/locale_settings.h"
     79 #include "grit/theme_resources.h"
     80 #include "grit/webkit_resources.h"
     81 #include "ui/base/accessibility/accessible_view_state.h"
     82 #include "ui/base/l10n/l10n_util.h"
     83 #include "ui/base/resource/resource_bundle.h"
     84 #include "ui/gfx/canvas_skia.h"
     85 #include "views/controls/single_split_view.h"
     86 #include "views/events/event.h"
     87 #include "views/focus/external_focus_tracker.h"
     88 #include "views/focus/view_storage.h"
     89 #include "views/layout/grid_layout.h"
     90 #include "views/widget/root_view.h"
     91 #include "views/window/dialog_delegate.h"
     92 #include "views/window/window.h"
     93 
     94 #if defined(OS_WIN)
     95 #include "chrome/browser/aeropeek_manager.h"
     96 #include "chrome/browser/jumplist_win.h"
     97 #include "ui/base/message_box_win.h"
     98 #include "ui/base/view_prop.h"
     99 #include "views/window/window_win.h"
    100 #elif defined(OS_LINUX)
    101 #include "chrome/browser/ui/views/accelerator_table_gtk.h"
    102 #include "views/window/hit_test.h"
    103 #include "views/window/window_gtk.h"
    104 #endif
    105 
    106 #if defined(OS_CHROMEOS)
    107 #include "chrome/browser/ui/views/keyboard_overlay_dialog_view.h"
    108 #endif
    109 
    110 using base::TimeDelta;
    111 using views::ColumnSet;
    112 using views::GridLayout;
    113 
    114 // The height of the status bubble.
    115 static const int kStatusBubbleHeight = 20;
    116 // The name of a key to store on the window handle so that other code can
    117 // locate this object using just the handle.
    118 static const char* const kBrowserViewKey = "__BROWSER_VIEW__";
    119 // How frequently we check for hung plugin windows.
    120 static const int kDefaultHungPluginDetectFrequency = 2000;
    121 // How long do we wait before we consider a window hung (in ms).
    122 static const int kDefaultPluginMessageResponseTimeout = 30000;
    123 // The number of milliseconds between loading animation frames.
    124 static const int kLoadingAnimationFrameTimeMs = 30;
    125 // The amount of space we expect the window border to take up.
    126 static const int kWindowBorderWidth = 5;
    127 
    128 // How round the 'new tab' style bookmarks bar is.
    129 static const int kNewtabBarRoundness = 5;
    130 // ------------
    131 
    132 // Returned from BrowserView::GetClassName.
    133 const char BrowserView::kViewClassName[] = "browser/ui/views/BrowserView";
    134 
    135 #if defined(OS_CHROMEOS)
    136 // Get a normal browser window of given |profile| to use as dialog parent
    137 // if given |browser| is not one. Otherwise, returns browser window of
    138 // |browser|. If |profile| is NULL, |browser|'s profile is used to find the
    139 // normal browser.
    140 static gfx::NativeWindow GetNormalBrowserWindowForBrowser(Browser* browser,
    141                                                           Profile* profile) {
    142   if (browser->type() != Browser::TYPE_NORMAL) {
    143     Browser* normal_browser = BrowserList::FindBrowserWithType(
    144         profile ? profile : browser->profile(),
    145         Browser::TYPE_NORMAL, true);
    146     if (normal_browser && normal_browser->window())
    147       return normal_browser->window()->GetNativeHandle();
    148   }
    149 
    150   return browser->window()->GetNativeHandle();
    151 }
    152 #endif  // defined(OS_CHROMEOS)
    153 
    154 ///////////////////////////////////////////////////////////////////////////////
    155 // BookmarkExtensionBackground, private:
    156 // This object serves as the views::Background object which is used to layout
    157 // and paint the bookmark bar.
    158 class BookmarkExtensionBackground : public views::Background {
    159  public:
    160   explicit BookmarkExtensionBackground(BrowserView* browser_view,
    161                                        DetachableToolbarView* host_view,
    162                                        Browser* browser);
    163 
    164   // View methods overridden from views:Background.
    165   virtual void Paint(gfx::Canvas* canvas, views::View* view) const;
    166 
    167  private:
    168   BrowserView* browser_view_;
    169 
    170   // The view hosting this background.
    171   DetachableToolbarView* host_view_;
    172 
    173   Browser* browser_;
    174 
    175   DISALLOW_COPY_AND_ASSIGN(BookmarkExtensionBackground);
    176 };
    177 
    178 BookmarkExtensionBackground::BookmarkExtensionBackground(
    179     BrowserView* browser_view,
    180     DetachableToolbarView* host_view,
    181     Browser* browser)
    182     : browser_view_(browser_view),
    183       host_view_(host_view),
    184       browser_(browser) {
    185 }
    186 
    187 void BookmarkExtensionBackground::Paint(gfx::Canvas* canvas,
    188                                         views::View* view) const {
    189   ui::ThemeProvider* tp = host_view_->GetThemeProvider();
    190   int toolbar_overlap = host_view_->GetToolbarOverlap();
    191   // The client edge is drawn below the toolbar bounds.
    192   if (toolbar_overlap)
    193     toolbar_overlap += views::NonClientFrameView::kClientEdgeThickness;
    194   if (host_view_->IsDetached()) {
    195     // Draw the background to match the new tab page.
    196     int height = 0;
    197     TabContents* contents = browser_->GetSelectedTabContents();
    198     if (contents && contents->view())
    199       height = contents->view()->GetContainerSize().height();
    200     NtpBackgroundUtil::PaintBackgroundDetachedMode(
    201         host_view_->GetThemeProvider(), canvas,
    202         gfx::Rect(0, toolbar_overlap, host_view_->width(),
    203                   host_view_->height() - toolbar_overlap), height);
    204 
    205     // As 'hidden' according to the animation is the full in-tab state,
    206     // we invert the value - when current_state is at '0', we expect the
    207     // bar to be docked.
    208     double current_state = 1 - host_view_->GetAnimationValue();
    209     double h_padding =
    210         static_cast<double>(BookmarkBarView::kNewtabHorizontalPadding) *
    211         current_state;
    212     double v_padding =
    213         static_cast<double>(BookmarkBarView::kNewtabVerticalPadding) *
    214         current_state;
    215 
    216     SkRect rect;
    217     double roundness = 0;
    218     DetachableToolbarView::CalculateContentArea(current_state, h_padding,
    219         v_padding, &rect, &roundness, host_view_);
    220     DetachableToolbarView::PaintContentAreaBackground(canvas, tp, rect,
    221                                                       roundness);
    222     DetachableToolbarView::PaintContentAreaBorder(canvas, tp, rect, roundness);
    223     if (!toolbar_overlap)
    224       DetachableToolbarView::PaintHorizontalBorder(canvas, host_view_);
    225   } else {
    226     DetachableToolbarView::PaintBackgroundAttachedMode(canvas, host_view_,
    227         browser_view_->OffsetPointForToolbarBackgroundImage(
    228         gfx::Point(host_view_->GetMirroredX(), host_view_->y())));
    229     if (host_view_->height() >= toolbar_overlap)
    230       DetachableToolbarView::PaintHorizontalBorder(canvas, host_view_);
    231   }
    232 }
    233 
    234 ///////////////////////////////////////////////////////////////////////////////
    235 // ResizeCorner, private:
    236 
    237 class ResizeCorner : public views::View {
    238  public:
    239   ResizeCorner() {
    240     EnableCanvasFlippingForRTLUI(true);
    241   }
    242 
    243   virtual void OnPaint(gfx::Canvas* canvas) {
    244     views::Window* window = GetWindow();
    245     if (!window || (window->IsMaximized() || window->IsFullscreen()))
    246       return;
    247 
    248     SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
    249         IDR_TEXTAREA_RESIZER);
    250     bitmap->buildMipMap(false);
    251     canvas->DrawBitmapInt(*bitmap, width() - bitmap->width(),
    252                           height() - bitmap->height());
    253   }
    254 
    255   static gfx::Size GetSize() {
    256     // This is disabled until we find what makes us slower when we let
    257     // WebKit know that we have a resizer rect...
    258     // int scrollbar_thickness = gfx::scrollbar_size();
    259     // return gfx::Size(scrollbar_thickness, scrollbar_thickness);
    260     return gfx::Size();
    261   }
    262 
    263   virtual gfx::Size GetPreferredSize() {
    264     views::Window* window = GetWindow();
    265     return (!window || window->IsMaximized() || window->IsFullscreen()) ?
    266         gfx::Size() : GetSize();
    267   }
    268 
    269   virtual void Layout() {
    270     if (parent()) {
    271       gfx::Size ps = GetPreferredSize();
    272       // No need to handle Right to left text direction here,
    273       // our parent must take care of it for us...
    274       // TODO(alekseys): fix it.
    275       SetBounds(parent()->width() - ps.width(),
    276                 parent()->height() - ps.height(), ps.width(), ps.height());
    277     }
    278   }
    279 
    280  private:
    281   // Returns the WindowWin we're displayed in. Returns NULL if we're not
    282   // currently in a window.
    283   views::Window* GetWindow() {
    284     views::Widget* widget = GetWidget();
    285     return widget ? widget->GetWindow() : NULL;
    286   }
    287 
    288   DISALLOW_COPY_AND_ASSIGN(ResizeCorner);
    289 };
    290 
    291 ///////////////////////////////////////////////////////////////////////////////
    292 // BrowserView, public:
    293 
    294 BrowserView::BrowserView(Browser* browser)
    295     : views::ClientView(NULL, NULL),
    296       last_focused_view_storage_id_(
    297           views::ViewStorage::GetInstance()->CreateStorageID()),
    298       frame_(NULL),
    299       browser_(browser),
    300       active_bookmark_bar_(NULL),
    301       tabstrip_(NULL),
    302       toolbar_(NULL),
    303       infobar_container_(NULL),
    304       sidebar_container_(NULL),
    305       sidebar_split_(NULL),
    306       contents_container_(NULL),
    307       devtools_container_(NULL),
    308       preview_container_(NULL),
    309       contents_(NULL),
    310       contents_split_(NULL),
    311       initialized_(false),
    312       ignore_layout_(true)
    313 #if defined(OS_WIN)
    314       , hung_window_detector_(&hung_plugin_action_),
    315       ticker_(0)
    316 #endif
    317                  {
    318   browser_->tabstrip_model()->AddObserver(this);
    319 
    320   registrar_.Add(this,
    321                  NotificationType::SIDEBAR_CHANGED,
    322                  Source<SidebarManager>(SidebarManager::GetInstance()));
    323 }
    324 
    325 BrowserView::~BrowserView() {
    326   browser_->tabstrip_model()->RemoveObserver(this);
    327 
    328 #if defined(OS_WIN)
    329   // Remove this observer.
    330   if (aeropeek_manager_.get())
    331     browser_->tabstrip_model()->RemoveObserver(aeropeek_manager_.get());
    332 
    333   // Stop hung plugin monitoring.
    334   ticker_.Stop();
    335   ticker_.UnregisterTickHandler(&hung_window_detector_);
    336 #endif
    337 
    338   // We destroy the download shelf before |browser_| to remove its child
    339   // download views from the set of download observers (since the observed
    340   // downloads can be destroyed along with |browser_| and the observer
    341   // notifications will call back into deleted objects).
    342   download_shelf_.reset();
    343 
    344   // The TabStrip attaches a listener to the model. Make sure we shut down the
    345   // TabStrip first so that it can cleanly remove the listener.
    346   if (tabstrip_) {
    347     tabstrip_->parent()->RemoveChildView(tabstrip_);
    348     delete tabstrip_;
    349     tabstrip_ = NULL;
    350   }
    351   // Child views maintain PrefMember attributes that point to
    352   // OffTheRecordProfile's PrefService which gets deleted by ~Browser.
    353   RemoveAllChildViews(true);
    354   // Explicitly set browser_ to NULL.
    355   browser_.reset();
    356 }
    357 
    358 // static
    359 BrowserView* BrowserView::GetBrowserViewForNativeWindow(
    360     gfx::NativeWindow window) {
    361 #if defined(OS_WIN)
    362   if (IsWindow(window)) {
    363     return reinterpret_cast<BrowserView*>(
    364         ui::ViewProp::GetValue(window, kBrowserViewKey));
    365   }
    366 #else
    367   if (window) {
    368     return static_cast<BrowserView*>(
    369         g_object_get_data(G_OBJECT(window), kBrowserViewKey));
    370   }
    371 #endif
    372   return NULL;
    373 }
    374 
    375 gfx::Rect BrowserView::GetToolbarBounds() const {
    376   gfx::Rect toolbar_bounds(toolbar_->bounds());
    377   if (toolbar_bounds.IsEmpty())
    378     return toolbar_bounds;
    379   // When using vertical tabs, the toolbar appears to extend behind the tab
    380   // column.
    381   if (UseVerticalTabs())
    382     toolbar_bounds.Inset(tabstrip_->x() - toolbar_bounds.x(), 0, 0, 0);
    383   // The apparent toolbar edges are outside the "real" toolbar edges.
    384   toolbar_bounds.Inset(-views::NonClientFrameView::kClientEdgeThickness, 0);
    385   return toolbar_bounds;
    386 }
    387 
    388 gfx::Rect BrowserView::GetClientAreaBounds() const {
    389   gfx::Rect container_bounds = contents_->bounds();
    390   gfx::Point container_origin = container_bounds.origin();
    391   ConvertPointToView(this, parent(), &container_origin);
    392   container_bounds.set_origin(container_origin);
    393   return container_bounds;
    394 }
    395 
    396 gfx::Rect BrowserView::GetFindBarBoundingBox() const {
    397   return GetBrowserViewLayout()->GetFindBarBoundingBox();
    398 }
    399 
    400 int BrowserView::GetTabStripHeight() const {
    401   // We want to return tabstrip_->height(), but we might be called in the midst
    402   // of layout, when that hasn't yet been updated to reflect the current state.
    403   // So return what the tabstrip height _ought_ to be right now.
    404   return IsTabStripVisible() ? tabstrip_->GetPreferredSize().height() : 0;
    405 }
    406 
    407 gfx::Point BrowserView::OffsetPointForToolbarBackgroundImage(
    408     const gfx::Point& point) const {
    409   // The background image starts tiling horizontally at the window left edge and
    410   // vertically at the top edge of the horizontal tab strip (or where it would
    411   // be).  We expect our parent's origin to be the window origin.
    412   gfx::Point window_point(point.Add(GetMirroredPosition()));
    413   window_point.Offset(0, -frame_->GetHorizontalTabStripVerticalOffset(false));
    414   return window_point;
    415 }
    416 
    417 int BrowserView::GetSidebarWidth() const {
    418   if (!sidebar_container_ || !sidebar_container_->IsVisible())
    419     return 0;
    420   return sidebar_split_->divider_offset();
    421 }
    422 
    423 bool BrowserView::IsTabStripVisible() const {
    424   return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP);
    425 }
    426 
    427 bool BrowserView::UseVerticalTabs() const {
    428   return browser_->tabstrip_model()->delegate()->UseVerticalTabs();
    429 }
    430 
    431 bool BrowserView::IsOffTheRecord() const {
    432   return browser_->profile()->IsOffTheRecord();
    433 }
    434 
    435 bool BrowserView::ShouldShowOffTheRecordAvatar() const {
    436   return IsOffTheRecord() && IsBrowserTypeNormal();
    437 }
    438 
    439 bool BrowserView::AcceleratorPressed(const views::Accelerator& accelerator) {
    440 #if defined(OS_CHROMEOS)
    441   // If accessibility is enabled, stop speech and return false so that key
    442   // combinations involving Search can be used for extra accessibility
    443   // functionality.
    444   if (accelerator.GetKeyCode() == ui::VKEY_LWIN &&
    445       g_browser_process->local_state()->GetBoolean(
    446           prefs::kAccessibilityEnabled)) {
    447     ExtensionTtsController::GetInstance()->Stop();
    448     return false;
    449   }
    450 #endif
    451 
    452   std::map<views::Accelerator, int>::const_iterator iter =
    453       accelerator_table_.find(accelerator);
    454   DCHECK(iter != accelerator_table_.end());
    455   int command_id = iter->second;
    456 
    457   if (!browser_->block_command_execution())
    458     UpdateAcceleratorMetrics(accelerator, command_id);
    459   return browser_->ExecuteCommandIfEnabled(command_id);
    460 }
    461 
    462 bool BrowserView::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) {
    463   // The standard Ctrl-X, Ctrl-V and Ctrl-C are not defined as accelerators
    464   // anywhere so we need to check for them explicitly here.
    465   switch (cmd_id) {
    466     case IDC_CUT:
    467       *accelerator = views::Accelerator(ui::VKEY_X, false, true, false);
    468       return true;
    469     case IDC_COPY:
    470       *accelerator = views::Accelerator(ui::VKEY_C, false, true, false);
    471       return true;
    472     case IDC_PASTE:
    473       *accelerator = views::Accelerator(ui::VKEY_V, false, true, false);
    474       return true;
    475   }
    476   // Else, we retrieve the accelerator information from the accelerator table.
    477   std::map<views::Accelerator, int>::iterator it =
    478       accelerator_table_.begin();
    479   for (; it != accelerator_table_.end(); ++it) {
    480     if (it->second == cmd_id) {
    481       *accelerator = it->first;
    482       return true;
    483     }
    484   }
    485   return false;
    486 }
    487 
    488 bool BrowserView::ActivateAppModalDialog() const {
    489   // If another browser is app modal, flash and activate the modal browser.
    490   if (AppModalDialogQueue::GetInstance()->HasActiveDialog()) {
    491     Browser* active_browser = BrowserList::GetLastActive();
    492     if (active_browser && (browser_ != active_browser)) {
    493       active_browser->window()->FlashFrame();
    494       active_browser->window()->Activate();
    495     }
    496     AppModalDialogQueue::GetInstance()->ActivateModalDialog();
    497     return true;
    498   }
    499   return false;
    500 }
    501 
    502 TabContents* BrowserView::GetSelectedTabContents() const {
    503   return browser_->GetSelectedTabContents();
    504 }
    505 
    506 TabContentsWrapper* BrowserView::GetSelectedTabContentsWrapper() const {
    507   return browser_->GetSelectedTabContentsWrapper();
    508 }
    509 
    510 SkBitmap BrowserView::GetOTRAvatarIcon() {
    511   static SkBitmap* otr_avatar_ = new SkBitmap();
    512 
    513   if (otr_avatar_->isNull()) {
    514     ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    515     *otr_avatar_ = *rb.GetBitmapNamed(IDR_OTR_ICON);
    516   }
    517   return *otr_avatar_;
    518 }
    519 
    520 #if defined(OS_WIN)
    521 void BrowserView::PrepareToRunSystemMenu(HMENU menu) {
    522   system_menu_->UpdateStates();
    523 }
    524 #endif
    525 
    526 // static
    527 void BrowserView::RegisterBrowserViewPrefs(PrefService* prefs) {
    528   prefs->RegisterIntegerPref(prefs::kPluginMessageResponseTimeout,
    529                              kDefaultPluginMessageResponseTimeout);
    530   prefs->RegisterIntegerPref(prefs::kHungPluginDetectFrequency,
    531                              kDefaultHungPluginDetectFrequency);
    532 }
    533 
    534 bool BrowserView::IsPositionInWindowCaption(const gfx::Point& point) {
    535   return GetBrowserViewLayout()->IsPositionInWindowCaption(point);
    536 }
    537 
    538 ///////////////////////////////////////////////////////////////////////////////
    539 // BrowserView, BrowserWindow implementation:
    540 
    541 void BrowserView::Show() {
    542   // If the window is already visible, just activate it.
    543   if (frame_->GetWindow()->IsVisible()) {
    544     frame_->GetWindow()->Activate();
    545     return;
    546   }
    547 
    548   // Setting the focus doesn't work when the window is invisible, so any focus
    549   // initialization that happened before this will be lost.
    550   //
    551   // We really "should" restore the focus whenever the window becomes unhidden,
    552   // but I think initializing is the only time where this can happen where
    553   // there is some focus change we need to pick up, and this is easier than
    554   // plumbing through an un-hide message all the way from the frame.
    555   //
    556   // If we do find there are cases where we need to restore the focus on show,
    557   // that should be added and this should be removed.
    558   RestoreFocus();
    559 
    560   frame_->GetWindow()->Show();
    561 }
    562 
    563 void BrowserView::ShowInactive() {
    564   views::Window* window = frame_->GetWindow();
    565   if (!window->IsVisible())
    566     window->ShowInactive();
    567 }
    568 
    569 void BrowserView::SetBounds(const gfx::Rect& bounds) {
    570   SetFullscreen(false);
    571   GetWidget()->SetBounds(bounds);
    572 }
    573 
    574 void BrowserView::Close() {
    575   BrowserBubbleHost::Close();
    576 
    577   frame_->GetWindow()->CloseWindow();
    578 }
    579 
    580 void BrowserView::Activate() {
    581   frame_->GetWindow()->Activate();
    582 }
    583 
    584 void BrowserView::Deactivate() {
    585   frame_->GetWindow()->Deactivate();
    586 }
    587 
    588 bool BrowserView::IsActive() const {
    589   return frame_->GetWindow()->IsActive();
    590 }
    591 
    592 void BrowserView::FlashFrame() {
    593 #if defined(OS_WIN)
    594   FLASHWINFO fwi;
    595   fwi.cbSize = sizeof(fwi);
    596   fwi.hwnd = frame_->GetWindow()->GetNativeWindow();
    597   fwi.dwFlags = FLASHW_ALL;
    598   fwi.uCount = 4;
    599   fwi.dwTimeout = 0;
    600   FlashWindowEx(&fwi);
    601 #else
    602   // Doesn't matter for chrome os.
    603 #endif
    604 }
    605 
    606 gfx::NativeWindow BrowserView::GetNativeHandle() {
    607   return GetWidget()->GetWindow()->GetNativeWindow();
    608 }
    609 
    610 BrowserWindowTesting* BrowserView::GetBrowserWindowTesting() {
    611   return this;
    612 }
    613 
    614 StatusBubble* BrowserView::GetStatusBubble() {
    615   return status_bubble_.get();
    616 }
    617 
    618 namespace {
    619   // Only used by ToolbarSizeChanged() below, but placed here because template
    620   // arguments (to AutoReset<>) must have external linkage.
    621   enum CallState { NORMAL, REENTRANT, REENTRANT_FORCE_FAST_RESIZE };
    622 }
    623 
    624 void BrowserView::ToolbarSizeChanged(bool is_animating) {
    625   // The call to InfoBarContainer::SetMaxTopArrowHeight() below can result in
    626   // reentrancy; |call_state| tracks whether we're reentrant.  We can't just
    627   // early-return in this case because we need to layout again so the infobar
    628   // container's bounds are set correctly.
    629   static CallState call_state = NORMAL;
    630 
    631   // A reentrant call can (and should) use the fast resize path unless both it
    632   // and the normal call are both non-animating.
    633   bool use_fast_resize =
    634       is_animating || (call_state == REENTRANT_FORCE_FAST_RESIZE);
    635   if (use_fast_resize)
    636     contents_container_->SetFastResize(true);
    637   UpdateUIForContents(browser_->GetSelectedTabContentsWrapper());
    638   if (use_fast_resize)
    639     contents_container_->SetFastResize(false);
    640 
    641   // Inform the InfoBarContainer that the distance to the location icon may have
    642   // changed.  We have to do this after the block above so that the toolbars are
    643   // laid out correctly for calculating the maximum arrow height below.
    644   {
    645     const LocationIconView* location_icon_view =
    646         toolbar_->location_bar()->location_icon_view();
    647     // The +1 in the next line creates a 1-px gap between icon and arrow tip.
    648     gfx::Point icon_bottom(0, location_icon_view->GetImageBounds().bottom() -
    649         LocationBarView::kIconInternalPadding + 1);
    650     ConvertPointToView(location_icon_view, this, &icon_bottom);
    651     gfx::Point infobar_top(0, infobar_container_->GetVerticalOverlap(NULL));
    652     ConvertPointToView(infobar_container_, this, &infobar_top);
    653 
    654     AutoReset<CallState> resetter(&call_state,
    655         is_animating ? REENTRANT_FORCE_FAST_RESIZE : REENTRANT);
    656     infobar_container_->SetMaxTopArrowHeight(infobar_top.y() - icon_bottom.y());
    657   }
    658 
    659   // When transitioning from animating to not animating we need to make sure the
    660   // contents_container_ gets layed out. If we don't do this and the bounds
    661   // haven't changed contents_container_ won't get a Layout out and we'll end up
    662   // with a gray rect because the clip wasn't updated.  Note that a reentrant
    663   // call never needs to do this, because after it returns, the normal call
    664   // wrapping it will do it.
    665   if ((call_state == NORMAL) && !is_animating) {
    666     contents_container_->InvalidateLayout();
    667     contents_split_->Layout();
    668   }
    669 }
    670 
    671 void BrowserView::UpdateTitleBar() {
    672   frame_->GetWindow()->UpdateWindowTitle();
    673   if (ShouldShowWindowIcon() && !loading_animation_timer_.IsRunning())
    674     frame_->GetWindow()->UpdateWindowIcon();
    675 }
    676 
    677 void BrowserView::ShelfVisibilityChanged() {
    678   Layout();
    679 }
    680 
    681 void BrowserView::UpdateDevTools() {
    682   UpdateDevToolsForContents(GetSelectedTabContentsWrapper());
    683   Layout();
    684 }
    685 
    686 void BrowserView::UpdateLoadingAnimations(bool should_animate) {
    687   if (should_animate) {
    688     if (!loading_animation_timer_.IsRunning()) {
    689       // Loads are happening, and the timer isn't running, so start it.
    690       last_animation_time_ = base::TimeTicks::Now();
    691       loading_animation_timer_.Start(
    692           TimeDelta::FromMilliseconds(kLoadingAnimationFrameTimeMs), this,
    693           &BrowserView::LoadingAnimationCallback);
    694     }
    695   } else {
    696     if (loading_animation_timer_.IsRunning()) {
    697       last_animation_time_ = base::TimeTicks();
    698       loading_animation_timer_.Stop();
    699       // Loads are now complete, update the state if a task was scheduled.
    700       LoadingAnimationCallback();
    701     }
    702   }
    703 }
    704 
    705 void BrowserView::SetStarredState(bool is_starred) {
    706   toolbar_->location_bar()->SetStarToggled(is_starred);
    707 }
    708 
    709 gfx::Rect BrowserView::GetRestoredBounds() const {
    710   return frame_->GetWindow()->GetNormalBounds();
    711 }
    712 
    713 gfx::Rect BrowserView::GetBounds() const {
    714   return frame_->GetWindow()->GetBounds();
    715 }
    716 
    717 bool BrowserView::IsMaximized() const {
    718   return frame_->GetWindow()->IsMaximized();
    719 }
    720 
    721 void BrowserView::SetFullscreen(bool fullscreen) {
    722   if (IsFullscreen() == fullscreen)
    723     return;  // Nothing to do.
    724 
    725 #if defined(OS_WIN)
    726   ProcessFullscreen(fullscreen);
    727 #else
    728   // On Linux changing fullscreen is async. Ask the window to change it's
    729   // fullscreen state, and when done invoke ProcessFullscreen.
    730   frame_->GetWindow()->SetFullscreen(fullscreen);
    731 #endif
    732 }
    733 
    734 bool BrowserView::IsFullscreen() const {
    735   return frame_->GetWindow()->IsFullscreen();
    736 }
    737 
    738 bool BrowserView::IsFullscreenBubbleVisible() const {
    739   return fullscreen_bubble_.get() ? true : false;
    740 }
    741 
    742 void BrowserView::FullScreenStateChanged() {
    743   ProcessFullscreen(IsFullscreen());
    744 }
    745 
    746 void BrowserView::RestoreFocus() {
    747   TabContents* selected_tab_contents = GetSelectedTabContents();
    748   if (selected_tab_contents)
    749     selected_tab_contents->view()->RestoreFocus();
    750 }
    751 
    752 LocationBar* BrowserView::GetLocationBar() const {
    753   return toolbar_->location_bar();
    754 }
    755 
    756 void BrowserView::SetFocusToLocationBar(bool select_all) {
    757   LocationBarView* location_bar = toolbar_->location_bar();
    758   if (location_bar->IsFocusableInRootView()) {
    759     // Location bar got focus.
    760     location_bar->FocusLocation(select_all);
    761   } else {
    762     // If none of location bar/compact navigation bar got focus,
    763     // then clear focus.
    764     views::FocusManager* focus_manager = GetFocusManager();
    765     DCHECK(focus_manager);
    766     focus_manager->ClearFocus();
    767   }
    768 }
    769 
    770 void BrowserView::UpdateReloadStopState(bool is_loading, bool force) {
    771   toolbar_->reload_button()->ChangeMode(
    772       is_loading ? ReloadButton::MODE_STOP : ReloadButton::MODE_RELOAD, force);
    773 }
    774 
    775 void BrowserView::UpdateToolbar(TabContentsWrapper* contents,
    776                                 bool should_restore_state) {
    777   toolbar_->Update(contents->tab_contents(), should_restore_state);
    778 }
    779 
    780 void BrowserView::FocusToolbar() {
    781   // Start the traversal within the main toolbar, passing it the storage id
    782   // of the view where focus should be returned if the user exits the toolbar.
    783   SaveFocusedView();
    784   toolbar_->SetPaneFocus(last_focused_view_storage_id_, NULL);
    785 }
    786 
    787 void BrowserView::FocusBookmarksToolbar() {
    788   if (active_bookmark_bar_ && bookmark_bar_view_->IsVisible()) {
    789     SaveFocusedView();
    790     bookmark_bar_view_->SetPaneFocus(last_focused_view_storage_id_, NULL);
    791   }
    792 }
    793 
    794 void BrowserView::FocusAppMenu() {
    795   // Chrome doesn't have a traditional menu bar, but it has a menu button in the
    796   // main toolbar that plays the same role.  If the user presses a key that
    797   // would typically focus the menu bar, tell the toolbar to focus the menu
    798   // button.  If the user presses the key again, return focus to the previous
    799   // location.
    800   //
    801   // Not used on the Mac, which has a normal menu bar.
    802   if (toolbar_->IsAppMenuFocused()) {
    803     RestoreFocus();
    804   } else {
    805     SaveFocusedView();
    806     toolbar_->SetPaneFocusAndFocusAppMenu(last_focused_view_storage_id_);
    807   }
    808 }
    809 
    810 void BrowserView::RotatePaneFocus(bool forwards) {
    811   // This gets called when the user presses F6 (forwards) or Shift+F6
    812   // (backwards) to rotate to the next pane. Here, our "panes" are the
    813   // tab contents and each of our accessible toolbars, infobars, downloads
    814   // shelf, etc.  When a pane has focus, all of its controls are accessible
    815   // in the tab traversal, and the tab traversal is "trapped" within that pane.
    816   //
    817   // Get a vector of all panes in the order we want them to be focused,
    818   // with NULL to represent the tab contents getting focus. If one of these
    819   // is currently invisible or has no focusable children it will be
    820   // automatically skipped.
    821   std::vector<AccessiblePaneView*> accessible_panes;
    822   GetAccessiblePanes(&accessible_panes);
    823   int pane_count = static_cast<int>(accessible_panes.size());
    824 
    825   std::vector<views::View*> accessible_views(
    826       accessible_panes.begin(), accessible_panes.end());
    827   accessible_views.push_back(GetTabContentsContainerView());
    828   if (sidebar_container_ && sidebar_container_->IsVisible())
    829     accessible_views.push_back(GetSidebarContainerView());
    830   if (devtools_container_->IsVisible())
    831     accessible_views.push_back(devtools_container_->GetFocusView());
    832   int count = static_cast<int>(accessible_views.size());
    833 
    834   // Figure out which view (if any) currently has the focus.
    835   views::View* focused_view = GetFocusManager()->GetFocusedView();
    836   int index = -1;
    837   if (focused_view) {
    838     for (int i = 0; i < count; ++i) {
    839       if (accessible_views[i] == focused_view ||
    840           accessible_views[i]->Contains(focused_view)) {
    841         index = i;
    842         break;
    843       }
    844     }
    845   }
    846 
    847   // If the focus isn't currently in a pane, save the focus so we
    848   // can restore it if the user presses Escape.
    849   if (focused_view && index >= pane_count)
    850     SaveFocusedView();
    851 
    852   // Try to focus the next pane; if SetPaneFocusAndFocusDefault returns
    853   // false it means the pane didn't have any focusable controls, so skip
    854   // it and try the next one.
    855   for (;;) {
    856     if (forwards)
    857       index = (index + 1) % count;
    858     else
    859       index = ((index - 1) + count) % count;
    860 
    861     if (index < pane_count) {
    862       if (accessible_panes[index]->SetPaneFocusAndFocusDefault(
    863               last_focused_view_storage_id_)) {
    864         break;
    865       }
    866     } else {
    867       accessible_views[index]->RequestFocus();
    868       break;
    869     }
    870   }
    871 }
    872 
    873 void BrowserView::SaveFocusedView() {
    874   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
    875   if (view_storage->RetrieveView(last_focused_view_storage_id_))
    876     view_storage->RemoveView(last_focused_view_storage_id_);
    877   views::View* focused_view = GetFocusManager()->GetFocusedView();
    878   if (focused_view)
    879     view_storage->StoreView(last_focused_view_storage_id_, focused_view);
    880 }
    881 
    882 void BrowserView::DestroyBrowser() {
    883   // Explicitly delete the BookmarkBarView now. That way we don't have to
    884   // worry about the BookmarkBarView potentially outliving the Browser &
    885   // Profile.
    886   bookmark_bar_view_.reset();
    887   browser_.reset();
    888 }
    889 
    890 bool BrowserView::IsBookmarkBarVisible() const {
    891   return browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR) &&
    892       active_bookmark_bar_ &&
    893       (active_bookmark_bar_->GetPreferredSize().height() != 0);
    894 }
    895 
    896 bool BrowserView::IsBookmarkBarAnimating() const {
    897   return bookmark_bar_view_.get() && bookmark_bar_view_->is_animating();
    898 }
    899 
    900 bool BrowserView::IsTabStripEditable() const {
    901   return tabstrip_->IsTabStripEditable();
    902 }
    903 
    904 bool BrowserView::IsToolbarVisible() const {
    905   return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) ||
    906          browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
    907 }
    908 
    909 void BrowserView::DisableInactiveFrame() {
    910 #if defined(OS_WIN)
    911   frame_->GetWindow()->DisableInactiveRendering();
    912 #endif  // No tricks are needed to get the right behavior on Linux.
    913 }
    914 
    915 void BrowserView::ConfirmSetDefaultSearchProvider(
    916     TabContents* tab_contents,
    917     TemplateURL* template_url,
    918     TemplateURLModel* template_url_model) {
    919 #if defined(OS_WIN)
    920   DefaultSearchView::Show(tab_contents, template_url, template_url_model);
    921 #else
    922   // TODO(levin): Implement for other platforms. Right now this is behind
    923   // a command line flag which is off. http://crbug.com/38475
    924 #endif
    925 }
    926 
    927 void BrowserView::ConfirmAddSearchProvider(const TemplateURL* template_url,
    928                                            Profile* profile) {
    929   browser::EditSearchEngine(GetWindow()->GetNativeWindow(), template_url, NULL,
    930                             profile);
    931 }
    932 
    933 void BrowserView::ToggleBookmarkBar() {
    934   bookmark_utils::ToggleWhenVisible(browser_->profile());
    935 }
    936 
    937 void BrowserView::ShowAboutChromeDialog() {
    938   DoShowAboutChromeDialog();
    939 }
    940 
    941 views::Window* BrowserView::DoShowAboutChromeDialog() {
    942   return browser::ShowAboutChromeView(GetWindow()->GetNativeWindow(),
    943                                       browser_->profile());
    944 }
    945 
    946 void BrowserView::ShowUpdateChromeDialog() {
    947   UpdateRecommendedMessageBox::ShowMessageBox(GetWindow()->GetNativeWindow());
    948 }
    949 
    950 void BrowserView::ShowTaskManager() {
    951   browser::ShowTaskManager();
    952 }
    953 
    954 void BrowserView::ShowBackgroundPages() {
    955   browser::ShowBackgroundPages();
    956 }
    957 
    958 void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) {
    959   toolbar_->location_bar()->ShowStarBubble(url, !already_bookmarked);
    960 }
    961 
    962 void BrowserView::SetDownloadShelfVisible(bool visible) {
    963   // This can be called from the superclass destructor, when it destroys our
    964   // child views. At that point, browser_ is already gone.
    965   if (browser_ == NULL)
    966     return;
    967 
    968   if (visible && IsDownloadShelfVisible() != visible) {
    969     // Invoke GetDownloadShelf to force the shelf to be created.
    970     GetDownloadShelf();
    971   }
    972 
    973   if (browser_ != NULL)
    974     browser_->UpdateDownloadShelfVisibility(visible);
    975 
    976   // SetDownloadShelfVisible can force-close the shelf, so make sure we lay out
    977   // everything correctly, as if the animation had finished. This doesn't
    978   // matter for showing the shelf, as the show animation will do it.
    979   ToolbarSizeChanged(false);
    980 }
    981 
    982 bool BrowserView::IsDownloadShelfVisible() const {
    983   return download_shelf_.get() && download_shelf_->IsShowing();
    984 }
    985 
    986 DownloadShelf* BrowserView::GetDownloadShelf() {
    987   if (!download_shelf_.get()) {
    988     download_shelf_.reset(new DownloadShelfView(browser_.get(), this));
    989     download_shelf_->set_parent_owned(false);
    990   }
    991   return download_shelf_.get();
    992 }
    993 
    994 void BrowserView::ShowRepostFormWarningDialog(TabContents* tab_contents) {
    995   browser::ShowRepostFormWarningDialog(GetNativeHandle(), tab_contents);
    996 }
    997 
    998 void BrowserView::ShowCollectedCookiesDialog(TabContents* tab_contents) {
    999   browser::ShowCollectedCookiesDialog(GetNativeHandle(), tab_contents);
   1000 }
   1001 
   1002 void BrowserView::ShowThemeInstallBubble() {
   1003   TabContents* tab_contents = browser_->GetSelectedTabContents();
   1004   if (!tab_contents)
   1005     return;
   1006   ThemeInstallBubbleView::Show(tab_contents);
   1007 }
   1008 
   1009 void BrowserView::ConfirmBrowserCloseWithPendingDownloads() {
   1010   DownloadInProgressDialogView* view =
   1011       new DownloadInProgressDialogView(browser_.get());
   1012   browser::CreateViewsWindow(GetNativeHandle(), gfx::Rect(), view)->Show();
   1013 }
   1014 
   1015 void BrowserView::ShowHTMLDialog(HtmlDialogUIDelegate* delegate,
   1016                                  gfx::NativeWindow parent_window) {
   1017   // Default to using our window as the parent if the argument is not specified.
   1018   gfx::NativeWindow parent = parent_window ? parent_window
   1019                                            : GetNativeHandle();
   1020 #if defined(OS_CHROMEOS)
   1021   parent = GetNormalBrowserWindowForBrowser(browser(), NULL);
   1022 #endif  // defined(OS_CHROMEOS)
   1023 
   1024   browser::ShowHtmlDialog(parent, browser_.get()->profile(), delegate);
   1025 }
   1026 
   1027 void BrowserView::ShowCreateWebAppShortcutsDialog(
   1028     TabContentsWrapper* tab_contents) {
   1029   browser::ShowCreateWebAppShortcutsDialog(GetNativeHandle(), tab_contents);
   1030 }
   1031 
   1032 void BrowserView::ShowCreateChromeAppShortcutsDialog(Profile* profile,
   1033                                                      const Extension* app) {
   1034   browser::ShowCreateChromeAppShortcutsDialog(GetNativeHandle(), profile, app);
   1035 }
   1036 
   1037 void BrowserView::UserChangedTheme() {
   1038   frame_->GetWindow()->FrameTypeChanged();
   1039 }
   1040 
   1041 int BrowserView::GetExtraRenderViewHeight() const {
   1042   // Currently this is only used on linux.
   1043   return 0;
   1044 }
   1045 
   1046 void BrowserView::TabContentsFocused(TabContents* tab_contents) {
   1047   contents_container_->TabContentsFocused(tab_contents);
   1048 }
   1049 
   1050 void BrowserView::ShowPageInfo(Profile* profile,
   1051                                const GURL& url,
   1052                                const NavigationEntry::SSLStatus& ssl,
   1053                                bool show_history) {
   1054   gfx::NativeWindow parent = GetWindow()->GetNativeWindow();
   1055 
   1056   browser::ShowPageInfoBubble(parent, profile, url, ssl, show_history);
   1057 }
   1058 
   1059 void BrowserView::ShowAppMenu() {
   1060   toolbar_->app_menu()->Activate();
   1061 }
   1062 
   1063 bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
   1064                                          bool* is_keyboard_shortcut) {
   1065   if (event.type != WebKit::WebInputEvent::RawKeyDown)
   1066     return false;
   1067 
   1068 #if defined(OS_WIN)
   1069   // As Alt+F4 is the close-app keyboard shortcut, it needs processing
   1070   // immediately.
   1071   if (event.windowsKeyCode == ui::VKEY_F4 &&
   1072       event.modifiers == NativeWebKeyboardEvent::AltKey) {
   1073     DefWindowProc(event.os_event.hwnd, event.os_event.message,
   1074                   event.os_event.wParam, event.os_event.lParam);
   1075     return true;
   1076   }
   1077 #endif
   1078 
   1079   views::FocusManager* focus_manager = GetFocusManager();
   1080   DCHECK(focus_manager);
   1081 
   1082 #if defined(OS_LINUX) && !defined(TOUCH_UI)
   1083   // Views and WebKit use different tables for GdkEventKey -> views::KeyEvent
   1084   // conversion. We need to use View's conversion table here to keep consistent
   1085   // behavior with views::FocusManager::OnKeyEvent() method.
   1086   // TODO(suzhe): We need to check if Windows code also has this issue, and
   1087   // it'll be best if we can unify these conversion tables.
   1088   // See http://crbug.com/54315
   1089   views::KeyEvent views_event(reinterpret_cast<GdkEvent*>(event.os_event));
   1090   views::Accelerator accelerator(views_event.key_code(),
   1091                                  views_event.IsShiftDown(),
   1092                                  views_event.IsControlDown(),
   1093                                  views_event.IsAltDown());
   1094 #else
   1095   views::Accelerator accelerator(
   1096       static_cast<ui::KeyboardCode>(event.windowsKeyCode),
   1097       (event.modifiers & NativeWebKeyboardEvent::ShiftKey) ==
   1098           NativeWebKeyboardEvent::ShiftKey,
   1099       (event.modifiers & NativeWebKeyboardEvent::ControlKey) ==
   1100           NativeWebKeyboardEvent::ControlKey,
   1101       (event.modifiers & NativeWebKeyboardEvent::AltKey) ==
   1102           NativeWebKeyboardEvent::AltKey);
   1103 #endif
   1104 
   1105   // We first find out the browser command associated to the |event|.
   1106   // Then if the command is a reserved one, and should be processed
   1107   // immediately according to the |event|, the command will be executed
   1108   // immediately. Otherwise we just set |*is_keyboard_shortcut| properly and
   1109   // return false.
   1110 
   1111   // This piece of code is based on the fact that accelerators registered
   1112   // into the |focus_manager| may only trigger a browser command execution.
   1113   //
   1114   // Here we need to retrieve the command id (if any) associated to the
   1115   // keyboard event. Instead of looking up the command id in the
   1116   // |accelerator_table_| by ourselves, we block the command execution of
   1117   // the |browser_| object then send the keyboard event to the
   1118   // |focus_manager| as if we are activating an accelerator key.
   1119   // Then we can retrieve the command id from the |browser_| object.
   1120   browser_->SetBlockCommandExecution(true);
   1121   focus_manager->ProcessAccelerator(accelerator);
   1122   int id = browser_->GetLastBlockedCommand(NULL);
   1123   browser_->SetBlockCommandExecution(false);
   1124 
   1125   if (id == -1)
   1126     return false;
   1127 
   1128   // Executing the command may cause |this| object to be destroyed.
   1129 #if defined(OS_LINUX) && !defined(TOUCH_UI)
   1130   if (browser_->IsReservedCommandOrKey(id, event) &&
   1131       !event.match_edit_command) {
   1132 #else
   1133   if (browser_->IsReservedCommandOrKey(id, event)) {
   1134 #endif
   1135     UpdateAcceleratorMetrics(accelerator, id);
   1136     return browser_->ExecuteCommandIfEnabled(id);
   1137   }
   1138 
   1139   DCHECK(is_keyboard_shortcut != NULL);
   1140   *is_keyboard_shortcut = true;
   1141 
   1142   return false;
   1143 }
   1144 
   1145 void BrowserView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
   1146 #if defined(OS_LINUX) && !defined(TOUCH_UI)
   1147   views::Window* window = GetWidget()->GetWindow();
   1148   if (window && event.os_event && !event.skip_in_browser) {
   1149     views::KeyEvent views_event(reinterpret_cast<GdkEvent*>(event.os_event));
   1150     static_cast<views::WindowGtk*>(window)->HandleKeyboardEvent(views_event);
   1151   }
   1152 #else
   1153   unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
   1154                                                         GetFocusManager());
   1155 #endif
   1156 }
   1157 
   1158 // TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always
   1159 // enabled in the page menu regardless of whether the command will do
   1160 // anything. When someone selects the menu item, we just act as if they hit
   1161 // the keyboard shortcut for the command by sending the associated key press
   1162 // to windows. The real fix to this bug is to disable the commands when they
   1163 // won't do anything. We'll need something like an overall clipboard command
   1164 // manager to do that.
   1165 void BrowserView::Cut() {
   1166   ui_controls::SendKeyPress(GetNativeHandle(), ui::VKEY_X,
   1167                             true, false, false, false);
   1168 }
   1169 
   1170 void BrowserView::Copy() {
   1171   ui_controls::SendKeyPress(GetNativeHandle(), ui::VKEY_C,
   1172                             true, false, false, false);
   1173 }
   1174 
   1175 void BrowserView::Paste() {
   1176   ui_controls::SendKeyPress(GetNativeHandle(), ui::VKEY_V,
   1177                             true, false, false, false);
   1178 }
   1179 
   1180 void BrowserView::ToggleTabStripMode() {
   1181   InitTabStrip(browser_->tabstrip_model());
   1182   frame_->TabStripDisplayModeChanged();
   1183 }
   1184 
   1185 void BrowserView::PrepareForInstant() {
   1186   contents_->FadeActiveContents();
   1187 }
   1188 
   1189 void BrowserView::ShowInstant(TabContentsWrapper* preview) {
   1190   if (!preview_container_)
   1191     preview_container_ = new TabContentsContainer();
   1192   contents_->SetPreview(preview_container_, preview->tab_contents());
   1193   preview_container_->ChangeTabContents(preview->tab_contents());
   1194 
   1195 #if defined(OS_WIN)
   1196   // Removing the fade is instant (on windows). We need to force the preview to
   1197   // draw, otherwise the current page flickers before the new page appears.
   1198   RedrawWindow(preview->tab_contents()->view()->GetContentNativeView(), NULL,
   1199                NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
   1200 #endif
   1201 
   1202   contents_->RemoveFade();
   1203 }
   1204 
   1205 void BrowserView::HideInstant(bool instant_is_active) {
   1206   if (instant_is_active)
   1207     contents_->ShowFade();
   1208   else
   1209     contents_->RemoveFade();
   1210 
   1211   if (!preview_container_)
   1212     return;
   1213 
   1214   // The contents must be changed before SetPreview is invoked.
   1215   preview_container_->ChangeTabContents(NULL);
   1216   contents_->SetPreview(NULL, NULL);
   1217   delete preview_container_;
   1218   preview_container_ = NULL;
   1219 }
   1220 
   1221 gfx::Rect BrowserView::GetInstantBounds() {
   1222   return contents_->GetPreviewBounds();
   1223 }
   1224 
   1225 #if defined(OS_CHROMEOS)
   1226 void BrowserView::ShowKeyboardOverlay(gfx::NativeWindow owning_window) {
   1227   KeyboardOverlayDialogView::ShowDialog(owning_window, this);
   1228 }
   1229 #endif
   1230 
   1231 ///////////////////////////////////////////////////////////////////////////////
   1232 // BrowserView, BrowserWindowTesting implementation:
   1233 
   1234 BookmarkBarView* BrowserView::GetBookmarkBarView() const {
   1235   return bookmark_bar_view_.get();
   1236 }
   1237 
   1238 LocationBarView* BrowserView::GetLocationBarView() const {
   1239   return toolbar_->location_bar();
   1240 }
   1241 
   1242 views::View* BrowserView::GetTabContentsContainerView() const {
   1243   return contents_container_->GetFocusView();
   1244 }
   1245 
   1246 views::View* BrowserView::GetSidebarContainerView() const {
   1247   if (!sidebar_container_)
   1248     return NULL;
   1249   return sidebar_container_->GetFocusView();
   1250 }
   1251 
   1252 ToolbarView* BrowserView::GetToolbarView() const {
   1253   return toolbar_;
   1254 }
   1255 
   1256 ///////////////////////////////////////////////////////////////////////////////
   1257 // BrowserView, NotificationObserver implementation:
   1258 
   1259 void BrowserView::Observe(NotificationType type,
   1260                           const NotificationSource& source,
   1261                           const NotificationDetails& details) {
   1262   switch (type.value) {
   1263     case NotificationType::PREF_CHANGED:
   1264       if (*Details<std::string>(details).ptr() == prefs::kShowBookmarkBar &&
   1265           MaybeShowBookmarkBar(browser_->GetSelectedTabContentsWrapper())) {
   1266         Layout();
   1267       }
   1268       break;
   1269 
   1270     case NotificationType::SIDEBAR_CHANGED:
   1271       if (Details<SidebarContainer>(details)->tab_contents() ==
   1272           browser_->GetSelectedTabContents()) {
   1273         UpdateSidebar();
   1274       }
   1275       break;
   1276 
   1277     default:
   1278       NOTREACHED() << "Got a notification we didn't register for!";
   1279       break;
   1280   }
   1281 }
   1282 
   1283 ///////////////////////////////////////////////////////////////////////////////
   1284 // BrowserView, TabStripModelObserver implementation:
   1285 
   1286 void BrowserView::TabDetachedAt(TabContentsWrapper* contents, int index) {
   1287   // We use index here rather than comparing |contents| because by this time
   1288   // the model has already removed |contents| from its list, so
   1289   // browser_->GetSelectedTabContents() will return NULL or something else.
   1290   if (index == browser_->tabstrip_model()->active_index()) {
   1291     // We need to reset the current tab contents to NULL before it gets
   1292     // freed. This is because the focus manager performs some operations
   1293     // on the selected TabContents when it is removed.
   1294     contents_container_->ChangeTabContents(NULL);
   1295     infobar_container_->ChangeTabContents(NULL);
   1296     UpdateSidebarForContents(NULL);
   1297     UpdateDevToolsForContents(NULL);
   1298   }
   1299 }
   1300 
   1301 void BrowserView::TabDeselected(TabContentsWrapper* contents) {
   1302   // We do not store the focus when closing the tab to work-around bug 4633.
   1303   // Some reports seem to show that the focus manager and/or focused view can
   1304   // be garbage at that point, it is not clear why.
   1305   if (!contents->tab_contents()->is_being_destroyed())
   1306     contents->view()->StoreFocus();
   1307 }
   1308 
   1309 void BrowserView::TabSelectedAt(TabContentsWrapper* old_contents,
   1310                                 TabContentsWrapper* new_contents,
   1311                                 int index,
   1312                                 bool user_gesture) {
   1313   if (old_contents == new_contents)
   1314     return;
   1315 
   1316   ProcessTabSelected(new_contents, true);
   1317 }
   1318 
   1319 void BrowserView::TabReplacedAt(TabStripModel* tab_strip_model,
   1320                                 TabContentsWrapper* old_contents,
   1321                                 TabContentsWrapper* new_contents,
   1322                                 int index) {
   1323   if (index != browser_->tabstrip_model()->active_index())
   1324     return;
   1325 
   1326   // Swap the 'active' and 'preview' and delete what was the active.
   1327   contents_->MakePreviewContentsActiveContents();
   1328   TabContentsContainer* old_container = contents_container_;
   1329   contents_container_ = preview_container_;
   1330   old_container->ChangeTabContents(NULL);
   1331   delete old_container;
   1332   preview_container_ = NULL;
   1333 
   1334   // Update the UI for what was the preview contents and is now active. Pass in
   1335   // false to ProcessTabSelected as new_contents is already parented correctly.
   1336   ProcessTabSelected(new_contents, false);
   1337 }
   1338 
   1339 void BrowserView::TabStripEmpty() {
   1340   // Make sure all optional UI is removed before we are destroyed, otherwise
   1341   // there will be consequences (since our view hierarchy will still have
   1342   // references to freed views).
   1343   UpdateUIForContents(NULL);
   1344 }
   1345 
   1346 ///////////////////////////////////////////////////////////////////////////////
   1347 // BrowserView, ui::SimpleMenuModel::Delegate implementation:
   1348 
   1349 bool BrowserView::IsCommandIdChecked(int command_id) const {
   1350   // TODO(beng): encoding menu.
   1351   // No items in our system menu are check-able.
   1352   return false;
   1353 }
   1354 
   1355 bool BrowserView::IsCommandIdEnabled(int command_id) const {
   1356   return browser_->command_updater()->IsCommandEnabled(command_id);
   1357 }
   1358 
   1359 bool BrowserView::GetAcceleratorForCommandId(int command_id,
   1360                                              ui::Accelerator* accelerator) {
   1361   // Let's let the ToolbarView own the canonical implementation of this method.
   1362   return toolbar_->GetAcceleratorForCommandId(command_id, accelerator);
   1363 }
   1364 
   1365 bool BrowserView::IsItemForCommandIdDynamic(int command_id) const {
   1366   return command_id == IDC_RESTORE_TAB;
   1367 }
   1368 
   1369 string16 BrowserView::GetLabelForCommandId(int command_id) const {
   1370   DCHECK(command_id == IDC_RESTORE_TAB);
   1371 
   1372   int string_id = IDS_RESTORE_TAB;
   1373   if (IsCommandIdEnabled(command_id)) {
   1374     TabRestoreService* trs = browser_->profile()->GetTabRestoreService();
   1375     if (trs && trs->entries().front()->type == TabRestoreService::WINDOW)
   1376       string_id = IDS_RESTORE_WINDOW;
   1377   }
   1378   return l10n_util::GetStringUTF16(string_id);
   1379 }
   1380 
   1381 void BrowserView::ExecuteCommand(int command_id) {
   1382   browser_->ExecuteCommandIfEnabled(command_id);
   1383 }
   1384 
   1385 ///////////////////////////////////////////////////////////////////////////////
   1386 // BrowserView, views::WindowDelegate implementation:
   1387 
   1388 bool BrowserView::CanResize() const {
   1389   return true;
   1390 }
   1391 
   1392 bool BrowserView::CanMaximize() const {
   1393   return true;
   1394 }
   1395 
   1396 bool BrowserView::CanActivate() const {
   1397   return !ActivateAppModalDialog();
   1398 }
   1399 
   1400 bool BrowserView::IsModal() const {
   1401   return false;
   1402 }
   1403 
   1404 std::wstring BrowserView::GetWindowTitle() const {
   1405   return UTF16ToWideHack(browser_->GetWindowTitleForCurrentTab());
   1406 }
   1407 
   1408 std::wstring BrowserView::GetAccessibleWindowTitle() const {
   1409   if (IsOffTheRecord()) {
   1410     return UTF16ToWide(l10n_util::GetStringFUTF16(
   1411         IDS_ACCESSIBLE_INCOGNITO_WINDOW_TITLE_FORMAT,
   1412         WideToUTF16(GetWindowTitle())));
   1413   }
   1414   return GetWindowTitle();
   1415 }
   1416 
   1417 views::View* BrowserView::GetInitiallyFocusedView() {
   1418   // We set the frame not focus on creation so this should never be called.
   1419   NOTREACHED();
   1420   return NULL;
   1421 }
   1422 
   1423 bool BrowserView::ShouldShowWindowTitle() const {
   1424   return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR);
   1425 }
   1426 
   1427 SkBitmap BrowserView::GetWindowAppIcon() {
   1428   if (browser_->type() & Browser::TYPE_APP) {
   1429     TabContentsWrapper* contents = browser_->GetSelectedTabContentsWrapper();
   1430     if (contents && contents->extension_tab_helper()->GetExtensionAppIcon())
   1431       return *contents->extension_tab_helper()->GetExtensionAppIcon();
   1432   }
   1433 
   1434   return GetWindowIcon();
   1435 }
   1436 
   1437 SkBitmap BrowserView::GetWindowIcon() {
   1438   if (browser_->type() & Browser::TYPE_APP)
   1439     return browser_->GetCurrentPageIcon();
   1440   return SkBitmap();
   1441 }
   1442 
   1443 bool BrowserView::ShouldShowWindowIcon() const {
   1444   return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR);
   1445 }
   1446 
   1447 bool BrowserView::ExecuteWindowsCommand(int command_id) {
   1448   // This function handles WM_SYSCOMMAND, WM_APPCOMMAND, and WM_COMMAND.
   1449 
   1450   // Translate WM_APPCOMMAND command ids into a command id that the browser
   1451   // knows how to handle.
   1452   int command_id_from_app_command = GetCommandIDForAppCommandID(command_id);
   1453   if (command_id_from_app_command != -1)
   1454     command_id = command_id_from_app_command;
   1455 
   1456   return browser_->ExecuteCommandIfEnabled(command_id);
   1457 }
   1458 
   1459 std::wstring BrowserView::GetWindowName() const {
   1460   return UTF8ToWide(browser_->GetWindowPlacementKey());
   1461 }
   1462 
   1463 void BrowserView::SaveWindowPlacement(const gfx::Rect& bounds,
   1464                                       bool maximized) {
   1465   // If IsFullscreen() is true, we've just changed into fullscreen mode, and
   1466   // we're catching the going-into-fullscreen sizing and positioning calls,
   1467   // which we want to ignore.
   1468   if (!IsFullscreen() && browser_->ShouldSaveWindowPlacement()) {
   1469     WindowDelegate::SaveWindowPlacement(bounds, maximized);
   1470     browser_->SaveWindowPlacement(bounds, maximized);
   1471   }
   1472 }
   1473 
   1474 bool BrowserView::GetSavedWindowBounds(gfx::Rect* bounds) const {
   1475   *bounds = browser_->GetSavedWindowBounds();
   1476   if (browser_->type() & Browser::TYPE_POPUP) {
   1477     // We are a popup window. The value passed in |bounds| represents two
   1478     // pieces of information:
   1479     // - the position of the window, in screen coordinates (outer position).
   1480     // - the size of the content area (inner size).
   1481     // We need to use these values to determine the appropriate size and
   1482     // position of the resulting window.
   1483     if (IsToolbarVisible()) {
   1484       // If we're showing the toolbar, we need to adjust |*bounds| to include
   1485       // its desired height, since the toolbar is considered part of the
   1486       // window's client area as far as GetWindowBoundsForClientBounds is
   1487       // concerned...
   1488       bounds->set_height(
   1489           bounds->height() + toolbar_->GetPreferredSize().height());
   1490     }
   1491 
   1492     gfx::Rect window_rect = frame_->GetWindow()->non_client_view()->
   1493         GetWindowBoundsForClientBounds(*bounds);
   1494     window_rect.set_origin(bounds->origin());
   1495 
   1496     // When we are given x/y coordinates of 0 on a created popup window,
   1497     // assume none were given by the window.open() command.
   1498     if (window_rect.x() == 0 && window_rect.y() == 0) {
   1499       gfx::Size size = window_rect.size();
   1500       window_rect.set_origin(WindowSizer::GetDefaultPopupOrigin(size));
   1501     }
   1502 
   1503     *bounds = window_rect;
   1504   }
   1505 
   1506   // We return true because we can _always_ locate reasonable bounds using the
   1507   // WindowSizer, and we don't want to trigger the Window's built-in "size to
   1508   // default" handling because the browser window has no default preferred
   1509   // size.
   1510   return true;
   1511 }
   1512 
   1513 bool BrowserView::GetSavedMaximizedState(bool* maximized) const {
   1514   *maximized = browser_->GetSavedMaximizedState();
   1515   return true;
   1516 }
   1517 
   1518 views::View* BrowserView::GetContentsView() {
   1519   return contents_container_;
   1520 }
   1521 
   1522 views::ClientView* BrowserView::CreateClientView(views::Window* window) {
   1523   set_window(window);
   1524   return this;
   1525 }
   1526 
   1527 void BrowserView::OnWindowActivationChanged(bool active) {
   1528   if (active)
   1529     BrowserList::SetLastActive(browser_.get());
   1530 }
   1531 
   1532 void BrowserView::OnWindowBeginUserBoundsChange() {
   1533   TabContents* tab_contents = GetSelectedTabContents();
   1534   if (tab_contents)
   1535     tab_contents->WindowMoveOrResizeStarted();
   1536 }
   1537 
   1538 void BrowserView::OnWidgetMove() {
   1539   // Cancel any tabstrip animations, some of them may be invalidated by the
   1540   // window being repositioned.
   1541   // Comment out for one cycle to see if this fixes dist tests.
   1542   // tabstrip_->DestroyDragController();
   1543 
   1544   status_bubble_->Reposition();
   1545 
   1546   BrowserBubbleHost::WindowMoved();
   1547 
   1548   browser::HideBookmarkBubbleView();
   1549 
   1550   // Close the omnibox popup, if any.
   1551   if (toolbar_ && toolbar_->location_bar())
   1552     toolbar_->location_bar()->location_entry()->ClosePopup();
   1553 }
   1554 
   1555 ///////////////////////////////////////////////////////////////////////////////
   1556 // BrowserView, views::ClientView overrides:
   1557 
   1558 bool BrowserView::CanClose() {
   1559   // You cannot close a frame for which there is an active originating drag
   1560   // session.
   1561     if (tabstrip_ && !tabstrip_->IsTabStripCloseable())
   1562       return false;
   1563 
   1564   // Give beforeunload handlers the chance to cancel the close before we hide
   1565   // the window below.
   1566   if (!browser_->ShouldCloseWindow())
   1567     return false;
   1568 
   1569   if (!browser_->tabstrip_model()->empty()) {
   1570     // Tab strip isn't empty.  Hide the frame (so it appears to have closed
   1571     // immediately) and close all the tabs, allowing the renderers to shut
   1572     // down. When the tab strip is empty we'll be called back again.
   1573     frame_->GetWindow()->HideWindow();
   1574     browser_->OnWindowClosing();
   1575     return false;
   1576   }
   1577 
   1578   // Empty TabStripModel, it's now safe to allow the Window to be closed.
   1579   NotificationService::current()->Notify(
   1580       NotificationType::WINDOW_CLOSED,
   1581       Source<gfx::NativeWindow>(frame_->GetWindow()->GetNativeWindow()),
   1582       NotificationService::NoDetails());
   1583   return true;
   1584 }
   1585 
   1586 int BrowserView::NonClientHitTest(const gfx::Point& point) {
   1587 #if defined(OS_WIN)
   1588   // The following code is not in the LayoutManager because it's
   1589   // independent of layout and also depends on the ResizeCorner which
   1590   // is private.
   1591   if (!frame_->GetWindow()->IsMaximized() &&
   1592       !frame_->GetWindow()->IsFullscreen()) {
   1593     CRect client_rect;
   1594     ::GetClientRect(frame_->GetWindow()->GetNativeWindow(), &client_rect);
   1595     gfx::Size resize_corner_size = ResizeCorner::GetSize();
   1596     gfx::Rect resize_corner_rect(client_rect.right - resize_corner_size.width(),
   1597         client_rect.bottom - resize_corner_size.height(),
   1598         resize_corner_size.width(), resize_corner_size.height());
   1599     bool rtl_dir = base::i18n::IsRTL();
   1600     if (rtl_dir)
   1601       resize_corner_rect.set_x(0);
   1602     if (resize_corner_rect.Contains(point)) {
   1603       if (rtl_dir)
   1604         return HTBOTTOMLEFT;
   1605       return HTBOTTOMRIGHT;
   1606     }
   1607   }
   1608 #endif
   1609 
   1610   return GetBrowserViewLayout()->NonClientHitTest(point);
   1611 }
   1612 
   1613 gfx::Size BrowserView::GetMinimumSize() {
   1614   return GetBrowserViewLayout()->GetMinimumSize();
   1615 }
   1616 
   1617 ///////////////////////////////////////////////////////////////////////////////
   1618 // BrowserView, protected
   1619 
   1620 void BrowserView::GetAccessiblePanes(
   1621     std::vector<AccessiblePaneView*>* panes) {
   1622   // This should be in the order of pane traversal of the panes using F6.
   1623   // If one of these is invisible or has no focusable children, it will be
   1624   // automatically skipped.
   1625   panes->push_back(toolbar_);
   1626   if (bookmark_bar_view_.get())
   1627     panes->push_back(bookmark_bar_view_.get());
   1628   if (infobar_container_)
   1629     panes->push_back(infobar_container_);
   1630   if (download_shelf_.get())
   1631     panes->push_back(download_shelf_.get());
   1632 }
   1633 
   1634 ///////////////////////////////////////////////////////////////////////////////
   1635 // BrowserView, views::View overrides:
   1636 
   1637 std::string BrowserView::GetClassName() const {
   1638   return kViewClassName;
   1639 }
   1640 
   1641 void BrowserView::Layout() {
   1642   if (ignore_layout_)
   1643     return;
   1644   views::View::Layout();
   1645 
   1646   // The status bubble position requires that all other layout finish first.
   1647   LayoutStatusBubble();
   1648 
   1649 #if defined(OS_WIN)
   1650   // Send the margins of the "user-perceived content area" of this
   1651   // browser window so AeroPeekManager can render a background-tab image in
   1652   // the area.
   1653   // TODO(pkasting) correct content inset??
   1654   if (aeropeek_manager_.get()) {
   1655     gfx::Insets insets(GetFindBarBoundingBox().y() + 1,
   1656                        0,
   1657                        0,
   1658                        0);
   1659     aeropeek_manager_->SetContentInsets(insets);
   1660   }
   1661 #endif
   1662 }
   1663 
   1664 void BrowserView::PaintChildren(gfx::Canvas* canvas) {
   1665   // Paint the |infobar_container_| last so that it may paint its
   1666   // overlapping tabs.
   1667   for (int i = 0; i < child_count(); ++i) {
   1668     View* child = GetChildViewAt(i);
   1669     if (child != infobar_container_)
   1670       child->Paint(canvas);
   1671   }
   1672 
   1673   infobar_container_->Paint(canvas);
   1674 }
   1675 
   1676 void BrowserView::ViewHierarchyChanged(bool is_add,
   1677                                        views::View* parent,
   1678                                        views::View* child) {
   1679   if (is_add && child == this && GetWidget() && !initialized_) {
   1680     Init();
   1681     initialized_ = true;
   1682   }
   1683 }
   1684 
   1685 void BrowserView::ChildPreferredSizeChanged(View* child) {
   1686   Layout();
   1687 }
   1688 
   1689 void BrowserView::GetAccessibleState(ui::AccessibleViewState* state) {
   1690   state->name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
   1691   state->role = ui::AccessibilityTypes::ROLE_CLIENT;
   1692 }
   1693 
   1694 SkColor BrowserView::GetInfoBarSeparatorColor() const {
   1695   // NOTE: Keep this in sync with ToolbarView::OnPaint()!
   1696   return (IsTabStripVisible() ||
   1697           !frame_->GetWindow()->non_client_view()->UseNativeFrame()) ?
   1698       ResourceBundle::toolbar_separator_color : SK_ColorBLACK;
   1699 }
   1700 
   1701 void BrowserView::InfoBarContainerStateChanged(bool is_animating) {
   1702   ToolbarSizeChanged(is_animating);
   1703 }
   1704 
   1705 bool BrowserView::DrawInfoBarArrows(int* x) const {
   1706   if (x) {
   1707     const LocationIconView* location_icon_view =
   1708         toolbar_->location_bar()->location_icon_view();
   1709     gfx::Point icon_center(location_icon_view->GetImageBounds().CenterPoint());
   1710     ConvertPointToView(location_icon_view, this, &icon_center);
   1711     *x = icon_center.x();
   1712   }
   1713   return true;
   1714 }
   1715 
   1716 bool BrowserView::SplitHandleMoved(views::SingleSplitView* view) {
   1717   for (int i = 0; i < view->child_count(); ++i)
   1718     view->GetChildViewAt(i)->InvalidateLayout();
   1719   SchedulePaint();
   1720   Layout();
   1721   return false;
   1722 }
   1723 
   1724 views::LayoutManager* BrowserView::CreateLayoutManager() const {
   1725   return new BrowserViewLayout;
   1726 }
   1727 
   1728 void BrowserView::InitTabStrip(TabStripModel* model) {
   1729   // Throw away the existing tabstrip if we're switching display modes.
   1730   scoped_ptr<AbstractTabStripView> old_strip(tabstrip_);
   1731   if (tabstrip_)
   1732     tabstrip_->parent()->RemoveChildView(tabstrip_);
   1733 
   1734   tabstrip_ = CreateTabStrip(browser_.get(), this, model, UseVerticalTabs());
   1735 }
   1736 
   1737 ToolbarView* BrowserView::CreateToolbar() const {
   1738   return new ToolbarView(browser_.get());
   1739 }
   1740 
   1741 void BrowserView::Init() {
   1742   SetLayoutManager(CreateLayoutManager());
   1743   // Stow a pointer to this object onto the window handle so that we can get at
   1744   // it later when all we have is a native view.
   1745   GetWidget()->native_widget()->SetNativeWindowProperty(kBrowserViewKey, this);
   1746 
   1747   // Stow a pointer to the browser's profile onto the window handle so that we
   1748   // can get it later when all we have is a native view.
   1749   GetWidget()->native_widget()->SetNativeWindowProperty(Profile::kProfileKey,
   1750                                                         browser_->profile());
   1751 
   1752   // Start a hung plugin window detector for this browser object (as long as
   1753   // hang detection is not disabled).
   1754   if (!CommandLine::ForCurrentProcess()->HasSwitch(
   1755           switches::kDisableHangMonitor)) {
   1756     InitHangMonitor();
   1757   }
   1758 
   1759   LoadAccelerators();
   1760 
   1761   InitTabStrip(browser_->tabstrip_model());
   1762 
   1763   SetToolbar(CreateToolbar());
   1764 
   1765   infobar_container_ = new InfoBarContainerView(this);
   1766   AddChildView(infobar_container_);
   1767 
   1768   contents_container_ = new TabContentsContainer;
   1769   contents_ = new ContentsContainer(contents_container_);
   1770 
   1771   SkColor bg_color = GetWidget()->GetThemeProvider()->
   1772       GetColor(ThemeService::COLOR_TOOLBAR);
   1773 
   1774   bool sidebar_allowed = SidebarManager::IsSidebarAllowed();
   1775   if (sidebar_allowed) {
   1776     sidebar_container_ = new TabContentsContainer;
   1777     sidebar_container_->SetID(VIEW_ID_SIDE_BAR_CONTAINER);
   1778     sidebar_container_->SetVisible(false);
   1779 
   1780     sidebar_split_ = new views::SingleSplitView(
   1781         contents_,
   1782         sidebar_container_,
   1783         views::SingleSplitView::HORIZONTAL_SPLIT,
   1784         this);
   1785     sidebar_split_->SetID(VIEW_ID_SIDE_BAR_SPLIT);
   1786     sidebar_split_->SetAccessibleName(
   1787         l10n_util::GetStringUTF16(IDS_ACCNAME_SIDE_BAR));
   1788     sidebar_split_->set_background(
   1789         views::Background::CreateSolidBackground(bg_color));
   1790   }
   1791 
   1792   devtools_container_ = new TabContentsContainer;
   1793   devtools_container_->SetID(VIEW_ID_DEV_TOOLS_DOCKED);
   1794   devtools_container_->SetVisible(false);
   1795 
   1796   views::View* contents_view = contents_;
   1797   if (sidebar_allowed)
   1798     contents_view = sidebar_split_;
   1799 
   1800   contents_split_ = new views::SingleSplitView(
   1801       contents_view,
   1802       devtools_container_,
   1803       views::SingleSplitView::VERTICAL_SPLIT,
   1804       this);
   1805   contents_split_->SetID(VIEW_ID_CONTENTS_SPLIT);
   1806   contents_split_->SetAccessibleName(
   1807       l10n_util::GetStringUTF16(IDS_ACCNAME_WEB_CONTENTS));
   1808   contents_split_->set_background(
   1809       views::Background::CreateSolidBackground(bg_color));
   1810   AddChildView(contents_split_);
   1811   set_contents_view(contents_split_);
   1812 
   1813   status_bubble_.reset(new StatusBubbleViews(contents_));
   1814 
   1815 #if defined(OS_WIN)
   1816   InitSystemMenu();
   1817 
   1818   // Create a custom JumpList and add it to an observer of TabRestoreService
   1819   // so we can update the custom JumpList when a tab is added or removed.
   1820   if (JumpList::Enabled()) {
   1821     jumplist_.reset(new JumpList);
   1822     jumplist_->AddObserver(browser_->profile());
   1823   }
   1824 
   1825   if (AeroPeekManager::Enabled()) {
   1826     aeropeek_manager_.reset(new AeroPeekManager(
   1827         frame_->GetWindow()->GetNativeWindow()));
   1828     browser_->tabstrip_model()->AddObserver(aeropeek_manager_.get());
   1829   }
   1830 #endif
   1831 
   1832   // We're now initialized and ready to process Layout requests.
   1833   ignore_layout_ = false;
   1834 }
   1835 
   1836 void BrowserView::LoadingAnimationCallback() {
   1837   base::TimeTicks now = base::TimeTicks::Now();
   1838   if (!last_animation_time_.is_null()) {
   1839     UMA_HISTOGRAM_TIMES(
   1840         "Tabs.LoadingAnimationTime",
   1841         now - last_animation_time_);
   1842   }
   1843   last_animation_time_ = now;
   1844   if (browser_->type() == Browser::TYPE_NORMAL) {
   1845     // Loading animations are shown in the tab for tabbed windows.  We check the
   1846     // browser type instead of calling IsTabStripVisible() because the latter
   1847     // will return false for fullscreen windows, but we still need to update
   1848     // their animations (so that when they come out of fullscreen mode they'll
   1849     // be correct).
   1850     tabstrip_->UpdateLoadingAnimations();
   1851   } else if (ShouldShowWindowIcon()) {
   1852     // ... or in the window icon area for popups and app windows.
   1853     TabContents* tab_contents = browser_->GetSelectedTabContents();
   1854     // GetSelectedTabContents can return NULL for example under Purify when
   1855     // the animations are running slowly and this function is called on a timer
   1856     // through LoadingAnimationCallback.
   1857     frame_->UpdateThrobber(tab_contents && tab_contents->is_loading());
   1858   }
   1859 }
   1860 
   1861 // BrowserView, private --------------------------------------------------------
   1862 
   1863 #if defined(OS_WIN)
   1864 void BrowserView::InitSystemMenu() {
   1865   system_menu_contents_.reset(new views::SystemMenuModel(this));
   1866   // We add the menu items in reverse order so that insertion_index never needs
   1867   // to change.
   1868   if (IsBrowserTypeNormal())
   1869     BuildSystemMenuForBrowserWindow();
   1870   else
   1871     BuildSystemMenuForAppOrPopupWindow(browser_->type() == Browser::TYPE_APP);
   1872   system_menu_.reset(
   1873       new views::NativeMenuWin(system_menu_contents_.get(),
   1874                                frame_->GetWindow()->GetNativeWindow()));
   1875   system_menu_->Rebuild();
   1876 }
   1877 #endif
   1878 
   1879 BrowserViewLayout* BrowserView::GetBrowserViewLayout() const {
   1880   return static_cast<BrowserViewLayout*>(GetLayoutManager());
   1881 }
   1882 
   1883 void BrowserView::LayoutStatusBubble() {
   1884   // In restored mode, the client area has a client edge between it and the
   1885   // frame.
   1886   int overlap = StatusBubbleViews::kShadowThickness +
   1887       (IsMaximized() ? 0 : views::NonClientFrameView::kClientEdgeThickness);
   1888   int x = -overlap;
   1889   if (UseVerticalTabs() && IsTabStripVisible())
   1890     x += tabstrip_->bounds().right();
   1891   int height = status_bubble_->GetPreferredSize().height();
   1892   int contents_height = status_bubble_->base_view()->bounds().height();
   1893   gfx::Point origin(-overlap, contents_height - height + overlap);
   1894   status_bubble_->SetBounds(origin.x(), origin.y(), width() / 3, height);
   1895 }
   1896 
   1897 bool BrowserView::MaybeShowBookmarkBar(TabContentsWrapper* contents) {
   1898   views::View* new_bookmark_bar_view = NULL;
   1899   if (browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR)
   1900       && contents) {
   1901     if (!bookmark_bar_view_.get()) {
   1902       bookmark_bar_view_.reset(new BookmarkBarView(contents->profile(),
   1903                                                    browser_.get()));
   1904       bookmark_bar_view_->set_parent_owned(false);
   1905       bookmark_bar_view_->set_background(
   1906           new BookmarkExtensionBackground(this, bookmark_bar_view_.get(),
   1907                                           browser_.get()));
   1908     } else {
   1909       bookmark_bar_view_->SetProfile(contents->profile());
   1910     }
   1911     bookmark_bar_view_->SetPageNavigator(contents->tab_contents());
   1912     new_bookmark_bar_view = bookmark_bar_view_.get();
   1913   }
   1914   return UpdateChildViewAndLayout(new_bookmark_bar_view, &active_bookmark_bar_);
   1915 }
   1916 
   1917 bool BrowserView::MaybeShowInfoBar(TabContentsWrapper* contents) {
   1918   // TODO(beng): Remove this function once the interface between
   1919   //             InfoBarContainer, DownloadShelfView and TabContents and this
   1920   //             view is sorted out.
   1921   return true;
   1922 }
   1923 
   1924 void BrowserView::UpdateSidebar() {
   1925   UpdateSidebarForContents(GetSelectedTabContentsWrapper());
   1926   Layout();
   1927 }
   1928 
   1929 void BrowserView::UpdateSidebarForContents(TabContentsWrapper* tab_contents) {
   1930   if (!sidebar_container_)
   1931     return;  // Happens when sidebar is not allowed.
   1932   if (!SidebarManager::GetInstance())
   1933     return;  // Happens only in tests.
   1934 
   1935   TabContents* sidebar_contents = NULL;
   1936   if (tab_contents) {
   1937     SidebarContainer* client_host = SidebarManager::GetInstance()->
   1938         GetActiveSidebarContainerFor(tab_contents->tab_contents());
   1939     if (client_host)
   1940       sidebar_contents = client_host->sidebar_contents();
   1941   }
   1942 
   1943   bool visible = NULL != sidebar_contents &&
   1944                  browser_->SupportsWindowFeature(Browser::FEATURE_SIDEBAR);
   1945 
   1946   bool should_show = visible && !sidebar_container_->IsVisible();
   1947   bool should_hide = !visible && sidebar_container_->IsVisible();
   1948 
   1949   // Update sidebar content.
   1950   TabContents* old_contents = sidebar_container_->tab_contents();
   1951   sidebar_container_->ChangeTabContents(sidebar_contents);
   1952   SidebarManager::GetInstance()->
   1953       NotifyStateChanges(old_contents, sidebar_contents);
   1954 
   1955   // Update sidebar UI width.
   1956   if (should_show) {
   1957     // Restore split offset.
   1958     int sidebar_width = g_browser_process->local_state()->GetInteger(
   1959         prefs::kExtensionSidebarWidth);
   1960     if (sidebar_width < 0) {
   1961       // Initial load, set to default value.
   1962       sidebar_width = sidebar_split_->width() / 7;
   1963     }
   1964     // Make sure user can see both panes.
   1965     int min_sidebar_width = sidebar_split_->GetMinimumSize().width();
   1966     sidebar_width = std::min(sidebar_split_->width() - min_sidebar_width,
   1967                              std::max(min_sidebar_width, sidebar_width));
   1968 
   1969     sidebar_split_->set_divider_offset(
   1970         sidebar_split_->width() - sidebar_width);
   1971 
   1972     sidebar_container_->SetVisible(true);
   1973     sidebar_split_->InvalidateLayout();
   1974     Layout();
   1975   } else if (should_hide) {
   1976     // Store split offset when hiding sidebar only.
   1977     g_browser_process->local_state()->SetInteger(
   1978         prefs::kExtensionSidebarWidth,
   1979         sidebar_split_->width() - sidebar_split_->divider_offset());
   1980 
   1981     sidebar_container_->SetVisible(false);
   1982     sidebar_split_->InvalidateLayout();
   1983     Layout();
   1984   }
   1985 }
   1986 
   1987 void BrowserView::UpdateDevToolsForContents(TabContentsWrapper* wrapper) {
   1988   TabContents* devtools_contents = NULL;
   1989   if (wrapper) {
   1990     TabContentsWrapper* devtools_contents_wrapper =
   1991         DevToolsWindow::GetDevToolsContents(wrapper->tab_contents());
   1992     if (devtools_contents_wrapper)
   1993       devtools_contents = devtools_contents_wrapper->tab_contents();
   1994   }
   1995 
   1996   bool should_show = devtools_contents && !devtools_container_->IsVisible();
   1997   bool should_hide = !devtools_contents && devtools_container_->IsVisible();
   1998 
   1999   devtools_container_->ChangeTabContents(devtools_contents);
   2000 
   2001   if (should_show) {
   2002     if (!devtools_focus_tracker_.get()) {
   2003       // Install devtools focus tracker when dev tools window is shown for the
   2004       // first time.
   2005       devtools_focus_tracker_.reset(
   2006           new views::ExternalFocusTracker(devtools_container_,
   2007                                           GetFocusManager()));
   2008     }
   2009 
   2010     // Restore split offset.
   2011     int split_offset = browser_->profile()->GetPrefs()->
   2012         GetInteger(prefs::kDevToolsSplitLocation);
   2013     if (split_offset == -1) {
   2014       // Initial load, set to default value.
   2015       split_offset = 2 * contents_split_->height() / 3;
   2016     }
   2017     // Make sure user can see both panes.
   2018     int min_split_size = contents_split_->height() / 10;
   2019     split_offset = std::min(contents_split_->height() - min_split_size,
   2020                             std::max(min_split_size, split_offset));
   2021     contents_split_->set_divider_offset(split_offset);
   2022 
   2023     devtools_container_->SetVisible(true);
   2024     contents_split_->InvalidateLayout();
   2025     Layout();
   2026   } else if (should_hide) {
   2027     // Store split offset when hiding devtools window only.
   2028     browser_->profile()->GetPrefs()->SetInteger(prefs::kDevToolsSplitLocation,
   2029         contents_split_->divider_offset());
   2030 
   2031     // Restore focus to the last focused view when hiding devtools window.
   2032     devtools_focus_tracker_->FocusLastFocusedExternalView();
   2033 
   2034     devtools_container_->SetVisible(false);
   2035     contents_split_->InvalidateLayout();
   2036     Layout();
   2037   }
   2038 }
   2039 
   2040 void BrowserView::UpdateUIForContents(TabContentsWrapper* contents) {
   2041   bool needs_layout = MaybeShowBookmarkBar(contents);
   2042   needs_layout |= MaybeShowInfoBar(contents);
   2043   if (needs_layout)
   2044     Layout();
   2045 }
   2046 
   2047 bool BrowserView::UpdateChildViewAndLayout(views::View* new_view,
   2048                                            views::View** old_view) {
   2049   DCHECK(old_view);
   2050   if (*old_view == new_view) {
   2051     // The views haven't changed, if the views pref changed schedule a layout.
   2052     if (new_view) {
   2053       if (new_view->GetPreferredSize().height() != new_view->height())
   2054         return true;
   2055     }
   2056     return false;
   2057   }
   2058 
   2059   // The views differ, and one may be null (but not both). Remove the old
   2060   // view (if it non-null), and add the new one (if it is non-null). If the
   2061   // height has changed, schedule a layout, otherwise reuse the existing
   2062   // bounds to avoid scheduling a layout.
   2063 
   2064   int current_height = 0;
   2065   if (*old_view) {
   2066     current_height = (*old_view)->height();
   2067     RemoveChildView(*old_view);
   2068   }
   2069 
   2070   int new_height = 0;
   2071   if (new_view) {
   2072     new_height = new_view->GetPreferredSize().height();
   2073     AddChildView(new_view);
   2074   }
   2075   bool changed = false;
   2076   if (new_height != current_height) {
   2077     changed = true;
   2078   } else if (new_view && *old_view) {
   2079     // The view changed, but the new view wants the same size, give it the
   2080     // bounds of the last view and have it repaint.
   2081     new_view->SetBoundsRect((*old_view)->bounds());
   2082     new_view->SchedulePaint();
   2083   } else if (new_view) {
   2084     DCHECK_EQ(0, new_height);
   2085     // The heights are the same, but the old view is null. This only happens
   2086     // when the height is zero. Zero out the bounds.
   2087     new_view->SetBounds(0, 0, 0, 0);
   2088   }
   2089   *old_view = new_view;
   2090   return changed;
   2091 }
   2092 
   2093 void BrowserView::ProcessFullscreen(bool fullscreen) {
   2094   // Reduce jankiness during the following position changes by:
   2095   //   * Hiding the window until it's in the final position
   2096   //   * Ignoring all intervening Layout() calls, which resize the webpage and
   2097   //     thus are slow and look ugly
   2098   ignore_layout_ = true;
   2099   LocationBarView* location_bar = toolbar_->location_bar();
   2100 #if defined(OS_WIN)
   2101   AutocompleteEditViewWin* edit_view =
   2102       static_cast<AutocompleteEditViewWin*>(location_bar->location_entry());
   2103 #endif
   2104   if (!fullscreen) {
   2105     // Hide the fullscreen bubble as soon as possible, since the mode toggle can
   2106     // take enough time for the user to notice.
   2107     fullscreen_bubble_.reset();
   2108   } else {
   2109     // Move focus out of the location bar if necessary.
   2110     views::FocusManager* focus_manager = GetFocusManager();
   2111     DCHECK(focus_manager);
   2112     if (focus_manager->GetFocusedView() == location_bar)
   2113       focus_manager->ClearFocus();
   2114 
   2115 #if defined(OS_WIN)
   2116     // If we don't hide the edit and force it to not show until we come out of
   2117     // fullscreen, then if the user was on the New Tab Page, the edit contents
   2118     // will appear atop the web contents once we go into fullscreen mode.  This
   2119     // has something to do with how we move the main window while it's hidden;
   2120     // if we don't hide the main window below, we don't get this problem.
   2121     edit_view->set_force_hidden(true);
   2122     ShowWindow(edit_view->m_hWnd, SW_HIDE);
   2123 #endif
   2124   }
   2125 #if defined(OS_WIN)
   2126   static_cast<views::WindowWin*>(
   2127       frame_->GetWindow()->native_window())->PushForceHidden();
   2128 #endif
   2129 
   2130   // Notify bookmark bar, so it can set itself to the appropriate drawing state.
   2131   if (bookmark_bar_view_.get())
   2132     bookmark_bar_view_->OnFullscreenToggled(fullscreen);
   2133 
   2134   // Toggle fullscreen mode.
   2135 #if defined(OS_WIN)
   2136   frame_->GetWindow()->SetFullscreen(fullscreen);
   2137 #endif  // No need to invoke SetFullscreen for linux as this code is executed
   2138         // once we're already fullscreen on linux.
   2139 
   2140 #if defined(OS_LINUX)
   2141   // Updating of commands for fullscreen mode is called from SetFullScreen on
   2142   // Wndows (see just above), but for ChromeOS, this method (ProcessFullScreen)
   2143   // is called after full screen has happened successfully (via GTK's
   2144   // window-state-change event), so we have to update commands here.
   2145   browser_->UpdateCommandsForFullscreenMode(fullscreen);
   2146 #endif
   2147 
   2148   if (fullscreen) {
   2149     bool is_kiosk =
   2150         CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode);
   2151     if (!is_kiosk) {
   2152       fullscreen_bubble_.reset(new FullscreenExitBubble(GetWidget(),
   2153                                                         browser_.get()));
   2154     }
   2155   } else {
   2156 #if defined(OS_WIN)
   2157     // Show the edit again since we're no longer in fullscreen mode.
   2158     edit_view->set_force_hidden(false);
   2159     ShowWindow(edit_view->m_hWnd, SW_SHOW);
   2160 #endif
   2161   }
   2162 
   2163   // Undo our anti-jankiness hacks and force the window to relayout now that
   2164   // it's in its final position.
   2165   ignore_layout_ = false;
   2166   Layout();
   2167 #if defined(OS_WIN)
   2168   static_cast<views::WindowWin*>(
   2169       frame_->GetWindow()->native_window())->PopForceHidden();
   2170 #endif
   2171 }
   2172 
   2173 
   2174 void BrowserView::LoadAccelerators() {
   2175 #if defined(OS_WIN)
   2176   HACCEL accelerator_table = AtlLoadAccelerators(IDR_MAINFRAME);
   2177   DCHECK(accelerator_table);
   2178 
   2179   // We have to copy the table to access its contents.
   2180   int count = CopyAcceleratorTable(accelerator_table, 0, 0);
   2181   if (count == 0) {
   2182     // Nothing to do in that case.
   2183     return;
   2184   }
   2185 
   2186   ACCEL* accelerators = static_cast<ACCEL*>(malloc(sizeof(ACCEL) * count));
   2187   CopyAcceleratorTable(accelerator_table, accelerators, count);
   2188 
   2189   views::FocusManager* focus_manager = GetFocusManager();
   2190   DCHECK(focus_manager);
   2191 
   2192   // Let's fill our own accelerator table.
   2193   for (int i = 0; i < count; ++i) {
   2194     bool alt_down = (accelerators[i].fVirt & FALT) == FALT;
   2195     bool ctrl_down = (accelerators[i].fVirt & FCONTROL) == FCONTROL;
   2196     bool shift_down = (accelerators[i].fVirt & FSHIFT) == FSHIFT;
   2197     views::Accelerator accelerator(
   2198         static_cast<ui::KeyboardCode>(accelerators[i].key),
   2199         shift_down, ctrl_down, alt_down);
   2200     accelerator_table_[accelerator] = accelerators[i].cmd;
   2201 
   2202     // Also register with the focus manager.
   2203     focus_manager->RegisterAccelerator(accelerator, this);
   2204   }
   2205 
   2206   // We don't need the Windows accelerator table anymore.
   2207   free(accelerators);
   2208 #else
   2209   views::FocusManager* focus_manager = GetFocusManager();
   2210   DCHECK(focus_manager);
   2211   // Let's fill our own accelerator table.
   2212   for (size_t i = 0; i < browser::kAcceleratorMapLength; ++i) {
   2213     views::Accelerator accelerator(browser::kAcceleratorMap[i].keycode,
   2214                                    browser::kAcceleratorMap[i].shift_pressed,
   2215                                    browser::kAcceleratorMap[i].ctrl_pressed,
   2216                                    browser::kAcceleratorMap[i].alt_pressed);
   2217     accelerator_table_[accelerator] = browser::kAcceleratorMap[i].command_id;
   2218 
   2219     // Also register with the focus manager.
   2220     focus_manager->RegisterAccelerator(accelerator, this);
   2221   }
   2222 #endif
   2223 }
   2224 
   2225 #if defined(OS_WIN)
   2226 void BrowserView::BuildSystemMenuForBrowserWindow() {
   2227   system_menu_contents_->AddSeparator();
   2228   system_menu_contents_->AddItemWithStringId(IDC_TASK_MANAGER,
   2229                                              IDS_TASK_MANAGER);
   2230   system_menu_contents_->AddSeparator();
   2231   system_menu_contents_->AddItemWithStringId(IDC_RESTORE_TAB, IDS_RESTORE_TAB);
   2232   system_menu_contents_->AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB);
   2233   // If it's a regular browser window with tabs, we don't add any more items,
   2234   // since it already has menus (Page, Chrome).
   2235 }
   2236 
   2237 void BrowserView::BuildSystemMenuForAppOrPopupWindow(bool is_app) {
   2238   if (is_app) {
   2239     system_menu_contents_->AddSeparator();
   2240     system_menu_contents_->AddItemWithStringId(IDC_TASK_MANAGER,
   2241                                                IDS_TASK_MANAGER);
   2242   }
   2243   system_menu_contents_->AddSeparator();
   2244   encoding_menu_contents_.reset(new EncodingMenuModel(browser_.get()));
   2245   system_menu_contents_->AddSubMenuWithStringId(IDC_ENCODING_MENU,
   2246                                                 IDS_ENCODING_MENU,
   2247                                                 encoding_menu_contents_.get());
   2248   zoom_menu_contents_.reset(new ZoomMenuModel(this));
   2249   system_menu_contents_->AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_ZOOM_MENU,
   2250                                                 zoom_menu_contents_.get());
   2251   system_menu_contents_->AddItemWithStringId(IDC_PRINT, IDS_PRINT);
   2252   system_menu_contents_->AddItemWithStringId(IDC_FIND, IDS_FIND);
   2253   system_menu_contents_->AddSeparator();
   2254   system_menu_contents_->AddItemWithStringId(IDC_PASTE, IDS_PASTE);
   2255   system_menu_contents_->AddItemWithStringId(IDC_COPY, IDS_COPY);
   2256   system_menu_contents_->AddItemWithStringId(IDC_CUT, IDS_CUT);
   2257   system_menu_contents_->AddSeparator();
   2258   if (is_app) {
   2259     system_menu_contents_->AddItemWithStringId(IDC_NEW_TAB,
   2260                                                IDS_APP_MENU_NEW_WEB_PAGE);
   2261   } else {
   2262     system_menu_contents_->AddItemWithStringId(IDC_SHOW_AS_TAB,
   2263                                                IDS_SHOW_AS_TAB);
   2264   }
   2265   system_menu_contents_->AddItemWithStringId(IDC_COPY_URL,
   2266                                              IDS_APP_MENU_COPY_URL);
   2267   system_menu_contents_->AddSeparator();
   2268   system_menu_contents_->AddItemWithStringId(IDC_RELOAD, IDS_APP_MENU_RELOAD);
   2269   system_menu_contents_->AddItemWithStringId(IDC_FORWARD,
   2270                                              IDS_CONTENT_CONTEXT_FORWARD);
   2271   system_menu_contents_->AddItemWithStringId(IDC_BACK,
   2272                                              IDS_CONTENT_CONTEXT_BACK);
   2273 }
   2274 #endif
   2275 
   2276 int BrowserView::GetCommandIDForAppCommandID(int app_command_id) const {
   2277 #if defined(OS_WIN)
   2278   switch (app_command_id) {
   2279     // NOTE: The order here matches the APPCOMMAND declaration order in the
   2280     // Windows headers.
   2281     case APPCOMMAND_BROWSER_BACKWARD: return IDC_BACK;
   2282     case APPCOMMAND_BROWSER_FORWARD:  return IDC_FORWARD;
   2283     case APPCOMMAND_BROWSER_REFRESH:  return IDC_RELOAD;
   2284     case APPCOMMAND_BROWSER_HOME:     return IDC_HOME;
   2285     case APPCOMMAND_BROWSER_STOP:     return IDC_STOP;
   2286     case APPCOMMAND_BROWSER_SEARCH:   return IDC_FOCUS_SEARCH;
   2287     case APPCOMMAND_HELP:             return IDC_HELP_PAGE;
   2288     case APPCOMMAND_NEW:              return IDC_NEW_TAB;
   2289     case APPCOMMAND_OPEN:             return IDC_OPEN_FILE;
   2290     case APPCOMMAND_CLOSE:            return IDC_CLOSE_TAB;
   2291     case APPCOMMAND_SAVE:             return IDC_SAVE_PAGE;
   2292     case APPCOMMAND_PRINT:            return IDC_PRINT;
   2293     case APPCOMMAND_COPY:             return IDC_COPY;
   2294     case APPCOMMAND_CUT:              return IDC_CUT;
   2295     case APPCOMMAND_PASTE:            return IDC_PASTE;
   2296 
   2297       // TODO(pkasting): http://b/1113069 Handle these.
   2298     case APPCOMMAND_UNDO:
   2299     case APPCOMMAND_REDO:
   2300     case APPCOMMAND_SPELL_CHECK:
   2301     default:                          return -1;
   2302   }
   2303 #else
   2304   // App commands are Windows-specific so there's nothing to do here.
   2305   return -1;
   2306 #endif
   2307 }
   2308 
   2309 void BrowserView::InitHangMonitor() {
   2310 #if defined(OS_WIN)
   2311   PrefService* pref_service = g_browser_process->local_state();
   2312   if (!pref_service)
   2313     return;
   2314 
   2315   int plugin_message_response_timeout =
   2316       pref_service->GetInteger(prefs::kPluginMessageResponseTimeout);
   2317   int hung_plugin_detect_freq =
   2318       pref_service->GetInteger(prefs::kHungPluginDetectFrequency);
   2319   if ((hung_plugin_detect_freq > 0) &&
   2320       hung_window_detector_.Initialize(GetWidget()->GetNativeView(),
   2321                                        plugin_message_response_timeout)) {
   2322     ticker_.set_tick_interval(hung_plugin_detect_freq);
   2323     ticker_.RegisterTickHandler(&hung_window_detector_);
   2324     ticker_.Start();
   2325 
   2326     pref_service->SetInteger(prefs::kPluginMessageResponseTimeout,
   2327                              plugin_message_response_timeout);
   2328     pref_service->SetInteger(prefs::kHungPluginDetectFrequency,
   2329                              hung_plugin_detect_freq);
   2330   }
   2331 #endif
   2332 }
   2333 
   2334 void BrowserView::UpdateAcceleratorMetrics(
   2335     const views::Accelerator& accelerator, int command_id) {
   2336 #if defined(OS_CHROMEOS)
   2337   // Collect information about the relative popularity of various accelerators
   2338   // on Chrome OS.
   2339   const ui::KeyboardCode key_code = accelerator.GetKeyCode();
   2340   switch (command_id) {
   2341     case IDC_BACK:
   2342       if (key_code == ui::VKEY_BACK)
   2343         UserMetrics::RecordAction(UserMetricsAction("Accel_Back_Backspace"));
   2344       else if (key_code == ui::VKEY_F1)
   2345         UserMetrics::RecordAction(UserMetricsAction("Accel_Back_F1"));
   2346       else if (key_code == ui::VKEY_LEFT)
   2347         UserMetrics::RecordAction(UserMetricsAction("Accel_Back_Left"));
   2348       break;
   2349     case IDC_FORWARD:
   2350       if (key_code == ui::VKEY_BACK)
   2351         UserMetrics::RecordAction(UserMetricsAction("Accel_Forward_Backspace"));
   2352       else if (key_code == ui::VKEY_F2)
   2353         UserMetrics::RecordAction(UserMetricsAction("Accel_Forward_F2"));
   2354       else if (key_code == ui::VKEY_RIGHT)
   2355         UserMetrics::RecordAction(UserMetricsAction("Accel_Forward_Right"));
   2356       break;
   2357     case IDC_RELOAD:
   2358     case IDC_RELOAD_IGNORING_CACHE:
   2359       if (key_code == ui::VKEY_R)
   2360         UserMetrics::RecordAction(UserMetricsAction("Accel_Reload_R"));
   2361       else if (key_code == ui::VKEY_F3)
   2362         UserMetrics::RecordAction(UserMetricsAction("Accel_Reload_F3"));
   2363       break;
   2364     case IDC_FULLSCREEN:
   2365       if (key_code == ui::VKEY_F4)
   2366         UserMetrics::RecordAction(UserMetricsAction("Accel_Fullscreen_F4"));
   2367       break;
   2368     case IDC_NEW_TAB:
   2369       if (key_code == ui::VKEY_T)
   2370         UserMetrics::RecordAction(UserMetricsAction("Accel_NewTab_T"));
   2371       break;
   2372     case IDC_SEARCH:
   2373       if (key_code == ui::VKEY_LWIN)
   2374         UserMetrics::RecordAction(UserMetricsAction("Accel_Search_LWin"));
   2375       break;
   2376     case IDC_FOCUS_LOCATION:
   2377       if (key_code == ui::VKEY_D)
   2378         UserMetrics::RecordAction(UserMetricsAction("Accel_FocusLocation_D"));
   2379       else if (key_code == ui::VKEY_L)
   2380         UserMetrics::RecordAction(UserMetricsAction("Accel_FocusLocation_L"));
   2381       break;
   2382     case IDC_FOCUS_SEARCH:
   2383       if (key_code == ui::VKEY_E)
   2384         UserMetrics::RecordAction(UserMetricsAction("Accel_FocusSearch_E"));
   2385       else if (key_code == ui::VKEY_K)
   2386         UserMetrics::RecordAction(UserMetricsAction("Accel_FocusSearch_K"));
   2387       break;
   2388     default:
   2389       // Do nothing.
   2390       break;
   2391   }
   2392 #endif
   2393 }
   2394 
   2395 void BrowserView::ProcessTabSelected(TabContentsWrapper* new_contents,
   2396                                      bool change_tab_contents) {
   2397   // Update various elements that are interested in knowing the current
   2398   // TabContents.
   2399 
   2400   // When we toggle the NTP floating bookmarks bar and/or the info bar,
   2401   // we don't want any TabContents to be attached, so that we
   2402   // avoid an unnecessary resize and re-layout of a TabContents.
   2403   if (change_tab_contents)
   2404     contents_container_->ChangeTabContents(NULL);
   2405   infobar_container_->ChangeTabContents(new_contents->tab_contents());
   2406   UpdateUIForContents(new_contents);
   2407   if (change_tab_contents)
   2408     contents_container_->ChangeTabContents(new_contents->tab_contents());
   2409   UpdateSidebarForContents(new_contents);
   2410 
   2411   UpdateDevToolsForContents(new_contents);
   2412   // TODO(beng): This should be called automatically by ChangeTabContents, but I
   2413   //             am striving for parity now rather than cleanliness. This is
   2414   //             required to make features like Duplicate Tab, Undo Close Tab,
   2415   //             etc not result in sad tab.
   2416   new_contents->tab_contents()->DidBecomeSelected();
   2417   if (BrowserList::GetLastActive() == browser_ &&
   2418       !browser_->tabstrip_model()->closing_all() && GetWindow()->IsVisible()) {
   2419     // We only restore focus if our window is visible, to avoid invoking blur
   2420     // handlers when we are eventually shown.
   2421     new_contents->view()->RestoreFocus();
   2422   }
   2423 
   2424   // Update all the UI bits.
   2425   UpdateTitleBar();
   2426   // No need to update Toolbar because it's already updated in
   2427   // browser.cc.
   2428 }
   2429 
   2430 gfx::Size BrowserView::GetResizeCornerSize() const {
   2431   return ResizeCorner::GetSize();
   2432 }
   2433 
   2434 void BrowserView::SetToolbar(ToolbarView* toolbar) {
   2435   if (toolbar_) {
   2436     RemoveChildView(toolbar_);
   2437     delete toolbar_;
   2438   }
   2439   toolbar_ = toolbar;
   2440   if (toolbar) {
   2441     AddChildView(toolbar_);
   2442     toolbar_->Init(browser_->profile());
   2443   }
   2444 }
   2445 
   2446 #if !defined(OS_CHROMEOS)
   2447 // static
   2448 BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
   2449   // Create the view and the frame. The frame will attach itself via the view
   2450   // so we don't need to do anything with the pointer.
   2451   BrowserView* view = new BrowserView(browser);
   2452   BrowserFrame::Create(view, browser->profile());
   2453 
   2454   view->GetWindow()->non_client_view()->SetAccessibleName(
   2455       l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
   2456 
   2457   return view;
   2458 }
   2459 #endif
   2460 
   2461 // static
   2462 FindBar* BrowserWindow::CreateFindBar(Browser* browser) {
   2463   return browser::CreateFindBar(static_cast<BrowserView*>(browser->window()));
   2464 }
   2465