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