browser_view.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/views/frame/browser_view.h"
6
7#include <algorithm>
8
9#include "base/auto_reset.h"
10#include "base/command_line.h"
11#include "base/i18n/rtl.h"
12#include "base/metrics/histogram.h"
13#include "base/prefs/pref_service.h"
14#include "base/strings/string_number_conversions.h"
15#include "base/strings/utf_string_conversions.h"
16#include "chrome/app/chrome_command_ids.h"
17#include "chrome/app/chrome_dll_resource.h"
18#include "chrome/browser/app_mode/app_mode_utils.h"
19#include "chrome/browser/bookmarks/bookmark_utils.h"
20#include "chrome/browser/browser_process.h"
21#include "chrome/browser/extensions/tab_helper.h"
22#include "chrome/browser/infobars/infobar_service.h"
23#include "chrome/browser/native_window_notification_source.h"
24#include "chrome/browser/password_manager/password_manager.h"
25#include "chrome/browser/profiles/avatar_menu_model.h"
26#include "chrome/browser/profiles/profile.h"
27#include "chrome/browser/profiles/profile_info_cache.h"
28#include "chrome/browser/profiles/profile_manager.h"
29#include "chrome/browser/search/search.h"
30#include "chrome/browser/sessions/tab_restore_service.h"
31#include "chrome/browser/sessions/tab_restore_service_factory.h"
32#include "chrome/browser/speech/tts_controller.h"
33#include "chrome/browser/themes/theme_properties.h"
34#include "chrome/browser/themes/theme_service_factory.h"
35#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
36#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
37#include "chrome/browser/ui/bookmarks/bookmark_utils.h"
38#include "chrome/browser/ui/browser.h"
39#include "chrome/browser/ui/browser_command_controller.h"
40#include "chrome/browser/ui/browser_commands.h"
41#include "chrome/browser/ui/browser_dialogs.h"
42#include "chrome/browser/ui/browser_finder.h"
43#include "chrome/browser/ui/browser_list.h"
44#include "chrome/browser/ui/browser_window_state.h"
45#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
46#include "chrome/browser/ui/ntp_background_util.h"
47#include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
48#include "chrome/browser/ui/omnibox/omnibox_popup_view.h"
49#include "chrome/browser/ui/omnibox/omnibox_view.h"
50#include "chrome/browser/ui/search/search_delegate.h"
51#include "chrome/browser/ui/search/search_model.h"
52#include "chrome/browser/ui/search/search_ui.h"
53#include "chrome/browser/ui/tabs/tab_menu_model.h"
54#include "chrome/browser/ui/tabs/tab_strip_model.h"
55#include "chrome/browser/ui/view_ids.h"
56#include "chrome/browser/ui/views/accelerator_table.h"
57#include "chrome/browser/ui/views/accessibility/invert_bubble_view.h"
58#include "chrome/browser/ui/views/avatar_menu_bubble_view.h"
59#include "chrome/browser/ui/views/avatar_menu_button.h"
60#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
61#include "chrome/browser/ui/views/browser_dialogs.h"
62#include "chrome/browser/ui/views/download/download_in_progress_dialog_view.h"
63#include "chrome/browser/ui/views/download/download_shelf_view.h"
64#include "chrome/browser/ui/views/frame/browser_view_layout.h"
65#include "chrome/browser/ui/views/frame/browser_view_layout_delegate.h"
66#include "chrome/browser/ui/views/frame/contents_container.h"
67#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
68#include "chrome/browser/ui/views/frame/instant_overlay_controller_views.h"
69#include "chrome/browser/ui/views/frame/overlay_container.h"
70#include "chrome/browser/ui/views/frame/top_container_view.h"
71#include "chrome/browser/ui/views/fullscreen_exit_bubble_views.h"
72#include "chrome/browser/ui/views/infobars/infobar_container_view.h"
73#include "chrome/browser/ui/views/location_bar/location_icon_view.h"
74#include "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
75#include "chrome/browser/ui/views/omnibox/omnibox_views.h"
76#include "chrome/browser/ui/views/password_generation_bubble_view.h"
77#include "chrome/browser/ui/views/status_bubble_views.h"
78#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
79#include "chrome/browser/ui/views/tabs/tab.h"
80#include "chrome/browser/ui/views/tabs/tab_strip.h"
81#include "chrome/browser/ui/views/toolbar_view.h"
82#include "chrome/browser/ui/views/update_recommended_message_box.h"
83#include "chrome/browser/ui/views/website_settings/website_settings_popup_view.h"
84#include "chrome/browser/ui/window_sizer/window_sizer.h"
85#include "chrome/common/chrome_notification_types.h"
86#include "chrome/common/chrome_switches.h"
87#include "chrome/common/pref_names.h"
88#include "chrome/common/url_constants.h"
89#include "content/public/browser/download_manager.h"
90#include "content/public/browser/native_web_keyboard_event.h"
91#include "content/public/browser/notification_service.h"
92#include "content/public/browser/render_view_host.h"
93#include "content/public/browser/render_widget_host.h"
94#include "content/public/browser/user_metrics.h"
95#include "content/public/browser/web_contents.h"
96#include "content/public/browser/web_contents_view.h"
97#include "content/public/common/content_switches.h"
98#include "grit/chromium_strings.h"
99#include "grit/generated_resources.h"
100#include "grit/locale_settings.h"
101#include "grit/theme_resources.h"
102#include "grit/ui_resources.h"
103#include "grit/ui_strings.h"
104#include "grit/webkit_resources.h"
105#include "ui/base/accelerators/accelerator.h"
106#include "ui/base/accessibility/accessible_view_state.h"
107#include "ui/base/events/event_utils.h"
108#include "ui/base/hit_test.h"
109#include "ui/base/l10n/l10n_util.h"
110#include "ui/base/resource/resource_bundle.h"
111#include "ui/base/theme_provider.h"
112#include "ui/gfx/canvas.h"
113#include "ui/gfx/color_utils.h"
114#include "ui/gfx/sys_color_change_listener.h"
115#include "ui/views/controls/single_split_view.h"
116#include "ui/views/controls/textfield/textfield.h"
117#include "ui/views/controls/webview/webview.h"
118#include "ui/views/focus/external_focus_tracker.h"
119#include "ui/views/focus/view_storage.h"
120#include "ui/views/layout/grid_layout.h"
121#include "ui/views/widget/native_widget.h"
122#include "ui/views/widget/root_view.h"
123#include "ui/views/widget/widget.h"
124#include "ui/views/window/dialog_delegate.h"
125
126#if defined(USE_ASH)
127#include "ash/launcher/launcher.h"
128#include "ash/launcher/launcher_model.h"
129#include "ash/shell.h"
130#include "chrome/browser/ui/ash/ash_util.h"
131#include "chrome/browser/ui/ash/chrome_shell_delegate.h"
132#include "chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h"
133#include "chrome/browser/ui/ash/window_positioner.h"
134#endif
135
136#if defined(USE_AURA)
137#include "ui/aura/window.h"
138#include "ui/gfx/screen.h"
139#elif defined(OS_WIN)  // !defined(USE_AURA)
140#include "chrome/browser/jumplist_win.h"
141#include "chrome/browser/ui/views/omnibox/omnibox_view_win.h"
142#include "ui/views/widget/native_widget_win.h"
143#include "ui/views/win/scoped_fullscreen_visibility.h"
144#endif
145
146#if defined(OS_WIN)
147#include "base/win/windows_version.h"
148#include "win8/util/win8_util.h"
149#endif
150
151#if defined(ENABLE_ONE_CLICK_SIGNIN)
152#include "chrome/browser/ui/views/sync/one_click_signin_bubble_view.h"
153#endif
154
155using base::TimeDelta;
156using content::NativeWebKeyboardEvent;
157using content::SSLStatus;
158using content::UserMetricsAction;
159using content::WebContents;
160using views::ColumnSet;
161using views::GridLayout;
162using web_modal::WebContentsModalDialogHost;
163
164namespace {
165// The height of the status bubble.
166const int kStatusBubbleHeight = 20;
167// The name of a key to store on the window handle so that other code can
168// locate this object using just the handle.
169const char* const kBrowserViewKey = "__BROWSER_VIEW__";
170
171// The number of milliseconds between loading animation frames.
172const int kLoadingAnimationFrameTimeMs = 30;
173// The amount of space we expect the window border to take up.
174const int kWindowBorderWidth = 5;
175
176// How round the 'new tab' style bookmarks bar is.
177const int kNewtabBarRoundness = 5;
178
179// TODO(kuan): These functions are temporarily for the bookmark bar while its
180// detached state is at the top of the page;  it'll be moved to float on the
181// content page in the very near future, at which time, these local functions
182// will be removed.
183void PaintDetachedBookmarkBar(gfx::Canvas* canvas,
184                              DetachableToolbarView* view,
185                              ThemeService* theme_service) {
186  // Paint background for detached state; if animating, this is fade in/out.
187  canvas->DrawColor(
188      chrome::GetDetachedBookmarkBarBackgroundColor(theme_service));
189  // Draw the separators above and below bookmark bar;
190  // if animating, these are fading in/out.
191  SkColor separator_color =
192      chrome::GetDetachedBookmarkBarSeparatorColor(theme_service);
193  DetachableToolbarView::PaintHorizontalBorder(canvas, view, true,
194                                               separator_color);
195  // The bottom border needs to be 1-px thick in both regular and retina
196  // displays, so we can't use DetachableToolbarView::PaintHorizontalBorder
197  // which paints a 2-px thick border in retina display.
198  SkPaint paint;
199  paint.setAntiAlias(false);
200  // Sets border to 1-px thick regardless of scale factor.
201  paint.setStrokeWidth(0);
202  // Bottom border is at 50% opacity of top border.
203  paint.setColor(SkColorSetA(separator_color,
204                             SkColorGetA(separator_color) / 2));
205  // Calculate thickness of bottom border as per current scale factor to
206  // determine where to draw the 1-px thick border.
207  float thickness = views::NonClientFrameView::kClientEdgeThickness /
208                    ui::GetScaleFactorScale(canvas->scale_factor());
209  SkScalar y = SkIntToScalar(view->height()) - SkFloatToScalar(thickness);
210  canvas->sk_canvas()->drawLine(SkIntToScalar(0), y,
211                                SkIntToScalar(view->width()), y, paint);
212}
213
214void PaintAttachedBookmarkBar(gfx::Canvas* canvas,
215                              DetachableToolbarView* view,
216                              BrowserView* browser_view,
217                              chrome::HostDesktopType host_desktop_type,
218                              int toolbar_overlap) {
219  // Paint background for attached state, this is fade in/out.
220  gfx::Point background_image_offset =
221      browser_view->OffsetPointForToolbarBackgroundImage(
222          gfx::Point(view->GetMirroredX(), view->y()));
223  DetachableToolbarView::PaintBackgroundAttachedMode(canvas,
224      view->GetThemeProvider(), view->GetLocalBounds(),
225      background_image_offset, host_desktop_type);
226  if (view->height() >= toolbar_overlap) {
227    // Draw the separator below bookmark bar; this is fading in/out.
228    DetachableToolbarView::PaintHorizontalBorder(canvas, view, false,
229        ThemeProperties::GetDefaultColor(
230            ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
231  }
232}
233
234}  // namespace
235
236// static
237const char BrowserView::kViewClassName[] = "BrowserView";
238
239namespace {
240
241bool ShouldSaveOrRestoreWindowPos() {
242#if defined(OS_WIN)
243  // In Windows 8's single window Metro mode the window is always maximized
244  // (without the WS_MAXIMIZE style).
245  if (win8::IsSingleWindowMetroMode())
246    return false;
247#endif
248  return true;
249}
250
251// Returns whether immersive mode should replace fullscreen, which should only
252// occur for "browser-fullscreen" and not for "tab-fullscreen" (which has a URL
253// for the tab entering fullscreen).
254bool UseImmersiveFullscreenForUrl(const GURL& url) {
255  bool is_browser_fullscreen = url.is_empty();
256  return is_browser_fullscreen &&
257         ImmersiveFullscreenConfiguration::UseImmersiveFullscreen();
258}
259
260}  // namespace
261
262///////////////////////////////////////////////////////////////////////////////
263
264// Delegate implementation for BrowserViewLayout. Usually just forwards calls
265// into BrowserView.
266class BrowserViewLayoutDelegateImpl : public BrowserViewLayoutDelegate {
267 public:
268  explicit BrowserViewLayoutDelegateImpl(BrowserView* browser_view)
269      : browser_view_(browser_view) {}
270  virtual ~BrowserViewLayoutDelegateImpl() {}
271
272  // BrowserViewLayoutDelegate overrides:
273  virtual views::View* GetWindowSwitcherButton() const OVERRIDE {
274    return browser_view_->window_switcher_button();
275  }
276
277  virtual bool DownloadShelfNeedsLayout() const OVERRIDE {
278    DownloadShelfView* download_shelf = browser_view_->download_shelf_.get();
279    // Re-layout the shelf either if it is visible or if its close animation
280    // is currently running.
281    return download_shelf &&
282           (download_shelf->IsShowing() || download_shelf->IsClosing());
283  }
284
285  virtual bool IsTabStripVisible() const OVERRIDE {
286    return browser_view_->IsTabStripVisible();
287  }
288
289  virtual gfx::Rect GetBoundsForTabStrip(
290      views::View* tab_strip) const OVERRIDE {
291    return browser_view_->frame()->GetBoundsForTabStrip(tab_strip);
292  }
293
294  virtual bool IsToolbarVisible() const OVERRIDE {
295    return browser_view_->IsToolbarVisible();
296  }
297
298  virtual bool IsBookmarkBarVisible() const OVERRIDE {
299    return browser_view_->IsBookmarkBarVisible();
300  }
301
302 private:
303  BrowserView* browser_view_;
304
305  DISALLOW_COPY_AND_ASSIGN(BrowserViewLayoutDelegateImpl);
306};
307
308///////////////////////////////////////////////////////////////////////////////
309// BookmarkExtensionBackground, private:
310// This object serves as the views::Background object which is used to layout
311// and paint the bookmark bar.
312class BookmarkExtensionBackground : public views::Background {
313 public:
314  BookmarkExtensionBackground(BrowserView* browser_view,
315                              DetachableToolbarView* host_view,
316                              Browser* browser);
317
318  // View methods overridden from views:Background.
319  virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE;
320
321 private:
322  BrowserView* browser_view_;
323
324  // The view hosting this background.
325  DetachableToolbarView* host_view_;
326
327  Browser* browser_;
328
329  DISALLOW_COPY_AND_ASSIGN(BookmarkExtensionBackground);
330};
331
332BookmarkExtensionBackground::BookmarkExtensionBackground(
333    BrowserView* browser_view,
334    DetachableToolbarView* host_view,
335    Browser* browser)
336    : browser_view_(browser_view),
337      host_view_(host_view),
338      browser_(browser) {
339}
340
341void BookmarkExtensionBackground::Paint(gfx::Canvas* canvas,
342                                        views::View* view) const {
343  int toolbar_overlap = host_view_->GetToolbarOverlap();
344  // The client edge is drawn below the toolbar bounds.
345  if (toolbar_overlap)
346    toolbar_overlap += views::NonClientFrameView::kClientEdgeThickness;
347  if (host_view_->IsDetached()) {
348    // As 'hidden' according to the animation is the full in-tab state,
349    // we invert the value - when current_state is at '0', we expect the
350    // bar to be docked.
351    double current_state = 1 - host_view_->GetAnimationValue();
352
353    // In Search NTP, the detached bookmark bar is different from regular NTP:
354    // - there's no padding around the bar
355    // - there's a separator below the bar
356    // - if animating between pinned and unpinned states:
357    //   - cross-fade the bar backgrounds
358    //   - fade in/out the separator between toolbar and bookmark bar.
359    if (chrome::IsInstantExtendedAPIEnabled()) {
360      ThemeService* ts =
361          ThemeServiceFactory::GetForProfile(browser_->profile());
362      if (current_state == 0.0 || current_state == 1.0) {
363        PaintDetachedBookmarkBar(canvas, host_view_, ts);
364        return;
365      }
366      // While animating, set opacity to cross-fade between attached and
367      // detached backgrounds including their respective separators.
368      int detached_alpha = static_cast<uint8>(current_state * 255);
369      int attached_alpha = 255 - detached_alpha;
370      if (browser_->bookmark_bar_state() == BookmarkBar::DETACHED) {
371        // To animate from attached to detached state:
372        // - fade out attached background
373        // - fade in detached background.
374        canvas->SaveLayerAlpha(attached_alpha);
375        PaintAttachedBookmarkBar(canvas, host_view_, browser_view_,
376                                 browser_->host_desktop_type(),
377                                 toolbar_overlap);
378        canvas->Restore();
379        canvas->SaveLayerAlpha(detached_alpha);
380        PaintDetachedBookmarkBar(canvas, host_view_, ts);
381      } else {
382        // To animate from detached to attached state:
383        // - fade out detached background
384        // - fade in attached background.
385        canvas->SaveLayerAlpha(detached_alpha);
386        PaintDetachedBookmarkBar(canvas, host_view_, ts);
387        canvas->Restore();
388        canvas->SaveLayerAlpha(attached_alpha);
389        PaintAttachedBookmarkBar(canvas, host_view_, browser_view_,
390                                 browser_->host_desktop_type(),
391                                 toolbar_overlap);
392      }
393      canvas->Restore();
394      return;
395    }
396
397    // Draw the background to match the new tab page.
398    ui::ThemeProvider* tp = host_view_->GetThemeProvider();
399    int height = 0;
400    WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents();
401    if (contents && contents->GetView())
402      height = contents->GetView()->GetContainerSize().height();
403    NtpBackgroundUtil::PaintBackgroundDetachedMode(
404        tp, canvas,
405        gfx::Rect(0, toolbar_overlap, host_view_->width(),
406                  host_view_->height() - toolbar_overlap),
407        height);
408
409    double h_padding =
410        static_cast<double>(BookmarkBarView::kNewtabHorizontalPadding) *
411        current_state;
412    double v_padding =
413        static_cast<double>(BookmarkBarView::kNewtabVerticalPadding) *
414        current_state;
415
416    SkRect rect;
417    double roundness = 0;
418    DetachableToolbarView::CalculateContentArea(current_state, h_padding,
419        v_padding, &rect, &roundness, host_view_);
420    DetachableToolbarView::PaintContentAreaBackground(canvas, tp, rect,
421                                                      roundness);
422    DetachableToolbarView::PaintContentAreaBorder(canvas, tp, rect, roundness);
423    if (!toolbar_overlap)
424      DetachableToolbarView::PaintHorizontalBorderForState(canvas, host_view_);
425  } else {
426    gfx::Point background_image_offset =
427        browser_view_->OffsetPointForToolbarBackgroundImage(
428            gfx::Point(host_view_->GetMirroredX(), host_view_->y()));
429    DetachableToolbarView::PaintBackgroundAttachedMode(canvas,
430        host_view_->GetThemeProvider(), host_view_->GetLocalBounds(),
431        background_image_offset, browser_->host_desktop_type());
432    if (host_view_->height() >= toolbar_overlap)
433      DetachableToolbarView::PaintHorizontalBorderForState(canvas, host_view_);
434  }
435}
436
437///////////////////////////////////////////////////////////////////////////////
438// BrowserView, public:
439
440BrowserView::BrowserView()
441    : views::ClientView(NULL, NULL),
442      last_focused_view_storage_id_(
443          views::ViewStorage::GetInstance()->CreateStorageID()),
444      frame_(NULL),
445      top_container_(NULL),
446      tabstrip_(NULL),
447      toolbar_(NULL),
448      window_switcher_button_(NULL),
449      find_bar_host_view_(NULL),
450      infobar_container_(NULL),
451      contents_web_view_(NULL),
452      devtools_container_(NULL),
453      contents_container_(NULL),
454      overlay_container_(NULL),
455      contents_split_(NULL),
456      devtools_dock_side_(DEVTOOLS_DOCK_SIDE_BOTTOM),
457      devtools_window_(NULL),
458      initialized_(false),
459      ignore_layout_(true),
460#if defined(OS_WIN) && !defined(USE_AURA)
461      hung_window_detector_(&hung_plugin_action_),
462      ticker_(0),
463#endif
464      force_location_bar_focus_(false),
465      immersive_mode_controller_(chrome::CreateImmersiveModeController()),
466      color_change_listener_(this),
467      activate_modal_dialog_factory_(this) {
468}
469
470BrowserView::~BrowserView() {
471#if defined(USE_ASH)
472  // Destroy BrowserLauncherItemController early on as it listens to the
473  // TabstripModel, which is destroyed by the browser.
474  launcher_item_controller_.reset();
475#endif
476
477  // Immersive mode may need to reparent views before they are removed/deleted.
478  immersive_mode_controller_.reset();
479
480  overlay_controller_.reset();
481
482  browser_->tab_strip_model()->RemoveObserver(this);
483
484#if defined(OS_WIN) && !defined(USE_AURA)
485  // Stop hung plugin monitoring.
486  ticker_.Stop();
487  ticker_.UnregisterTickHandler(&hung_window_detector_);
488
489  // Terminate the jumplist (must be called before browser_->profile() is
490  // destroyed.
491  if (jumplist_) {
492    jumplist_->Terminate();
493  }
494#endif
495
496  // We destroy the download shelf before |browser_| to remove its child
497  // download views from the set of download observers (since the observed
498  // downloads can be destroyed along with |browser_| and the observer
499  // notifications will call back into deleted objects).
500  BrowserViewLayout* browser_view_layout = GetBrowserViewLayout();
501  if (browser_view_layout)
502    browser_view_layout->set_download_shelf(NULL);
503  download_shelf_.reset();
504
505  // The TabStrip attaches a listener to the model. Make sure we shut down the
506  // TabStrip first so that it can cleanly remove the listener.
507  if (tabstrip_) {
508    tabstrip_->parent()->RemoveChildView(tabstrip_);
509    if (browser_view_layout)
510      browser_view_layout->set_tab_strip(NULL);
511    delete tabstrip_;
512    tabstrip_ = NULL;
513  }
514  // Child views maintain PrefMember attributes that point to
515  // OffTheRecordProfile's PrefService which gets deleted by ~Browser.
516  RemoveAllChildViews(true);
517
518  // It is possible that we were forced-closed by the native view system and
519  // that tabs remain in the browser. Close any such remaining tabs.
520  while (browser_->tab_strip_model()->count())
521    delete browser_->tab_strip_model()->GetWebContentsAt(0);
522
523  // Explicitly set browser_ to NULL.
524  browser_.reset();
525}
526
527void BrowserView::Init(Browser* browser) {
528  browser_.reset(browser);
529  browser_->tab_strip_model()->AddObserver(this);
530}
531
532// static
533BrowserView* BrowserView::GetBrowserViewForNativeWindow(
534    gfx::NativeWindow window) {
535  views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window);
536  return widget ?
537      reinterpret_cast<BrowserView*>(widget->GetNativeWindowProperty(
538          kBrowserViewKey)) : NULL;
539}
540
541// static
542BrowserView* BrowserView::GetBrowserViewForBrowser(const Browser* browser) {
543  return static_cast<BrowserView*>(browser->window());
544}
545
546gfx::Rect BrowserView::GetToolbarBounds() const {
547  gfx::Rect toolbar_bounds(toolbar_->bounds());
548  if (toolbar_bounds.IsEmpty())
549    return toolbar_bounds;
550  // The apparent toolbar edges are outside the "real" toolbar edges.
551  toolbar_bounds.Inset(-views::NonClientFrameView::kClientEdgeThickness, 0);
552  return toolbar_bounds;
553}
554
555gfx::Rect BrowserView::GetClientAreaBounds() const {
556  gfx::Rect container_bounds = contents_container_->bounds();
557  gfx::Point container_origin = container_bounds.origin();
558  ConvertPointToTarget(this, parent(), &container_origin);
559  container_bounds.set_origin(container_origin);
560  return container_bounds;
561}
562
563gfx::Rect BrowserView::GetFindBarBoundingBox() const {
564  return GetBrowserViewLayout()->GetFindBarBoundingBox();
565}
566
567int BrowserView::GetTabStripHeight() const {
568  // We want to return tabstrip_->height(), but we might be called in the midst
569  // of layout, when that hasn't yet been updated to reflect the current state.
570  // So return what the tabstrip height _ought_ to be right now.
571  return IsTabStripVisible() ? tabstrip_->GetPreferredSize().height() : 0;
572}
573
574gfx::Point BrowserView::OffsetPointForToolbarBackgroundImage(
575    const gfx::Point& point) const {
576  // The background image starts tiling horizontally at the window left edge and
577  // vertically at the top edge of the horizontal tab strip (or where it would
578  // be).  We expect our parent's origin to be the window origin.
579  gfx::Point window_point(point + GetMirroredPosition().OffsetFromOrigin());
580  window_point.Offset(frame_->GetThemeBackgroundXInset(),
581                      -frame_->GetTabStripInsets(false).top);
582  return window_point;
583}
584
585bool BrowserView::IsTabStripVisible() const {
586  if (immersive_mode_controller_->ShouldHideTopViews() &&
587      immersive_mode_controller_->ShouldHideTabIndicators())
588    return false;
589  return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP);
590}
591
592bool BrowserView::IsOffTheRecord() const {
593  return browser_->profile()->IsOffTheRecord();
594}
595
596int BrowserView::GetOTRIconResourceID() const {
597  int otr_resource_id = IDR_OTR_ICON;
598  if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) {
599    if (IsFullscreen())
600      otr_resource_id = IDR_OTR_ICON_FULLSCREEN;
601#if defined(OS_WIN)
602    if (win8::IsSingleWindowMetroMode())
603      otr_resource_id = IDR_OTR_ICON_FULLSCREEN;
604#endif
605  }
606
607  return otr_resource_id;
608}
609
610bool BrowserView::IsGuestSession() const {
611  return browser_->profile()->IsGuestSession();
612}
613
614bool BrowserView::ShouldShowAvatar() const {
615  if (!IsBrowserTypeNormal())
616    return false;
617  if (IsOffTheRecord() && !IsGuestSession())
618    return true;
619  // Tests may not have a profile manager.
620  if (!g_browser_process->profile_manager())
621    return false;
622  ProfileInfoCache& cache =
623      g_browser_process->profile_manager()->GetProfileInfoCache();
624  if (cache.GetIndexOfProfileWithPath(browser_->profile()->GetPath()) ==
625      std::string::npos) {
626    return false;
627  }
628
629  return AvatarMenuModel::ShouldShowAvatarMenu();
630}
631
632bool BrowserView::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) {
633  // We retrieve the accelerator information for standard accelerators
634  // for cut, copy and paste.
635  if (chrome::GetStandardAcceleratorForCommandId(cmd_id, accelerator))
636    return true;
637  // Else, we retrieve the accelerator information from the accelerator table.
638  for (std::map<ui::Accelerator, int>::const_iterator it =
639           accelerator_table_.begin(); it != accelerator_table_.end(); ++it) {
640    if (it->second == cmd_id) {
641      *accelerator = it->first;
642      return true;
643    }
644  }
645  // Else, we retrieve the accelerator information from Ash (if applicable).
646  return chrome::GetAshAcceleratorForCommandId(
647      cmd_id, browser_->host_desktop_type(), accelerator);
648}
649
650bool BrowserView::IsAcceleratorRegistered(const ui::Accelerator& accelerator) {
651  return accelerator_table_.find(accelerator) != accelerator_table_.end();
652}
653
654WebContents* BrowserView::GetActiveWebContents() const {
655  return browser_->tab_strip_model()->GetActiveWebContents();
656}
657
658gfx::ImageSkia BrowserView::GetOTRAvatarIcon() const {
659  return *GetThemeProvider()->GetImageSkiaNamed(GetOTRIconResourceID());
660}
661
662bool BrowserView::IsPositionInWindowCaption(const gfx::Point& point) {
663  if (window_switcher_button_) {
664    gfx::Point window_switcher_point(point);
665    views::View::ConvertPointToTarget(this, window_switcher_button_,
666                                      &window_switcher_point);
667    if (window_switcher_button_->HitTestPoint(window_switcher_point))
668      return false;
669  }
670  return GetBrowserViewLayout()->IsPositionInWindowCaption(point);
671}
672
673///////////////////////////////////////////////////////////////////////////////
674// BrowserView, BrowserWindow implementation:
675
676void BrowserView::Show() {
677  // If the window is already visible, just activate it.
678  if (frame_->IsVisible()) {
679    frame_->Activate();
680    return;
681  }
682
683  CreateLauncherIcon();
684
685  // Showing the window doesn't make the browser window active right away.
686  // This can cause SetFocusToLocationBar() to skip setting focus to the
687  // location bar. To avoid this we explicilty let SetFocusToLocationBar()
688  // know that it's ok to steal focus.
689  force_location_bar_focus_ = true;
690
691  // Setting the focus doesn't work when the window is invisible, so any focus
692  // initialization that happened before this will be lost.
693  //
694  // We really "should" restore the focus whenever the window becomes unhidden,
695  // but I think initializing is the only time where this can happen where
696  // there is some focus change we need to pick up, and this is easier than
697  // plumbing through an un-hide message all the way from the frame.
698  //
699  // If we do find there are cases where we need to restore the focus on show,
700  // that should be added and this should be removed.
701  RestoreFocus();
702
703  frame_->Show();
704
705  force_location_bar_focus_ = false;
706
707  browser()->OnWindowDidShow();
708
709  chrome::MaybeShowInvertBubbleView(browser_.get(), contents_container_);
710}
711
712void BrowserView::ShowInactive() {
713  if (frame_->IsVisible())
714    return;
715  CreateLauncherIcon();
716  frame_->ShowInactive();
717}
718
719void BrowserView::Hide() {
720  // Not implemented.
721}
722
723void BrowserView::SetBounds(const gfx::Rect& bounds) {
724  ExitFullscreen();
725  GetWidget()->SetBounds(bounds);
726}
727
728void BrowserView::Close() {
729  frame_->Close();
730}
731
732void BrowserView::Activate() {
733  frame_->Activate();
734}
735
736void BrowserView::Deactivate() {
737  frame_->Deactivate();
738}
739
740bool BrowserView::IsActive() const {
741  return frame_->IsActive();
742}
743
744void BrowserView::FlashFrame(bool flash) {
745  frame_->FlashFrame(flash);
746}
747
748bool BrowserView::IsAlwaysOnTop() const {
749  return false;
750}
751
752gfx::NativeWindow BrowserView::GetNativeWindow() {
753  // While the browser destruction is going on, the widget can already be gone,
754  // but utility functions like FindBrowserWithWindow will come here and crash.
755  // We short circuit therefore.
756  if (!GetWidget())
757    return NULL;
758  return GetWidget()->GetTopLevelWidget()->GetNativeWindow();
759}
760
761BrowserWindowTesting* BrowserView::GetBrowserWindowTesting() {
762  return this;
763}
764
765StatusBubble* BrowserView::GetStatusBubble() {
766  return status_bubble_.get();
767}
768
769namespace {
770  // Only used by ToolbarSizeChanged() below, but placed here because template
771  // arguments (to base::AutoReset<>) must have external linkage.
772  enum CallState { NORMAL, REENTRANT, REENTRANT_FORCE_FAST_RESIZE };
773}
774
775void BrowserView::UpdateTitleBar() {
776  frame_->UpdateWindowTitle();
777  if (ShouldShowWindowIcon() && !loading_animation_timer_.IsRunning())
778    frame_->UpdateWindowIcon();
779}
780
781void BrowserView::BookmarkBarStateChanged(
782    BookmarkBar::AnimateChangeType change_type) {
783  if (bookmark_bar_view_.get()) {
784    BookmarkBar::State new_state = browser_->bookmark_bar_state();
785
786    // We don't properly support animating the bookmark bar to and from the
787    // detached state in immersive fullscreen.
788    bool detached_changed = (new_state == BookmarkBar::DETACHED) ||
789        bookmark_bar_view_->IsDetached();
790    if (detached_changed && immersive_mode_controller_->IsEnabled())
791      change_type = BookmarkBar::DONT_ANIMATE_STATE_CHANGE;
792
793    bookmark_bar_view_->SetBookmarkBarState(new_state, change_type);
794  }
795  if (MaybeShowBookmarkBar(GetActiveWebContents()))
796    Layout();
797}
798
799void BrowserView::UpdateDevTools() {
800  UpdateDevToolsForContents(GetActiveWebContents());
801  Layout();
802}
803
804void BrowserView::UpdateLoadingAnimations(bool should_animate) {
805  if (should_animate) {
806    if (!loading_animation_timer_.IsRunning()) {
807      // Loads are happening, and the timer isn't running, so start it.
808      last_animation_time_ = base::TimeTicks::Now();
809      loading_animation_timer_.Start(FROM_HERE,
810          TimeDelta::FromMilliseconds(kLoadingAnimationFrameTimeMs), this,
811          &BrowserView::LoadingAnimationCallback);
812    }
813  } else {
814    if (loading_animation_timer_.IsRunning()) {
815      last_animation_time_ = base::TimeTicks();
816      loading_animation_timer_.Stop();
817      // Loads are now complete, update the state if a task was scheduled.
818      LoadingAnimationCallback();
819    }
820  }
821}
822
823void BrowserView::SetStarredState(bool is_starred) {
824  GetLocationBarView()->SetStarToggled(is_starred);
825}
826
827void BrowserView::ZoomChangedForActiveTab(bool can_show_bubble) {
828  GetLocationBarView()->ZoomChangedForActiveTab(
829      can_show_bubble && !toolbar_->IsWrenchMenuShowing());
830}
831
832gfx::Rect BrowserView::GetRestoredBounds() const {
833  return frame_->GetRestoredBounds();
834}
835
836ui::WindowShowState BrowserView::GetRestoredState() const {
837  if (IsMaximized())
838    return ui::SHOW_STATE_MAXIMIZED;
839  if (IsMinimized())
840    return ui::SHOW_STATE_MINIMIZED;
841  return ui::SHOW_STATE_NORMAL;
842}
843
844gfx::Rect BrowserView::GetBounds() const {
845  return frame_->GetWindowBoundsInScreen();
846}
847
848bool BrowserView::IsMaximized() const {
849  return frame_->IsMaximized();
850}
851
852bool BrowserView::IsMinimized() const {
853  return frame_->IsMinimized();
854}
855
856void BrowserView::Maximize() {
857  frame_->Maximize();
858}
859
860void BrowserView::Minimize() {
861  frame_->Minimize();
862}
863
864void BrowserView::Restore() {
865  frame_->Restore();
866}
867
868void BrowserView::EnterFullscreen(
869    const GURL& url, FullscreenExitBubbleType bubble_type) {
870  if (IsFullscreen())
871    return;  // Nothing to do.
872
873  ProcessFullscreen(true, FOR_DESKTOP, url, bubble_type);
874}
875
876void BrowserView::ExitFullscreen() {
877  if (!IsFullscreen())
878    return;  // Nothing to do.
879
880  ProcessFullscreen(false, FOR_DESKTOP, GURL(), FEB_TYPE_NONE);
881}
882
883void BrowserView::UpdateFullscreenExitBubbleContent(
884    const GURL& url,
885    FullscreenExitBubbleType bubble_type) {
886  // Immersive mode has no exit bubble because it has a visible strip at the
887  // top that gives the user a hover target.
888  // TODO(jamescook): Figure out what to do with mouse-lock.
889  if (bubble_type == FEB_TYPE_NONE || UseImmersiveFullscreenForUrl(url)) {
890    fullscreen_bubble_.reset();
891  } else if (fullscreen_bubble_.get()) {
892    fullscreen_bubble_->UpdateContent(url, bubble_type);
893  } else {
894    fullscreen_bubble_.reset(new FullscreenExitBubbleViews(
895        this, url, bubble_type));
896  }
897}
898
899bool BrowserView::ShouldHideUIForFullscreen() const {
900#if defined(USE_ASH)
901  // Immersive mode needs UI for the slide-down top panel.
902  return IsFullscreen() && !immersive_mode_controller_->IsEnabled();
903#endif
904  return IsFullscreen();
905}
906
907bool BrowserView::IsFullscreen() const {
908  return frame_->IsFullscreen();
909}
910
911bool BrowserView::IsFullscreenBubbleVisible() const {
912  return fullscreen_bubble_ != NULL;
913}
914
915#if defined(OS_WIN)
916void BrowserView::SetMetroSnapMode(bool enable) {
917  HISTOGRAM_COUNTS("Metro.SnapModeToggle", enable);
918  ProcessFullscreen(enable, FOR_METRO, GURL(), FEB_TYPE_NONE);
919}
920
921bool BrowserView::IsInMetroSnapMode() const {
922#if defined(USE_AURA)
923  return false;
924#else
925  return static_cast<views::NativeWidgetWin*>(
926      frame_->native_widget())->IsInMetroSnapMode();
927#endif
928}
929#endif  // defined(OS_WIN)
930
931void BrowserView::RestoreFocus() {
932  WebContents* selected_web_contents = GetActiveWebContents();
933  if (selected_web_contents)
934    selected_web_contents->GetView()->RestoreFocus();
935}
936
937void BrowserView::SetWindowSwitcherButton(views::Button* button) {
938  if (window_switcher_button_)
939    RemoveChildView(window_switcher_button_);
940  window_switcher_button_ = button;
941  AddChildView(button);
942}
943
944void BrowserView::ToolbarSizeChanged(bool is_animating) {
945  // The call to InfoBarContainer::SetMaxTopArrowHeight() below can result in
946  // reentrancy; |call_state| tracks whether we're reentrant.  We can't just
947  // early-return in this case because we need to layout again so the infobar
948  // container's bounds are set correctly.
949  static CallState call_state = NORMAL;
950
951  // A reentrant call can (and should) use the fast resize path unless both it
952  // and the normal call are both non-animating.
953  bool use_fast_resize =
954      is_animating || (call_state == REENTRANT_FORCE_FAST_RESIZE);
955  if (use_fast_resize)
956    contents_web_view_->SetFastResize(true);
957  UpdateUIForContents(GetActiveWebContents());
958  if (use_fast_resize)
959    contents_web_view_->SetFastResize(false);
960
961  // Inform the InfoBarContainer that the distance to the location icon may have
962  // changed.  We have to do this after the block above so that the toolbars are
963  // laid out correctly for calculating the maximum arrow height below.
964  {
965    base::AutoReset<CallState> resetter(&call_state,
966        is_animating ? REENTRANT_FORCE_FAST_RESIZE : REENTRANT);
967    infobar_container_->SetMaxTopArrowHeight(GetMaxTopInfoBarArrowHeight());
968  }
969
970  // When transitioning from animating to not animating we need to make sure the
971  // contents_container_ gets layed out. If we don't do this and the bounds
972  // haven't changed contents_container_ won't get a Layout out and we'll end up
973  // with a gray rect because the clip wasn't updated.  Note that a reentrant
974  // call never needs to do this, because after it returns, the normal call
975  // wrapping it will do it.
976  if ((call_state == NORMAL) && !is_animating) {
977    contents_web_view_->InvalidateLayout();
978    contents_split_->Layout();
979  }
980}
981
982void BrowserView::OnOverlayStateChanged(bool repaint_infobars) {
983  Layout();
984
985  // |top_container_| paints to a layer when in immersive fullscreen. Paint
986  // |overlay_container_| to a layer in this case so that the overlay stays
987  // stacked on top of |top_container_| in z-order.
988  if (overlay_container_->visible() &&
989      immersive_mode_controller_->IsRevealed()) {
990    overlay_container_->SetPaintToLayer(true);
991    overlay_container_->SetFillsBoundsOpaquely(false);
992  }
993
994  // When immersive mode is not reveal and infobar container is visible, set top
995  // infobar arrow as per overlay state.  Layout() needs to happen before
996  // GetMaxTopInfoBarArrowHeight() because the latter checks for visibility of
997  // overlay_container_| which is determined in Layout().
998  if (repaint_infobars &&
999      infobar_container_->visible() &&
1000      !immersive_mode_controller_->IsRevealed()) {
1001    infobar_container_->SetMaxTopArrowHeight(GetMaxTopInfoBarArrowHeight());
1002  }
1003}
1004
1005LocationBar* BrowserView::GetLocationBar() const {
1006  return GetLocationBarView();
1007}
1008
1009void BrowserView::SetFocusToLocationBar(bool select_all) {
1010  // On Windows, changing focus to the location bar causes the browser
1011  // window to become active. This can steal focus if the user has
1012  // another window open already. On ChromeOS, changing focus makes a
1013  // view believe it has a focus even if the widget doens't have a
1014  // focus. Either cases, we need to ignore this when the browser
1015  // window isn't active.
1016  if (!force_location_bar_focus_ && !IsActive())
1017    return;
1018
1019  // Temporarily reveal the top-of-window views (if not already revealed) so
1020  // that the location bar view is visible and is considered focusable. If the
1021  // location bar view gains focus, |immersive_mode_controller_| will keep the
1022  // top-of-window views revealed.
1023  scoped_ptr<ImmersiveRevealedLock> focus_reveal_lock(
1024      immersive_mode_controller_->GetRevealedLock(
1025          ImmersiveModeController::ANIMATE_REVEAL_YES));
1026
1027  LocationBarView* location_bar = GetLocationBarView();
1028  if (location_bar->IsLocationEntryFocusableInRootView()) {
1029    // Location bar got focus.
1030    location_bar->FocusLocation(select_all);
1031  } else {
1032    // If none of location bar got focus,
1033    // then clear focus.
1034    views::FocusManager* focus_manager = GetFocusManager();
1035    DCHECK(focus_manager);
1036    focus_manager->ClearFocus();
1037  }
1038}
1039
1040void BrowserView::UpdateReloadStopState(bool is_loading, bool force) {
1041  toolbar_->reload_button()->ChangeMode(
1042      is_loading ? ReloadButton::MODE_STOP : ReloadButton::MODE_RELOAD, force);
1043}
1044
1045void BrowserView::UpdateToolbar(content::WebContents* contents,
1046                                bool should_restore_state) {
1047  toolbar_->Update(contents, should_restore_state);
1048}
1049
1050void BrowserView::FocusToolbar() {
1051  // Temporarily reveal the top-of-window views (if not already revealed) so
1052  // that the toolbar is visible and is considered focusable. If the
1053  // toolbar gains focus, |immersive_mode_controller_| will keep the
1054  // top-of-window views revealed.
1055  scoped_ptr<ImmersiveRevealedLock> focus_reveal_lock(
1056      immersive_mode_controller_->GetRevealedLock(
1057          ImmersiveModeController::ANIMATE_REVEAL_YES));
1058
1059  // Start the traversal within the main toolbar. SetPaneFocus stores
1060  // the current focused view before changing focus.
1061  toolbar_->SetPaneFocus(NULL);
1062}
1063
1064void BrowserView::FocusBookmarksToolbar() {
1065  DCHECK(!immersive_mode_controller_->IsEnabled());
1066  if (bookmark_bar_view_.get() &&
1067      bookmark_bar_view_->visible() &&
1068      bookmark_bar_view_->GetPreferredSize().height() != 0) {
1069    bookmark_bar_view_->SetPaneFocusAndFocusDefault();
1070  }
1071}
1072
1073void BrowserView::FocusInfobars() {
1074  if (infobar_container_->child_count() > 0)
1075    infobar_container_->SetPaneFocusAndFocusDefault();
1076}
1077
1078void BrowserView::FocusAppMenu() {
1079  // Chrome doesn't have a traditional menu bar, but it has a menu button in the
1080  // main toolbar that plays the same role.  If the user presses a key that
1081  // would typically focus the menu bar, tell the toolbar to focus the menu
1082  // button.  If the user presses the key again, return focus to the previous
1083  // location.
1084  //
1085  // Not used on the Mac, which has a normal menu bar.
1086  if (toolbar_->IsAppMenuFocused()) {
1087    RestoreFocus();
1088  } else {
1089    DCHECK(!immersive_mode_controller_->IsEnabled());
1090    toolbar_->SetPaneFocusAndFocusAppMenu();
1091  }
1092}
1093
1094void BrowserView::RotatePaneFocus(bool forwards) {
1095  GetWidget()->GetFocusManager()->RotatePaneFocus(
1096      forwards ?
1097          views::FocusManager::kForward : views::FocusManager::kBackward,
1098      views::FocusManager::kWrap);
1099}
1100
1101void BrowserView::DestroyBrowser() {
1102  // After this returns other parts of Chrome are going to be shutdown. Close
1103  // the window now so that we are deleted immediately and aren't left holding
1104  // references to deleted objects.
1105  GetWidget()->RemoveObserver(this);
1106  frame_->CloseNow();
1107}
1108
1109bool BrowserView::IsBookmarkBarVisible() const {
1110  if (!browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR))
1111    return false;
1112  if (!bookmark_bar_view_.get())
1113    return false;
1114  if (bookmark_bar_view_->GetPreferredSize().height() == 0)
1115    return false;
1116  // New tab page needs visible bookmarks even when top-views are hidden.
1117  if (immersive_mode_controller_->ShouldHideTopViews() &&
1118      !bookmark_bar_view_->IsDetached())
1119    return false;
1120  return true;
1121}
1122
1123bool BrowserView::IsBookmarkBarAnimating() const {
1124  return bookmark_bar_view_.get() && bookmark_bar_view_->is_animating();
1125}
1126
1127bool BrowserView::IsTabStripEditable() const {
1128  return tabstrip_->IsTabStripEditable();
1129}
1130
1131bool BrowserView::IsToolbarVisible() const {
1132  if (immersive_mode_controller_->ShouldHideTopViews())
1133    return false;
1134  return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) ||
1135         browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
1136}
1137
1138gfx::Rect BrowserView::GetRootWindowResizerRect() const {
1139  // Views does not support resizer rects because they caused page cycler
1140  // performance regressions when they were added. See crrev.com/9654
1141  return gfx::Rect();
1142}
1143
1144void BrowserView::DisableInactiveFrame() {
1145#if defined(OS_WIN) && !defined(USE_AURA)
1146  frame_->DisableInactiveRendering();
1147#endif  // No tricks are needed to get the right behavior on Linux.
1148}
1149
1150void BrowserView::ConfirmAddSearchProvider(TemplateURL* template_url,
1151                                           Profile* profile) {
1152  chrome::EditSearchEngine(GetWidget()->GetNativeWindow(), template_url, NULL,
1153                           profile);
1154}
1155
1156void BrowserView::ToggleBookmarkBar() {
1157  chrome::ToggleBookmarkBarWhenVisible(browser_->profile());
1158}
1159
1160void BrowserView::ShowUpdateChromeDialog() {
1161  UpdateRecommendedMessageBox::Show(GetWidget()->GetNativeWindow());
1162}
1163
1164void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) {
1165  // Reveal the top-of-window views immediately (if they are not already
1166  // revealed) because it looks weird to show the bookmark bubble while the
1167  // top-of-window views are still animating. If the bookmark bubble gains
1168  // focus, |immersive_mode_controller_| will keep the top-of-window views
1169  // revealed.
1170  scoped_ptr<ImmersiveRevealedLock> focus_reveal_lock(
1171      immersive_mode_controller_->GetRevealedLock(
1172          ImmersiveModeController::ANIMATE_REVEAL_NO));
1173
1174  chrome::ShowBookmarkBubbleView(GetToolbarView()->GetBookmarkBubbleAnchor(),
1175                                 bookmark_bar_view_.get(), browser_->profile(),
1176                                 url, !already_bookmarked);
1177}
1178
1179void BrowserView::ShowBookmarkPrompt() {
1180  GetLocationBarView()->ShowBookmarkPrompt();
1181}
1182
1183void BrowserView::ShowChromeToMobileBubble() {
1184  GetLocationBarView()->ShowChromeToMobileBubble();
1185}
1186
1187#if defined(ENABLE_ONE_CLICK_SIGNIN)
1188void BrowserView::ShowOneClickSigninBubble(
1189    OneClickSigninBubbleType type,
1190    const string16& email,
1191    const string16& error_message,
1192    const StartSyncCallback& start_sync_callback) {
1193  OneClickSigninBubbleView::ShowBubble(type, email, error_message,
1194                                       toolbar_, start_sync_callback);
1195}
1196#endif
1197
1198void BrowserView::SetDownloadShelfVisible(bool visible) {
1199  // This can be called from the superclass destructor, when it destroys our
1200  // child views. At that point, browser_ is already gone.
1201  if (browser_ == NULL)
1202    return;
1203
1204  if (visible && IsDownloadShelfVisible() != visible) {
1205    // Invoke GetDownloadShelf to force the shelf to be created.
1206    GetDownloadShelf();
1207  }
1208
1209  if (browser_ != NULL)
1210    browser_->UpdateDownloadShelfVisibility(visible);
1211
1212  // SetDownloadShelfVisible can force-close the shelf, so make sure we lay out
1213  // everything correctly, as if the animation had finished. This doesn't
1214  // matter for showing the shelf, as the show animation will do it.
1215  ToolbarSizeChanged(false);
1216}
1217
1218bool BrowserView::IsDownloadShelfVisible() const {
1219  return download_shelf_.get() && download_shelf_->IsShowing();
1220}
1221
1222DownloadShelf* BrowserView::GetDownloadShelf() {
1223  if (!download_shelf_.get()) {
1224    download_shelf_.reset(new DownloadShelfView(browser_.get(), this));
1225    download_shelf_->set_owned_by_client();
1226    GetBrowserViewLayout()->set_download_shelf(download_shelf_.get());
1227  }
1228  return download_shelf_.get();
1229}
1230
1231void BrowserView::ConfirmBrowserCloseWithPendingDownloads() {
1232  DownloadInProgressDialogView::Show(browser_.get(), GetNativeWindow());
1233}
1234
1235void BrowserView::ShowCreateChromeAppShortcutsDialog(
1236    Profile* profile,
1237    const extensions::Extension* app) {
1238  chrome::ShowCreateChromeAppShortcutsDialog(GetNativeWindow(), profile, app);
1239}
1240
1241void BrowserView::UserChangedTheme() {
1242  frame_->FrameTypeChanged();
1243}
1244
1245int BrowserView::GetExtraRenderViewHeight() const {
1246  // Currently this is only used on linux.
1247  return 0;
1248}
1249
1250void BrowserView::WebContentsFocused(WebContents* contents) {
1251  if (contents_web_view_->GetWebContents() == contents)
1252    contents_web_view_->OnWebContentsFocused(contents);
1253  else if (overlay_container_->overlay_web_contents() == contents)
1254    overlay_controller_->overlay()->OnWebContentsFocused(contents);
1255  else
1256    devtools_container_->OnWebContentsFocused(contents);
1257}
1258
1259void BrowserView::ShowWebsiteSettings(Profile* profile,
1260                                      content::WebContents* web_contents,
1261                                      const GURL& url,
1262                                      const content::SSLStatus& ssl,
1263                                      bool show_history) {
1264  WebsiteSettingsPopupView::ShowPopup(
1265      GetLocationBarView()->location_icon_view(), profile,
1266      web_contents, url, ssl, browser_.get());
1267}
1268
1269void BrowserView::ShowAppMenu() {
1270  // Keep the top-of-window views revealed as long as the app menu is visible.
1271  scoped_ptr<ImmersiveRevealedLock> revealed_lock(
1272      immersive_mode_controller_->GetRevealedLock(
1273          ImmersiveModeController::ANIMATE_REVEAL_NO));
1274
1275  toolbar_->app_menu()->Activate();
1276}
1277
1278bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
1279                                         bool* is_keyboard_shortcut) {
1280  *is_keyboard_shortcut = false;
1281
1282  if ((event.type != WebKit::WebInputEvent::RawKeyDown) &&
1283      (event.type != WebKit::WebInputEvent::KeyUp)) {
1284    return false;
1285  }
1286
1287#if defined(OS_WIN) && !defined(USE_AURA)
1288  // As Alt+F4 is the close-app keyboard shortcut, it needs processing
1289  // immediately.
1290  if (event.windowsKeyCode == ui::VKEY_F4 &&
1291      event.type == WebKit::WebInputEvent::RawKeyDown &&
1292      event.modifiers == NativeWebKeyboardEvent::AltKey) {
1293    DefWindowProc(event.os_event.hwnd, event.os_event.message,
1294                  event.os_event.wParam, event.os_event.lParam);
1295    return true;
1296  }
1297#endif
1298
1299  views::FocusManager* focus_manager = GetFocusManager();
1300  DCHECK(focus_manager);
1301
1302  if (focus_manager->shortcut_handling_suspended())
1303    return false;
1304
1305  ui::Accelerator accelerator(
1306      static_cast<ui::KeyboardCode>(event.windowsKeyCode),
1307      content::GetModifiersFromNativeWebKeyboardEvent(event));
1308  if (event.type == WebKit::WebInputEvent::KeyUp)
1309    accelerator.set_type(ui::ET_KEY_RELEASED);
1310
1311  // What we have to do here is as follows:
1312  // - If the |browser_| is for an app, do nothing.
1313  // - If the |browser_| is not for an app, and the |accelerator| is not
1314  //   associated with the browser (e.g. an Ash shortcut), process it.
1315  // - If the |browser_| is not for an app, and the |accelerator| is associated
1316  //   with the browser, and it is a reserved one (e.g. Ctrl+w), process it.
1317  // - If the |browser_| is not for an app, and the |accelerator| is associated
1318  //   with the browser, and it is not a reserved one, do nothing.
1319
1320  if (browser_->is_app()) {
1321    // We don't have to flip |is_keyboard_shortcut| here. If we do that, the app
1322    // might not be able to see a subsequent Char event. See OnHandleInputEvent
1323    // in content/renderer/render_widget.cc for details.
1324    return false;
1325  }
1326
1327  chrome::BrowserCommandController* controller = browser_->command_controller();
1328
1329  // Here we need to retrieve the command id (if any) associated to the
1330  // keyboard event. Instead of looking up the command id in the
1331  // |accelerator_table_| by ourselves, we block the command execution of
1332  // the |browser_| object then send the keyboard event to the
1333  // |focus_manager| as if we are activating an accelerator key.
1334  // Then we can retrieve the command id from the |browser_| object.
1335  controller->SetBlockCommandExecution(true);
1336  // If the |accelerator| is a non-browser shortcut (e.g. Ash shortcut), the
1337  // command execution cannot be blocked and true is returned. However, it is
1338  // okay as long as is_app() is false. See comments in this function.
1339  const bool processed = focus_manager->ProcessAccelerator(accelerator);
1340  const int id = controller->GetLastBlockedCommand(NULL);
1341  controller->SetBlockCommandExecution(false);
1342
1343  // Executing the command may cause |this| object to be destroyed.
1344  if (controller->IsReservedCommandOrKey(id, event)) {
1345    UpdateAcceleratorMetrics(accelerator, id);
1346    return chrome::ExecuteCommand(browser_.get(), id);
1347  }
1348
1349  if (id != -1) {
1350    // |accelerator| is a non-reserved browser shortcut (e.g. Ctrl+f).
1351    if (event.type == WebKit::WebInputEvent::RawKeyDown)
1352      *is_keyboard_shortcut = true;
1353  } else if (processed) {
1354    // |accelerator| is a non-browser shortcut (e.g. F4-F10 on Ash).
1355    return true;
1356  }
1357
1358  return false;
1359}
1360
1361void BrowserView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
1362  unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
1363                                                        GetFocusManager());
1364}
1365
1366// TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always
1367// enabled in the page menu regardless of whether the command will do
1368// anything. When someone selects the menu item, we just act as if they hit
1369// the keyboard shortcut for the command by sending the associated key press
1370// to windows. The real fix to this bug is to disable the commands when they
1371// won't do anything. We'll need something like an overall clipboard command
1372// manager to do that.
1373void BrowserView::Cut() {
1374  // If a WebContent is focused, call RenderWidgetHost::Cut. Otherwise, e.g. if
1375  // Omnibox is focused, send a Ctrl+x key event to Chrome. Using RWH interface
1376  // rather than the fake key event for a WebContent is important since the fake
1377  // event might be consumed by the web content (crbug.com/137908).
1378  DoCutCopyPaste(&content::RenderWidgetHost::Cut,
1379#if defined(OS_WIN)
1380                 WM_CUT,
1381#endif
1382                 IDS_APP_CUT);
1383}
1384
1385void BrowserView::Copy() {
1386  DoCutCopyPaste(&content::RenderWidgetHost::Copy,
1387#if defined(OS_WIN)
1388                 WM_COPY,
1389#endif
1390                 IDS_APP_COPY);
1391}
1392
1393void BrowserView::Paste() {
1394  DoCutCopyPaste(&content::RenderWidgetHost::Paste,
1395#if defined(OS_WIN)
1396                 WM_PASTE,
1397#endif
1398                 IDS_APP_PASTE);
1399}
1400
1401gfx::Rect BrowserView::GetInstantBounds() {
1402  return overlay_container_->GetOverlayBounds();
1403}
1404
1405WindowOpenDisposition BrowserView::GetDispositionForPopupBounds(
1406    const gfx::Rect& bounds) {
1407#if defined(OS_WIN)
1408  // If we are in Win8's single window Metro mode, we can't allow popup windows.
1409  return win8::IsSingleWindowMetroMode() ? NEW_BACKGROUND_TAB : NEW_POPUP;
1410#else
1411  return NEW_POPUP;
1412#endif
1413}
1414
1415FindBar* BrowserView::CreateFindBar() {
1416  return chrome::CreateFindBar(this);
1417}
1418
1419WebContentsModalDialogHost* BrowserView::GetWebContentsModalDialogHost() {
1420  return GetBrowserViewLayout()->GetWebContentsModalDialogHost();
1421}
1422
1423///////////////////////////////////////////////////////////////////////////////
1424// BrowserView, BrowserWindowTesting implementation:
1425
1426BookmarkBarView* BrowserView::GetBookmarkBarView() const {
1427  return bookmark_bar_view_.get();
1428}
1429
1430LocationBarView* BrowserView::GetLocationBarView() const {
1431  return toolbar_ ? toolbar_->location_bar() : NULL;
1432}
1433
1434views::View* BrowserView::GetTabContentsContainerView() const {
1435  return contents_web_view_;
1436}
1437
1438ToolbarView* BrowserView::GetToolbarView() const {
1439  return toolbar_;
1440}
1441
1442///////////////////////////////////////////////////////////////////////////////
1443// BrowserView, TabStripModelObserver implementation:
1444
1445void BrowserView::TabDetachedAt(WebContents* contents, int index) {
1446  // We use index here rather than comparing |contents| because by this time
1447  // the model has already removed |contents| from its list, so
1448  // browser_->GetActiveWebContents() will return NULL or something else.
1449  if (index == browser_->tab_strip_model()->active_index()) {
1450    // We need to reset the current tab contents to NULL before it gets
1451    // freed. This is because the focus manager performs some operations
1452    // on the selected WebContents when it is removed.
1453    contents_web_view_->SetWebContents(NULL);
1454    infobar_container_->ChangeInfoBarService(NULL);
1455    UpdateDevToolsForContents(NULL);
1456  }
1457}
1458
1459void BrowserView::TabDeactivated(WebContents* contents) {
1460  // We do not store the focus when closing the tab to work-around bug 4633.
1461  // Some reports seem to show that the focus manager and/or focused view can
1462  // be garbage at that point, it is not clear why.
1463  if (!contents->IsBeingDestroyed())
1464    contents->GetView()->StoreFocus();
1465}
1466
1467void BrowserView::ActiveTabChanged(content::WebContents* old_contents,
1468                                   content::WebContents* new_contents,
1469                                   int index,
1470                                   int reason) {
1471  DCHECK(new_contents);
1472
1473  // See if the Instant overlay is being activated (committed).
1474  if (overlay_container_->overlay_web_contents() == new_contents) {
1475    MakeOverlayContentsActiveContents();
1476    views::WebView* old_container = contents_web_view_;
1477    contents_web_view_ = overlay_controller_->release_overlay();
1478    old_container->SetWebContents(NULL);
1479    delete old_container;
1480  }
1481
1482  // If |contents_container_| already has the correct WebContents, we can save
1483  // some work.  This also prevents extra events from being reported by the
1484  // Visibility API under Windows, as ChangeWebContents will briefly hide
1485  // the WebContents window.
1486  bool change_tab_contents =
1487      contents_web_view_->web_contents() != new_contents;
1488
1489  // Update various elements that are interested in knowing the current
1490  // WebContents.
1491
1492  // When we toggle the NTP floating bookmarks bar and/or the info bar,
1493  // we don't want any WebContents to be attached, so that we
1494  // avoid an unnecessary resize and re-layout of a WebContents.
1495  if (change_tab_contents)
1496    contents_web_view_->SetWebContents(NULL);
1497  infobar_container_->ChangeInfoBarService(
1498      InfoBarService::FromWebContents(new_contents));
1499  if (bookmark_bar_view_.get()) {
1500    bookmark_bar_view_->SetBookmarkBarState(
1501        browser_->bookmark_bar_state(),
1502        BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
1503  }
1504  UpdateUIForContents(new_contents);
1505
1506  // Layout for DevTools _before_ setting the main WebContents to avoid
1507  // toggling the size of the main WebContents.
1508  UpdateDevToolsForContents(new_contents);
1509
1510  if (change_tab_contents)
1511    contents_web_view_->SetWebContents(new_contents);
1512
1513  if (!browser_->tab_strip_model()->closing_all() && GetWidget()->IsActive() &&
1514      GetWidget()->IsVisible()) {
1515    // We only restore focus if our window is visible, to avoid invoking blur
1516    // handlers when we are eventually shown.
1517    new_contents->GetView()->RestoreFocus();
1518  }
1519
1520  // Update all the UI bits.
1521  UpdateTitleBar();
1522
1523  // No need to update Toolbar because it's already updated in
1524  // browser.cc.
1525}
1526
1527void BrowserView::TabStripEmpty() {
1528  // Make sure all optional UI is removed before we are destroyed, otherwise
1529  // there will be consequences (since our view hierarchy will still have
1530  // references to freed views).
1531  UpdateUIForContents(NULL);
1532}
1533
1534///////////////////////////////////////////////////////////////////////////////
1535// BrowserView, ui::AcceleratorProvider implementation:
1536
1537bool BrowserView::GetAcceleratorForCommandId(int command_id,
1538                                             ui::Accelerator* accelerator) {
1539  // Let's let the ToolbarView own the canonical implementation of this method.
1540  return toolbar_->GetAcceleratorForCommandId(command_id, accelerator);
1541}
1542
1543///////////////////////////////////////////////////////////////////////////////
1544// BrowserView, views::WidgetDelegate implementation:
1545
1546bool BrowserView::CanResize() const {
1547  return true;
1548}
1549
1550bool BrowserView::CanMaximize() const {
1551  return true;
1552}
1553
1554bool BrowserView::CanActivate() const {
1555  if (!AppModalDialogQueue::GetInstance()->active_dialog())
1556    return true;
1557
1558#if defined(USE_AURA) && defined(OS_CHROMEOS)
1559  // On Aura window manager controls all windows so settings focus via PostTask
1560  // will make only worse because posted task will keep trying to steal focus.
1561  AppModalDialogQueue::GetInstance()->ActivateModalDialog();
1562#else
1563  // If another browser is app modal, flash and activate the modal browser. This
1564  // has to be done in a post task, otherwise if the user clicked on a window
1565  // that doesn't have the modal dialog the windows keep trying to get the focus
1566  // from each other on Windows. http://crbug.com/141650.
1567  base::MessageLoop::current()->PostTask(
1568      FROM_HERE,
1569      base::Bind(&BrowserView::ActivateAppModalDialog,
1570                 activate_modal_dialog_factory_.GetWeakPtr()));
1571#endif
1572  return false;
1573}
1574
1575string16 BrowserView::GetWindowTitle() const {
1576  return browser_->GetWindowTitleForCurrentTab();
1577}
1578
1579string16 BrowserView::GetAccessibleWindowTitle() const {
1580  if (IsOffTheRecord()) {
1581    return l10n_util::GetStringFUTF16(
1582        IDS_ACCESSIBLE_INCOGNITO_WINDOW_TITLE_FORMAT,
1583        GetWindowTitle());
1584  }
1585  return GetWindowTitle();
1586}
1587
1588views::View* BrowserView::GetInitiallyFocusedView() {
1589  return NULL;
1590}
1591
1592bool BrowserView::ShouldShowWindowTitle() const {
1593#if defined(USE_ASH)
1594  // For Ash only, app host windows do not show an icon, crbug.com/119411.
1595  // Child windows (i.e. popups) do show an icon.
1596  if (browser_->is_app() && browser_->app_type() == Browser::APP_TYPE_HOST)
1597    return false;
1598#endif
1599  return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR);
1600}
1601
1602gfx::ImageSkia BrowserView::GetWindowAppIcon() {
1603  if (browser_->is_app()) {
1604    WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents();
1605    extensions::TabHelper* extensions_tab_helper =
1606        contents ? extensions::TabHelper::FromWebContents(contents) : NULL;
1607    if (extensions_tab_helper && extensions_tab_helper->GetExtensionAppIcon())
1608      return gfx::ImageSkia::CreateFrom1xBitmap(
1609          *extensions_tab_helper->GetExtensionAppIcon());
1610  }
1611
1612  return GetWindowIcon();
1613}
1614
1615gfx::ImageSkia BrowserView::GetWindowIcon() {
1616  if (browser_->is_app())
1617    return browser_->GetCurrentPageIcon().AsImageSkia();
1618  return gfx::ImageSkia();
1619}
1620
1621bool BrowserView::ShouldShowWindowIcon() const {
1622#if defined(USE_ASH)
1623  // For Ash only, app host windows do not show an icon, crbug.com/119411.
1624  // Child windows (i.e. popups) do show an icon.
1625  if (browser_->is_app() && browser_->app_type() == Browser::APP_TYPE_HOST)
1626    return false;
1627#endif
1628  return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR);
1629}
1630
1631bool BrowserView::ExecuteWindowsCommand(int command_id) {
1632  // This function handles WM_SYSCOMMAND, WM_APPCOMMAND, and WM_COMMAND.
1633#if defined(OS_WIN)
1634  if (command_id == IDC_DEBUG_FRAME_TOGGLE)
1635    GetWidget()->DebugToggleFrameType();
1636
1637  // In Windows 8 metro mode prevent sizing and moving.
1638  if (win8::IsSingleWindowMetroMode()) {
1639    // Windows uses the 4 lower order bits of |notification_code| for type-
1640    // specific information so we must exclude this when comparing.
1641    static const int sc_mask = 0xFFF0;
1642    if (((command_id & sc_mask) == SC_MOVE) ||
1643        ((command_id & sc_mask) == SC_SIZE) ||
1644        ((command_id & sc_mask) == SC_MAXIMIZE))
1645      return true;
1646  }
1647#endif
1648  // Translate WM_APPCOMMAND command ids into a command id that the browser
1649  // knows how to handle.
1650  int command_id_from_app_command = GetCommandIDForAppCommandID(command_id);
1651  if (command_id_from_app_command != -1)
1652    command_id = command_id_from_app_command;
1653
1654  return chrome::ExecuteCommand(browser_.get(), command_id);
1655}
1656
1657std::string BrowserView::GetWindowName() const {
1658  return chrome::GetWindowPlacementKey(browser_.get());
1659}
1660
1661void BrowserView::SaveWindowPlacement(const gfx::Rect& bounds,
1662                                      ui::WindowShowState show_state) {
1663  // If IsFullscreen() is true, we've just changed into fullscreen mode, and
1664  // we're catching the going-into-fullscreen sizing and positioning calls,
1665  // which we want to ignore.
1666  if (!ShouldSaveOrRestoreWindowPos())
1667    return;
1668
1669  if (!IsFullscreen() && chrome::ShouldSaveWindowPlacement(browser_.get())) {
1670    WidgetDelegate::SaveWindowPlacement(bounds, show_state);
1671    chrome::SaveWindowPlacement(browser_.get(), bounds, show_state);
1672  }
1673}
1674
1675bool BrowserView::GetSavedWindowPlacement(
1676    gfx::Rect* bounds,
1677    ui::WindowShowState* show_state) const {
1678  if (!ShouldSaveOrRestoreWindowPos())
1679    return false;
1680  chrome::GetSavedWindowBoundsAndShowState(browser_.get(), bounds, show_state);
1681
1682#if defined(USE_ASH)
1683  if (chrome::IsNativeWindowInAsh(
1684          const_cast<BrowserView*>(this)->GetNativeWindow())) {
1685    if (browser_->is_type_popup()) {
1686      // In case of a popup with an 'unspecified' location we are
1687      // looking for a good screen location. We are interpreting (0,0) as an
1688      // unspecified location.
1689      if (bounds->x() == 0 && bounds->y() == 0) {
1690        *bounds = ChromeShellDelegate::instance()->window_positioner()->
1691            GetPopupPosition(*bounds);
1692      }
1693    }
1694  }
1695#endif
1696
1697  if (browser_->is_type_popup() &&
1698      !browser_->is_app() &&
1699      !browser_->is_devtools()) {
1700    // This is non-app popup window. The value passed in |bounds| represents
1701    // two pieces of information:
1702    // - the position of the window, in screen coordinates (outer position).
1703    // - the size of the content area (inner size).
1704    // We need to use these values to determine the appropriate size and
1705    // position of the resulting window.
1706    if (IsToolbarVisible()) {
1707      // If we're showing the toolbar, we need to adjust |*bounds| to include
1708      // its desired height, since the toolbar is considered part of the
1709      // window's client area as far as GetWindowBoundsForClientBounds is
1710      // concerned...
1711      bounds->set_height(
1712          bounds->height() + toolbar_->GetPreferredSize().height());
1713    }
1714
1715    gfx::Rect window_rect = frame_->non_client_view()->
1716        GetWindowBoundsForClientBounds(*bounds);
1717    window_rect.set_origin(bounds->origin());
1718
1719    // When we are given x/y coordinates of 0 on a created popup window,
1720    // assume none were given by the window.open() command.
1721    if (window_rect.x() == 0 && window_rect.y() == 0) {
1722      gfx::Size size = window_rect.size();
1723      window_rect.set_origin(
1724          WindowSizer::GetDefaultPopupOrigin(size,
1725                                             browser_->host_desktop_type()));
1726    }
1727
1728    *bounds = window_rect;
1729    *show_state = ui::SHOW_STATE_NORMAL;
1730  }
1731
1732  // We return true because we can _always_ locate reasonable bounds using the
1733  // WindowSizer, and we don't want to trigger the Window's built-in "size to
1734  // default" handling because the browser window has no default preferred
1735  // size.
1736  return true;
1737}
1738
1739views::View* BrowserView::GetContentsView() {
1740  return contents_web_view_;
1741}
1742
1743views::ClientView* BrowserView::CreateClientView(views::Widget* widget) {
1744  return this;
1745}
1746
1747void BrowserView::OnWidgetActivationChanged(views::Widget* widget,
1748                                            bool active) {
1749#if defined(USE_ASH)
1750  if (launcher_item_controller_.get())
1751    launcher_item_controller_->BrowserActivationStateChanged();
1752#endif
1753
1754  if (active)
1755    BrowserList::SetLastActive(browser_.get());
1756}
1757
1758void BrowserView::OnWindowBeginUserBoundsChange() {
1759  WebContents* web_contents = GetActiveWebContents();
1760  if (!web_contents)
1761    return;
1762  web_contents->GetRenderViewHost()->NotifyMoveOrResizeStarted();
1763}
1764
1765void BrowserView::OnWidgetMove() {
1766  if (!initialized_) {
1767    // Creating the widget can trigger a move. Ignore it until we've initialized
1768    // things.
1769    return;
1770  }
1771
1772  // Cancel any tabstrip animations, some of them may be invalidated by the
1773  // window being repositioned.
1774  // Comment out for one cycle to see if this fixes dist tests.
1775  // tabstrip_->DestroyDragController();
1776
1777  // status_bubble_ may be NULL if this is invoked during construction.
1778  if (status_bubble_.get())
1779    status_bubble_->Reposition();
1780
1781  chrome::HideBookmarkBubbleView();
1782
1783  // Close the omnibox popup, if any.
1784  LocationBarView* location_bar_view = GetLocationBarView();
1785  if (location_bar_view)
1786    location_bar_view->GetLocationEntry()->CloseOmniboxPopup();
1787}
1788
1789views::Widget* BrowserView::GetWidget() {
1790  return View::GetWidget();
1791}
1792
1793const views::Widget* BrowserView::GetWidget() const {
1794  return View::GetWidget();
1795}
1796
1797void BrowserView::GetAccessiblePanes(std::vector<views::View*>* panes) {
1798  // This should be in the order of pane traversal of the panes using F6
1799  // (Windows) or Ctrl+Back/Forward (Chrome OS).  If one of these is
1800  // invisible or has no focusable children, it will be automatically
1801  // skipped.
1802  panes->push_back(toolbar_);
1803  if (bookmark_bar_view_.get())
1804    panes->push_back(bookmark_bar_view_.get());
1805  if (infobar_container_)
1806    panes->push_back(infobar_container_);
1807  if (download_shelf_.get())
1808    panes->push_back(download_shelf_.get());
1809  panes->push_back(GetTabContentsContainerView());
1810  if (devtools_container_->visible())
1811    panes->push_back(devtools_container_);
1812}
1813
1814///////////////////////////////////////////////////////////////////////////////
1815// BrowserView, views::ClientView overrides:
1816
1817bool BrowserView::CanClose() {
1818  // You cannot close a frame for which there is an active originating drag
1819  // session.
1820  if (tabstrip_ && !tabstrip_->IsTabStripCloseable())
1821    return false;
1822
1823  // Give beforeunload handlers the chance to cancel the close before we hide
1824  // the window below.
1825  if (!browser_->ShouldCloseWindow())
1826    return false;
1827
1828  if (!browser_->tab_strip_model()->empty()) {
1829    // Tab strip isn't empty.  Hide the frame (so it appears to have closed
1830    // immediately) and close all the tabs, allowing the renderers to shut
1831    // down. When the tab strip is empty we'll be called back again.
1832    frame_->Hide();
1833    browser_->OnWindowClosing();
1834    browser_->tab_strip_model()->CloseAllTabs();
1835    return false;
1836  } else if (!browser_->HasCompletedUnloadProcessing()) {
1837    // The browser needs to finish running unload handlers.
1838    // Hide the frame (so it appears to have closed immediately), and
1839    // the browser will call us back again when it is ready to close.
1840    frame_->Hide();
1841    return false;
1842  }
1843
1844  // Empty TabStripModel, it's now safe to allow the Window to be closed.
1845  content::NotificationService::current()->Notify(
1846      chrome::NOTIFICATION_WINDOW_CLOSED,
1847      content::Source<gfx::NativeWindow>(frame_->GetNativeWindow()),
1848      content::NotificationService::NoDetails());
1849  return true;
1850}
1851
1852int BrowserView::NonClientHitTest(const gfx::Point& point) {
1853  return GetBrowserViewLayout()->NonClientHitTest(point);
1854}
1855
1856gfx::Size BrowserView::GetMinimumSize() {
1857  return GetBrowserViewLayout()->GetMinimumSize();
1858}
1859
1860///////////////////////////////////////////////////////////////////////////////
1861// BrowserView, views::View overrides:
1862
1863const char* BrowserView::GetClassName() const {
1864  return kViewClassName;
1865}
1866
1867void BrowserView::Layout() {
1868  if (ignore_layout_)
1869    return;
1870
1871  views::View::Layout();
1872
1873  // TODO(jamescook): Why was this in the middle of layout code?
1874  toolbar_->location_bar()->SetLocationEntryFocusable(IsToolbarVisible());
1875
1876  // The status bubble position requires that all other layout finish first.
1877  LayoutStatusBubble();
1878}
1879
1880void BrowserView::PaintChildren(gfx::Canvas* canvas) {
1881  // Paint the |infobar_container_| last so that it may paint its
1882  // overlapping tabs.
1883  for (int i = 0; i < child_count(); ++i) {
1884    View* child = child_at(i);
1885    if (child != infobar_container_)
1886      child->Paint(canvas);
1887  }
1888
1889  infobar_container_->Paint(canvas);
1890}
1891
1892void BrowserView::ViewHierarchyChanged(
1893    const ViewHierarchyChangedDetails& details) {
1894  if (!initialized_ && details.is_add && details.child == this && GetWidget()) {
1895    InitViews();
1896    initialized_ = true;
1897  }
1898}
1899
1900void BrowserView::ChildPreferredSizeChanged(View* child) {
1901  Layout();
1902}
1903
1904void BrowserView::GetAccessibleState(ui::AccessibleViewState* state) {
1905  state->role = ui::AccessibilityTypes::ROLE_CLIENT;
1906}
1907
1908///////////////////////////////////////////////////////////////////////////////
1909// BrowserView, ui::AcceleratorTarget overrides:
1910
1911bool BrowserView::AcceleratorPressed(const ui::Accelerator& accelerator) {
1912#if defined(OS_CHROMEOS)
1913  // If accessibility is enabled, stop speech and return false so that key
1914  // combinations involving Search can be used for extra accessibility
1915  // functionality.
1916  if (accelerator.key_code() == ui::VKEY_LWIN &&
1917      g_browser_process->local_state()->GetBoolean(
1918          prefs::kSpokenFeedbackEnabled)) {
1919    TtsController::GetInstance()->Stop();
1920    return false;
1921  }
1922#endif
1923
1924  std::map<ui::Accelerator, int>::const_iterator iter =
1925      accelerator_table_.find(accelerator);
1926  DCHECK(iter != accelerator_table_.end());
1927  int command_id = iter->second;
1928
1929  chrome::BrowserCommandController* controller = browser_->command_controller();
1930  if (!controller->block_command_execution())
1931    UpdateAcceleratorMetrics(accelerator, command_id);
1932  return chrome::ExecuteCommand(browser_.get(), command_id);
1933}
1934
1935///////////////////////////////////////////////////////////////////////////////
1936// BrowserView, ImmersiveModeController::Delegate overrides:
1937
1938BookmarkBarView* BrowserView::GetBookmarkBar() {
1939  return bookmark_bar_view_.get();
1940}
1941
1942FullscreenController* BrowserView::GetFullscreenController() {
1943  // Cannot be injected into ImmersiveModeController because it is constructed
1944  // after BrowserView.
1945  return browser()->fullscreen_controller();
1946}
1947
1948void BrowserView::FullscreenStateChanged() {
1949  if (IsFullscreen()) {
1950    ProcessFullscreen(true, FOR_DESKTOP, GURL(),
1951                      FEB_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION);
1952  } else {
1953    ProcessFullscreen(false, FOR_DESKTOP, GURL(), FEB_TYPE_NONE);
1954  }
1955}
1956
1957void BrowserView::SetImmersiveStyle(bool immersive) {
1958  // Only the tab strip changes its painting style for immersive fullscreen.
1959  if (tabstrip_)
1960    tabstrip_->SetImmersiveStyle(immersive);
1961}
1962
1963///////////////////////////////////////////////////////////////////////////////
1964// BrowserView, InfoBarContainer::Delegate overrides:
1965
1966SkColor BrowserView::GetInfoBarSeparatorColor() const {
1967  // NOTE: Keep this in sync with ToolbarView::OnPaint()!
1968  return (IsTabStripVisible() || !frame_->ShouldUseNativeFrame()) ?
1969      ThemeProperties::GetDefaultColor(
1970          ThemeProperties::COLOR_TOOLBAR_SEPARATOR) :
1971      SK_ColorBLACK;
1972}
1973
1974void BrowserView::InfoBarContainerStateChanged(bool is_animating) {
1975  ToolbarSizeChanged(is_animating);
1976}
1977
1978bool BrowserView::DrawInfoBarArrows(int* x) const {
1979  if (x) {
1980    const LocationIconView* location_icon_view =
1981        toolbar_->location_bar()->location_icon_view();
1982    gfx::Point icon_center(location_icon_view->GetImageBounds().CenterPoint());
1983    ConvertPointToTarget(location_icon_view, this, &icon_center);
1984    *x = icon_center.x();
1985  }
1986  return true;
1987}
1988
1989bool BrowserView::SplitHandleMoved(views::SingleSplitView* sender) {
1990  for (int i = 0; i < sender->child_count(); ++i)
1991    sender->child_at(i)->InvalidateLayout();
1992  SchedulePaint();
1993  Layout();
1994  return false;
1995}
1996
1997void BrowserView::OnSysColorChange() {
1998  chrome::MaybeShowInvertBubbleView(browser_.get(), contents_container_);
1999}
2000
2001void BrowserView::InitViews() {
2002  GetWidget()->AddObserver(this);
2003
2004  // Stow a pointer to this object onto the window handle so that we can get at
2005  // it later when all we have is a native view.
2006  GetWidget()->SetNativeWindowProperty(kBrowserViewKey, this);
2007
2008  // Stow a pointer to the browser's profile onto the window handle so that we
2009  // can get it later when all we have is a native view.
2010  GetWidget()->SetNativeWindowProperty(Profile::kProfileKey,
2011                                       browser_->profile());
2012
2013  // Start a hung plugin window detector for this browser object (as long as
2014  // hang detection is not disabled).
2015  if (!CommandLine::ForCurrentProcess()->HasSwitch(
2016          switches::kDisableHangMonitor)) {
2017    InitHangMonitor();
2018  }
2019
2020  LoadAccelerators();
2021
2022  infobar_container_ = new InfoBarContainerView(this,
2023                                                browser()->search_model());
2024  AddChildView(infobar_container_);
2025
2026  contents_web_view_ = new views::WebView(browser_->profile());
2027  contents_web_view_->set_id(VIEW_ID_TAB_CONTAINER);
2028  contents_container_ = new ContentsContainer(contents_web_view_);
2029
2030  SkColor bg_color = GetWidget()->GetThemeProvider()->
2031      GetColor(ThemeProperties::COLOR_TOOLBAR);
2032
2033  devtools_container_ = new views::WebView(browser_->profile());
2034  devtools_container_->set_id(VIEW_ID_DEV_TOOLS_DOCKED);
2035  devtools_container_->SetVisible(false);
2036
2037  views::View* contents_container_view = contents_container_;
2038
2039  contents_split_ = new views::SingleSplitView(
2040      contents_container_view,
2041      devtools_container_,
2042      views::SingleSplitView::VERTICAL_SPLIT,
2043      this);
2044  contents_split_->set_id(VIEW_ID_CONTENTS_SPLIT);
2045  contents_split_->SetAccessibleName(
2046      l10n_util::GetStringUTF16(IDS_ACCNAME_WEB_CONTENTS));
2047  contents_split_->set_background(
2048      views::Background::CreateSolidBackground(bg_color));
2049  AddChildView(contents_split_);
2050  set_contents_view(contents_split_);
2051
2052  status_bubble_.reset(new StatusBubbleViews(contents_container_));
2053
2054  // Top container holds tab strip and toolbar and lives at the front of the
2055  // view hierarchy.
2056  top_container_ = new TopContainerView(this);
2057  AddChildView(top_container_);
2058
2059  // TabStrip takes ownership of the controller.
2060  BrowserTabStripController* tabstrip_controller =
2061      new BrowserTabStripController(browser_.get(),
2062                                    browser_->tab_strip_model());
2063  tabstrip_ = new TabStrip(tabstrip_controller);
2064  top_container_->AddChildView(tabstrip_);
2065  tabstrip_controller->InitFromModel(tabstrip_);
2066
2067  toolbar_ = new ToolbarView(browser_.get());
2068  top_container_->AddChildView(toolbar_);
2069  toolbar_->Init();
2070
2071  // Create do-nothing view for the sake of controlling the z-order of the find
2072  // bar widget.
2073  find_bar_host_view_ = new View();
2074  AddChildView(find_bar_host_view_);
2075
2076  overlay_container_ =
2077      new OverlayContainer(this, immersive_mode_controller_.get());
2078  overlay_container_->SetVisible(false);
2079  AddChildView(overlay_container_);
2080
2081  overlay_controller_.reset(
2082      new InstantOverlayControllerViews(browser(), overlay_container_));
2083
2084  immersive_mode_controller_->Init(this, GetWidget(), top_container_);
2085
2086  BrowserViewLayout* browser_view_layout = new BrowserViewLayout;
2087  browser_view_layout->Init(new BrowserViewLayoutDelegateImpl(this),
2088                            browser(),
2089                            this,
2090                            top_container_,
2091                            tabstrip_,
2092                            toolbar_,
2093                            infobar_container_,
2094                            contents_split_,
2095                            contents_container_,
2096                            overlay_container_,
2097                            immersive_mode_controller_.get());
2098  SetLayoutManager(browser_view_layout);
2099
2100#if defined(OS_WIN) && !defined(USE_AURA)
2101  // Create a custom JumpList and add it to an observer of TabRestoreService
2102  // so we can update the custom JumpList when a tab is added or removed.
2103  if (JumpList::Enabled()) {
2104    load_complete_listener_.reset(new LoadCompleteListener(this));
2105  }
2106#endif
2107
2108  // We're now initialized and ready to process Layout requests.
2109  ignore_layout_ = false;
2110}
2111
2112void BrowserView::LoadingAnimationCallback() {
2113  base::TimeTicks now = base::TimeTicks::Now();
2114  if (!last_animation_time_.is_null()) {
2115    UMA_HISTOGRAM_TIMES(
2116        "Tabs.LoadingAnimationTime",
2117        now - last_animation_time_);
2118  }
2119  last_animation_time_ = now;
2120  if (browser_->is_type_tabbed()) {
2121    // Loading animations are shown in the tab for tabbed windows.  We check the
2122    // browser type instead of calling IsTabStripVisible() because the latter
2123    // will return false for fullscreen windows, but we still need to update
2124    // their animations (so that when they come out of fullscreen mode they'll
2125    // be correct).
2126    tabstrip_->UpdateLoadingAnimations();
2127  } else if (ShouldShowWindowIcon()) {
2128    // ... or in the window icon area for popups and app windows.
2129    WebContents* web_contents =
2130        browser_->tab_strip_model()->GetActiveWebContents();
2131    // GetActiveWebContents can return NULL for example under Purify when
2132    // the animations are running slowly and this function is called on a timer
2133    // through LoadingAnimationCallback.
2134    frame_->UpdateThrobber(web_contents && web_contents->IsLoading());
2135  }
2136}
2137
2138void BrowserView::OnLoadCompleted() {
2139#if defined(OS_WIN) && !defined(USE_AURA)
2140  DCHECK(!jumplist_);
2141  jumplist_ = new JumpList();
2142  jumplist_->AddObserver(browser_->profile());
2143#endif
2144}
2145
2146BrowserViewLayout* BrowserView::GetBrowserViewLayout() const {
2147  return static_cast<BrowserViewLayout*>(GetLayoutManager());
2148}
2149
2150void BrowserView::LayoutStatusBubble() {
2151  // In restored mode, the client area has a client edge between it and the
2152  // frame.
2153  int overlap = StatusBubbleViews::kShadowThickness;
2154  // The extra pixels defined by kClientEdgeThickness is only drawn in frame
2155  // content border on windows for non-aura build.
2156#if !defined(USE_ASH)
2157  overlap +=
2158      IsMaximized() ? 0 : views::NonClientFrameView::kClientEdgeThickness;
2159#endif
2160  int height = status_bubble_->GetPreferredSize().height();
2161  int contents_height = status_bubble_->base_view()->bounds().height();
2162  gfx::Point origin(-overlap, contents_height - height + overlap);
2163  status_bubble_->SetBounds(origin.x(), origin.y(), width() / 3, height);
2164}
2165
2166bool BrowserView::MaybeShowBookmarkBar(WebContents* contents) {
2167  bool show_bookmark_bar = contents &&
2168      browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR);
2169  if (!show_bookmark_bar && !bookmark_bar_view_.get())
2170    return false;
2171  if (!bookmark_bar_view_.get()) {
2172    bookmark_bar_view_.reset(new BookmarkBarView(browser_.get(), this));
2173    bookmark_bar_view_->set_owned_by_client();
2174    bookmark_bar_view_->set_background(
2175        new BookmarkExtensionBackground(this,
2176                                        bookmark_bar_view_.get(),
2177                                        browser_.get()));
2178    bookmark_bar_view_->SetBookmarkBarState(
2179        browser_->bookmark_bar_state(),
2180        BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
2181    GetBrowserViewLayout()->set_bookmark_bar(bookmark_bar_view_.get());
2182  }
2183  bookmark_bar_view_->SetVisible(show_bookmark_bar);
2184  bookmark_bar_view_->SetPageNavigator(contents);
2185
2186  // Update parenting for the bookmark bar. This may detach it from all views.
2187  bool needs_layout = false;
2188  views::View* new_parent = NULL;
2189  if (show_bookmark_bar) {
2190    if (bookmark_bar_view_->IsDetached())
2191      new_parent = this;
2192    else
2193      new_parent = top_container_;
2194  }
2195  if (new_parent != bookmark_bar_view_->parent()) {
2196    SetBookmarkBarParent(new_parent);
2197    needs_layout = true;
2198  }
2199
2200  // Check for updates to the desired size.
2201  if (bookmark_bar_view_->GetPreferredSize().height() !=
2202      bookmark_bar_view_->height())
2203    needs_layout = true;
2204
2205  return needs_layout;
2206}
2207
2208void BrowserView::SetBookmarkBarParent(views::View* new_parent) {
2209  if (new_parent == this) {
2210    // Add it underneath |top_container_| or at the end if top container isn't
2211    // found.
2212    int top_container_index = GetIndexOf(top_container_);
2213    if (top_container_index >= 0)
2214      AddChildViewAt(bookmark_bar_view_.get(), top_container_index);
2215    else
2216      AddChildView(bookmark_bar_view_.get());
2217  } else if (new_parent) {
2218    // No special stacking is required for other parents.
2219    new_parent->AddChildView(bookmark_bar_view_.get());
2220  } else {
2221    // Bookmark bar is being detached from all views because it is hidden.
2222    bookmark_bar_view_->parent()->RemoveChildView(bookmark_bar_view_.get());
2223  }
2224}
2225
2226bool BrowserView::MaybeShowInfoBar(WebContents* contents) {
2227  // TODO(beng): Remove this function once the interface between
2228  //             InfoBarContainer, DownloadShelfView and WebContents and this
2229  //             view is sorted out.
2230  return true;
2231}
2232
2233void BrowserView::UpdateDevToolsForContents(WebContents* web_contents) {
2234  DevToolsWindow* new_devtools_window = web_contents ?
2235      DevToolsWindow::GetDockedInstanceForInspectedTab(web_contents) : NULL;
2236  // Fast return in case of the same window having same orientation.
2237  if (devtools_window_ == new_devtools_window) {
2238    if (!new_devtools_window ||
2239        (new_devtools_window->dock_side() == devtools_dock_side_)) {
2240      return;
2241    }
2242  }
2243
2244  // Replace tab contents.
2245  if (devtools_window_ != new_devtools_window) {
2246    devtools_container_->SetWebContents(
2247        new_devtools_window ? new_devtools_window->web_contents() : NULL);
2248  }
2249
2250  // Store last used position.
2251  if (devtools_window_) {
2252    int split_size = contents_split_->GetDividerSize();
2253    if (devtools_dock_side_ == DEVTOOLS_DOCK_SIDE_RIGHT) {
2254      devtools_window_->SetWidth(contents_split_->width() -
2255          split_size - contents_split_->divider_offset());
2256    } else if (devtools_dock_side_ == DEVTOOLS_DOCK_SIDE_BOTTOM) {
2257      devtools_window_->SetHeight(contents_split_->height() -
2258          split_size - contents_split_->divider_offset());
2259    }
2260  }
2261
2262  // Show / hide container if necessary. Changing dock orientation is
2263  // hide + show.
2264  bool should_hide = devtools_window_ && (!new_devtools_window ||
2265      devtools_dock_side_ != new_devtools_window->dock_side());
2266  bool should_show = new_devtools_window && (!devtools_window_ || should_hide);
2267
2268  if (should_hide)
2269    HideDevToolsContainer();
2270
2271  devtools_window_ = new_devtools_window;
2272
2273  if (should_show) {
2274    devtools_dock_side_ = new_devtools_window->dock_side();
2275    ShowDevToolsContainer();
2276  } else if (new_devtools_window) {
2277    UpdateDevToolsSplitPosition();
2278    contents_split_->Layout();
2279  }
2280}
2281
2282void BrowserView::ShowDevToolsContainer() {
2283  if (!devtools_focus_tracker_.get()) {
2284    // Install devtools focus tracker when dev tools window is shown for the
2285    // first time.
2286    devtools_focus_tracker_.reset(
2287        new views::ExternalFocusTracker(devtools_container_,
2288                                        GetFocusManager()));
2289  }
2290
2291  gfx::Size min_devtools_size(devtools_window_->GetMinimumWidth(),
2292      devtools_window_->GetMinimumHeight());
2293  devtools_container_->SetPreferredSize(min_devtools_size);
2294
2295  devtools_container_->SetVisible(true);
2296  devtools_dock_side_ = devtools_window_->dock_side();
2297  bool dock_to_right = devtools_dock_side_ == DEVTOOLS_DOCK_SIDE_RIGHT;
2298  contents_split_->set_orientation(
2299      dock_to_right ? views::SingleSplitView::HORIZONTAL_SPLIT
2300                    : views::SingleSplitView::VERTICAL_SPLIT);
2301  UpdateDevToolsSplitPosition();
2302  contents_split_->InvalidateLayout();
2303  Layout();
2304}
2305
2306void BrowserView::HideDevToolsContainer() {
2307  // Restore focus to the last focused view when hiding devtools window.
2308  devtools_focus_tracker_->FocusLastFocusedExternalView();
2309  devtools_container_->SetVisible(false);
2310  contents_split_->InvalidateLayout();
2311  Layout();
2312}
2313
2314void BrowserView::UpdateDevToolsSplitPosition() {
2315  contents_split_->set_resize_disabled(
2316      devtools_window_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED);
2317  int split_size = contents_split_->GetDividerSize();
2318  if (devtools_window_->dock_side() == DEVTOOLS_DOCK_SIDE_RIGHT) {
2319    int split_offset = contents_split_->width() - split_size -
2320        devtools_window_->GetWidth(contents_split_->width());
2321    contents_split_->set_divider_offset(split_offset);
2322  } else {
2323    int height = devtools_window_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED ?
2324        devtools_window_->GetMinimizedHeight() :
2325        devtools_window_->GetHeight(contents_split_->height());
2326    int split_offset = contents_split_->height() - split_size - height;
2327    contents_split_->set_divider_offset(split_offset);
2328  }
2329}
2330
2331void BrowserView::UpdateUIForContents(WebContents* contents) {
2332  bool needs_layout = MaybeShowBookmarkBar(contents);
2333  // TODO(jamescook): This function always returns true. Remove it and figure
2334  // out when layout is actually required.
2335  needs_layout |= MaybeShowInfoBar(contents);
2336  if (needs_layout)
2337    Layout();
2338}
2339
2340void BrowserView::ProcessFullscreen(bool fullscreen,
2341                                    FullscreenType type,
2342                                    const GURL& url,
2343                                    FullscreenExitBubbleType bubble_type) {
2344  // Reduce jankiness during the following position changes by:
2345  //   * Hiding the window until it's in the final position
2346  //   * Ignoring all intervening Layout() calls, which resize the webpage and
2347  //     thus are slow and look ugly
2348  ignore_layout_ = true;
2349  LocationBarView* location_bar = GetLocationBarView();
2350#if defined(OS_WIN) && !defined(USE_AURA)
2351  OmniboxViewWin* omnibox_win =
2352      GetOmniboxViewWin(location_bar->GetLocationEntry());
2353#endif
2354
2355  if (type == FOR_METRO || !fullscreen) {
2356    // Hide the fullscreen bubble as soon as possible, since the mode toggle can
2357    // take enough time for the user to notice.
2358    fullscreen_bubble_.reset();
2359  }
2360
2361  if (fullscreen) {
2362    // Move focus out of the location bar if necessary.
2363    views::FocusManager* focus_manager = GetFocusManager();
2364    DCHECK(focus_manager);
2365    // Look for focus in the location bar itself or any child view.
2366    if (location_bar->Contains(focus_manager->GetFocusedView()))
2367      focus_manager->ClearFocus();
2368
2369#if defined(OS_WIN) && !defined(USE_AURA)
2370    if (omnibox_win) {
2371      // If we don't hide the edit and force it to not show until we come out of
2372      // fullscreen, then if the user was on the New Tab Page, the edit contents
2373      // will appear atop the web contents once we go into fullscreen mode. This
2374      // has something to do with how we move the main window while it's hidden;
2375      // if we don't hide the main window below, we don't get this problem.
2376      omnibox_win->set_force_hidden(true);
2377      ShowWindow(omnibox_win->m_hWnd, SW_HIDE);
2378    }
2379#endif
2380  }
2381#if defined(OS_WIN) && !defined(USE_AURA)
2382  views::ScopedFullscreenVisibility visibility(frame_->GetNativeView());
2383#endif
2384
2385  if (type == FOR_METRO) {
2386#if defined(OS_WIN) && !defined(USE_AURA)
2387    // Enter metro snap mode.
2388    static_cast<views::NativeWidgetWin*>(
2389        frame_->native_widget())->SetMetroSnapFullscreen(fullscreen);
2390#endif
2391  } else {
2392    // Toggle fullscreen mode.
2393    frame_->SetFullscreen(fullscreen);
2394  }
2395
2396  // Enable immersive before the browser refreshes its list of enabled commands.
2397  if (UseImmersiveFullscreenForUrl(url))
2398    immersive_mode_controller_->SetEnabled(fullscreen);
2399
2400  browser_->WindowFullscreenStateChanged();
2401
2402  if (fullscreen) {
2403    if (!chrome::IsRunningInAppMode() &&
2404        type != FOR_METRO &&
2405        !UseImmersiveFullscreenForUrl(url)) {
2406      fullscreen_bubble_.reset(new FullscreenExitBubbleViews(
2407          this, url, bubble_type));
2408    }
2409  } else {
2410#if defined(OS_WIN) && !defined(USE_AURA)
2411    if (omnibox_win) {
2412      // Show the edit again since we're no longer in fullscreen mode.
2413      omnibox_win->set_force_hidden(false);
2414      ShowWindow(omnibox_win->m_hWnd, SW_SHOW);
2415    }
2416#endif
2417  }
2418
2419  // Undo our anti-jankiness hacks and force a re-layout. We also need to
2420  // recompute the height of the infobar top arrow because toggling in and out
2421  // of fullscreen changes it. Calling ToolbarSizeChanged() will do both these
2422  // things since it computes the arrow height directly and forces a layout
2423  // indirectly via UpdateUIForContents().
2424  ignore_layout_ = false;
2425  ToolbarSizeChanged(false);
2426}
2427
2428void BrowserView::LoadAccelerators() {
2429#if defined(OS_WIN) && !defined(USE_AURA)
2430  HACCEL accelerator_table = AtlLoadAccelerators(IDR_MAINFRAME);
2431  DCHECK(accelerator_table);
2432
2433  // We have to copy the table to access its contents.
2434  int count = CopyAcceleratorTable(accelerator_table, 0, 0);
2435  if (count == 0) {
2436    // Nothing to do in that case.
2437    return;
2438  }
2439
2440  ACCEL* accelerators = static_cast<ACCEL*>(malloc(sizeof(ACCEL) * count));
2441  CopyAcceleratorTable(accelerator_table, accelerators, count);
2442
2443  views::FocusManager* focus_manager = GetFocusManager();
2444  DCHECK(focus_manager);
2445
2446  // Let's fill our own accelerator table.
2447  for (int i = 0; i < count; ++i) {
2448    ui::Accelerator accelerator(
2449        static_cast<ui::KeyboardCode>(accelerators[i].key),
2450        ui::GetModifiersFromACCEL(accelerators[i]));
2451    accelerator_table_[accelerator] = accelerators[i].cmd;
2452
2453    // Also register with the focus manager.
2454    focus_manager->RegisterAccelerator(
2455        accelerator, ui::AcceleratorManager::kNormalPriority, this);
2456  }
2457
2458  // We don't need the Windows accelerator table anymore.
2459  free(accelerators);
2460#else
2461  views::FocusManager* focus_manager = GetFocusManager();
2462  DCHECK(focus_manager);
2463
2464  // Let's fill our own accelerator table.
2465  const bool is_app_mode = chrome::IsRunningInForcedAppMode();
2466  const std::vector<chrome::AcceleratorMapping> accelerator_list(
2467      chrome::GetAcceleratorList());
2468  for (std::vector<chrome::AcceleratorMapping>::const_iterator it =
2469           accelerator_list.begin(); it != accelerator_list.end(); ++it) {
2470    // In app mode, only allow accelerators of white listed commands to pass
2471    // through.
2472    if (is_app_mode && !chrome::IsCommandAllowedInAppMode(it->command_id))
2473      continue;
2474
2475    ui::Accelerator accelerator(it->keycode, it->modifiers);
2476    accelerator_table_[accelerator] = it->command_id;
2477
2478    // Also register with the focus manager.
2479    focus_manager->RegisterAccelerator(
2480        accelerator, ui::AcceleratorManager::kNormalPriority, this);
2481  }
2482#endif
2483}
2484
2485int BrowserView::GetCommandIDForAppCommandID(int app_command_id) const {
2486#if defined(OS_WIN)
2487  switch (app_command_id) {
2488    // NOTE: The order here matches the APPCOMMAND declaration order in the
2489    // Windows headers.
2490    case APPCOMMAND_BROWSER_BACKWARD: return IDC_BACK;
2491    case APPCOMMAND_BROWSER_FORWARD:  return IDC_FORWARD;
2492    case APPCOMMAND_BROWSER_REFRESH:  return IDC_RELOAD;
2493    case APPCOMMAND_BROWSER_HOME:     return IDC_HOME;
2494    case APPCOMMAND_BROWSER_STOP:     return IDC_STOP;
2495    case APPCOMMAND_BROWSER_SEARCH:   return IDC_FOCUS_SEARCH;
2496    case APPCOMMAND_HELP:             return IDC_HELP_PAGE_VIA_KEYBOARD;
2497    case APPCOMMAND_NEW:              return IDC_NEW_TAB;
2498    case APPCOMMAND_OPEN:             return IDC_OPEN_FILE;
2499    case APPCOMMAND_CLOSE:            return IDC_CLOSE_TAB;
2500    case APPCOMMAND_SAVE:             return IDC_SAVE_PAGE;
2501    case APPCOMMAND_PRINT:            return IDC_PRINT;
2502    case APPCOMMAND_COPY:             return IDC_COPY;
2503    case APPCOMMAND_CUT:              return IDC_CUT;
2504    case APPCOMMAND_PASTE:            return IDC_PASTE;
2505
2506      // TODO(pkasting): http://b/1113069 Handle these.
2507    case APPCOMMAND_UNDO:
2508    case APPCOMMAND_REDO:
2509    case APPCOMMAND_SPELL_CHECK:
2510    default:                          return -1;
2511  }
2512#else
2513  // App commands are Windows-specific so there's nothing to do here.
2514  return -1;
2515#endif
2516}
2517
2518void BrowserView::InitHangMonitor() {
2519#if defined(OS_WIN) && !defined(USE_AURA)
2520  PrefService* pref_service = g_browser_process->local_state();
2521  if (!pref_service)
2522    return;
2523
2524  int plugin_message_response_timeout =
2525      pref_service->GetInteger(prefs::kPluginMessageResponseTimeout);
2526  int hung_plugin_detect_freq =
2527      pref_service->GetInteger(prefs::kHungPluginDetectFrequency);
2528  if ((hung_plugin_detect_freq > 0) &&
2529      hung_window_detector_.Initialize(GetWidget()->GetNativeView(),
2530                                       plugin_message_response_timeout)) {
2531    ticker_.set_tick_interval(hung_plugin_detect_freq);
2532    ticker_.RegisterTickHandler(&hung_window_detector_);
2533    ticker_.Start();
2534
2535    pref_service->SetInteger(prefs::kPluginMessageResponseTimeout,
2536                             plugin_message_response_timeout);
2537    pref_service->SetInteger(prefs::kHungPluginDetectFrequency,
2538                             hung_plugin_detect_freq);
2539  }
2540#endif
2541}
2542
2543void BrowserView::UpdateAcceleratorMetrics(
2544    const ui::Accelerator& accelerator, int command_id) {
2545  const ui::KeyboardCode key_code = accelerator.key_code();
2546  if (command_id == IDC_HELP_PAGE_VIA_KEYBOARD && key_code == ui::VKEY_F1)
2547    content::RecordAction(UserMetricsAction("ShowHelpTabViaF1"));
2548
2549  if (command_id == IDC_BOOKMARK_PAGE)
2550    UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint",
2551                              bookmark_utils::ENTRY_POINT_ACCELERATOR,
2552                              bookmark_utils::ENTRY_POINT_LIMIT);
2553
2554#if defined(OS_CHROMEOS)
2555  // Collect information about the relative popularity of various accelerators
2556  // on Chrome OS.
2557  switch (command_id) {
2558    case IDC_BACK:
2559      if (key_code == ui::VKEY_BACK)
2560        content::RecordAction(UserMetricsAction("Accel_Back_Backspace"));
2561      else if (key_code == ui::VKEY_BROWSER_BACK)
2562        content::RecordAction(UserMetricsAction("Accel_Back_F1"));
2563      else if (key_code == ui::VKEY_LEFT)
2564        content::RecordAction(UserMetricsAction("Accel_Back_Left"));
2565      break;
2566    case IDC_FORWARD:
2567      if (key_code == ui::VKEY_BACK)
2568        content::RecordAction(UserMetricsAction("Accel_Forward_Backspace"));
2569      else if (key_code == ui::VKEY_BROWSER_FORWARD)
2570        content::RecordAction(UserMetricsAction("Accel_Forward_F2"));
2571      else if (key_code == ui::VKEY_RIGHT)
2572        content::RecordAction(UserMetricsAction("Accel_Forward_Right"));
2573      break;
2574    case IDC_RELOAD:
2575    case IDC_RELOAD_IGNORING_CACHE:
2576      if (key_code == ui::VKEY_R)
2577        content::RecordAction(UserMetricsAction("Accel_Reload_R"));
2578      else if (key_code == ui::VKEY_BROWSER_REFRESH)
2579        content::RecordAction(UserMetricsAction("Accel_Reload_F3"));
2580      break;
2581    case IDC_FOCUS_LOCATION:
2582      if (key_code == ui::VKEY_D)
2583        content::RecordAction(UserMetricsAction("Accel_FocusLocation_D"));
2584      else if (key_code == ui::VKEY_L)
2585        content::RecordAction(UserMetricsAction("Accel_FocusLocation_L"));
2586      break;
2587    case IDC_FOCUS_SEARCH:
2588      if (key_code == ui::VKEY_E)
2589        content::RecordAction(UserMetricsAction("Accel_FocusSearch_E"));
2590      else if (key_code == ui::VKEY_K)
2591        content::RecordAction(UserMetricsAction("Accel_FocusSearch_K"));
2592      break;
2593    default:
2594      // Do nothing.
2595      break;
2596  }
2597#endif
2598}
2599
2600void BrowserView::CreateLauncherIcon() {
2601#if defined(USE_ASH)
2602  if (chrome::IsNativeWindowInAsh(GetNativeWindow()) &&
2603      !launcher_item_controller_.get()) {
2604    launcher_item_controller_.reset(
2605        BrowserLauncherItemController::Create(browser_.get()));
2606  }
2607#endif  // defined(USE_ASH)
2608}
2609
2610// static
2611BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
2612  // Create the view and the frame. The frame will attach itself via the view
2613  // so we don't need to do anything with the pointer.
2614  BrowserView* view = new BrowserView();
2615  view->Init(browser);
2616  (new BrowserFrame(view))->InitBrowserFrame();
2617  view->GetWidget()->non_client_view()->SetAccessibleName(
2618      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
2619  return view;
2620}
2621
2622void BrowserView::ShowAvatarBubble(WebContents* web_contents,
2623                                   const gfx::Rect& rect) {
2624  gfx::Point origin(rect.origin());
2625  views::View::ConvertPointToScreen(GetTabContentsContainerView(), &origin);
2626  gfx::Rect bounds(origin, rect.size());
2627
2628  AvatarMenuBubbleView::ShowBubble(this, views::BubbleBorder::TOP_RIGHT,
2629      views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE, bounds, browser_.get());
2630}
2631
2632void BrowserView::ShowAvatarBubbleFromAvatarButton() {
2633  AvatarMenuButton* button = frame_->GetAvatarMenuButton();
2634  if (button)
2635    button->ShowAvatarBubble();
2636}
2637
2638void BrowserView::ShowPasswordGenerationBubble(
2639    const gfx::Rect& rect,
2640    const content::PasswordForm& form,
2641    autofill::PasswordGenerator* password_generator) {
2642  // Create a rect in the content bounds that the bubble will point to.
2643  gfx::Point origin(rect.origin());
2644  views::View::ConvertPointToScreen(GetTabContentsContainerView(), &origin);
2645  gfx::Rect bounds(origin, rect.size());
2646
2647  // Create the bubble.
2648  WebContents* web_contents = GetActiveWebContents();
2649  if (!web_contents)
2650    return;
2651
2652  PasswordGenerationBubbleView* bubble =
2653      new PasswordGenerationBubbleView(
2654          form,
2655          bounds,
2656          this,
2657          web_contents->GetRenderViewHost(),
2658          PasswordManager::FromWebContents(web_contents),
2659          password_generator,
2660          browser_.get(),
2661          GetWidget()->GetThemeProvider());
2662
2663  views::BubbleDelegateView::CreateBubble(bubble);
2664  bubble->SetAlignment(views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR);
2665  bubble->GetWidget()->Show();
2666}
2667
2668void BrowserView::DoCutCopyPaste(void (content::RenderWidgetHost::*method)(),
2669#if defined(OS_WIN)
2670                                 int windows_msg_id,
2671#endif
2672                                 int command_id) {
2673  WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents();
2674  if (!contents)
2675    return;
2676  if (DoCutCopyPasteForWebContents(contents, method))
2677    return;
2678
2679  DevToolsWindow* devtools_window =
2680      DevToolsWindow::GetDockedInstanceForInspectedTab(contents);
2681  if (devtools_window &&
2682      DoCutCopyPasteForWebContents(devtools_window->web_contents(), method)) {
2683    return;
2684  }
2685
2686  views::FocusManager* focus_manager = GetFocusManager();
2687  views::View* focused = focus_manager->GetFocusedView();
2688  if (focused &&
2689      (!strcmp(focused->GetClassName(), views::Textfield::kViewClassName) ||
2690       !strcmp(focused->GetClassName(), OmniboxViewViews::kViewClassName))) {
2691    views::Textfield* textfield = static_cast<views::Textfield*>(focused);
2692    textfield->ExecuteCommand(command_id);
2693    return;
2694  }
2695
2696#if defined(OS_WIN) && !defined(USE_AURA)
2697  OmniboxView* omnibox_view = GetLocationBarView()->GetLocationEntry();
2698  if (omnibox_view->model()->has_focus()) {
2699    OmniboxViewWin* omnibox_win = GetOmniboxViewWin(omnibox_view);
2700    ::SendMessage(omnibox_win->GetNativeView(), windows_msg_id, 0, 0);
2701  }
2702#endif
2703}
2704
2705bool BrowserView::DoCutCopyPasteForWebContents(
2706    WebContents* contents,
2707    void (content::RenderWidgetHost::*method)()) {
2708  gfx::NativeView native_view = contents->GetView()->GetContentNativeView();
2709  if (!native_view)
2710    return false;
2711#if defined(USE_AURA)
2712  if (native_view->HasFocus()) {
2713#elif defined(OS_WIN)
2714  if (native_view == ::GetFocus()) {
2715#endif
2716    (contents->GetRenderViewHost()->*method)();
2717    return true;
2718  }
2719
2720  return false;
2721}
2722
2723void BrowserView::ActivateAppModalDialog() const {
2724  // If another browser is app modal, flash and activate the modal browser.
2725  AppModalDialog* active_dialog =
2726      AppModalDialogQueue::GetInstance()->active_dialog();
2727  if (!active_dialog)
2728    return;
2729
2730  Browser* modal_browser =
2731      chrome::FindBrowserWithWebContents(active_dialog->web_contents());
2732  if (modal_browser && (browser_ != modal_browser)) {
2733    modal_browser->window()->FlashFrame(true);
2734    modal_browser->window()->Activate();
2735  }
2736
2737  AppModalDialogQueue::GetInstance()->ActivateModalDialog();
2738}
2739
2740void BrowserView::MakeOverlayContentsActiveContents() {
2741  views::WebView* overlay = overlay_controller_->overlay();
2742  DCHECK_EQ(overlay_container_, overlay->parent());
2743  overlay_container_->ResetOverlayAndContents();
2744
2745  // |overlay|'s current parent is |OverlayContainer|, and will be reparented
2746  // to |ContentsContainer|.  |overlay|'s height is either same as
2747  // |contents_web_view_| or taller when it appears over the attached bookmark
2748  // and/or info bars.  The latter means it's also taller than the parent's
2749  // height since |contents_web_view_|'s max height is the parent's height.
2750  // Reparenting this taller overlay will force a clip to be installed on it;
2751  // on ChromeOS, this results in a call into not-implemented
2752  // views::NativeViewHostAura::InstallClip().  So set the bounds of |overlay|
2753  // to same as |contents_web_view_| before reparenting.
2754  // Note:
2755  // - |overlay|'s origin is not (0,0), so just resizing it without changing the
2756  //   origin may still result in the undesired clipping
2757  // - there won't be extra repositioning or resizing of |overlay| since its new
2758  //   bounds will be unchanged in ContentsContainer::Layout().
2759  if (overlay->bounds().bottom() > contents_container_->height())
2760    overlay->SetBoundsRect(contents_web_view_->bounds());
2761  contents_container_->AddChildView(overlay);
2762  contents_container_->SetActive(overlay);
2763
2764  // Overlay is gone, force re-layout of |BrowserView| and infobars.
2765  OnOverlayStateChanged(true);
2766}
2767
2768int BrowserView::GetMaxTopInfoBarArrowHeight() {
2769  int top_arrow_height = 0;
2770  // Only show the arrows when not in fullscreen and when there's no overlay.
2771  if (!IsFullscreen() && !overlay_container_->visible()) {
2772    const LocationIconView* location_icon_view =
2773        toolbar_->location_bar()->location_icon_view();
2774    // The +1 in the next line creates a 1-px gap between icon and arrow tip.
2775    gfx::Point icon_bottom(0, location_icon_view->GetImageBounds().bottom() -
2776        LocationBarView::kIconInternalPadding + 1);
2777    ConvertPointToTarget(location_icon_view, this, &icon_bottom);
2778    gfx::Point infobar_top(0, infobar_container_->GetVerticalOverlap(NULL));
2779    ConvertPointToTarget(infobar_container_, this, &infobar_top);
2780    top_arrow_height = infobar_top.y() - icon_bottom.y();
2781  }
2782  return top_arrow_height;
2783}
2784