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