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