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