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