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