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