1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/browser.h" 6 7#if defined(OS_WIN) 8#include <shellapi.h> 9#include <windows.h> 10#endif // OS_WIN 11 12#include <algorithm> 13#include <string> 14 15#include "base/base_paths.h" 16#include "base/command_line.h" 17#include "base/logging.h" 18#include "base/metrics/histogram.h" 19#include "base/path_service.h" 20#include "base/string_util.h" 21#include "base/threading/thread.h" 22#include "base/threading/thread_restrictions.h" 23#include "base/time.h" 24#include "base/utf_string_conversions.h" 25#include "chrome/app/chrome_command_ids.h" 26#include "chrome/browser/autofill/autofill_manager.h" 27#include "chrome/browser/background_contents_service.h" 28#include "chrome/browser/bookmarks/bookmark_model.h" 29#include "chrome/browser/bookmarks/bookmark_utils.h" 30#include "chrome/browser/browser_process.h" 31#include "chrome/browser/browser_shutdown.h" 32#include "chrome/browser/browser_url_handler.h" 33#include "chrome/browser/character_encoding.h" 34#include "chrome/browser/debugger/devtools_manager.h" 35#include "chrome/browser/debugger/devtools_toggle_action.h" 36#include "chrome/browser/debugger/devtools_window.h" 37#include "chrome/browser/download/download_item.h" 38#include "chrome/browser/download/download_item_model.h" 39#include "chrome/browser/download/download_manager.h" 40#include "chrome/browser/download/download_shelf.h" 41#include "chrome/browser/download/download_started_animation.h" 42#include "chrome/browser/download/save_package.h" 43#include "chrome/browser/extensions/crx_installer.h" 44#include "chrome/browser/extensions/extension_browser_event_router.h" 45#include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" 46#include "chrome/browser/extensions/extension_host.h" 47#include "chrome/browser/extensions/extension_prefs.h" 48#include "chrome/browser/extensions/extension_service.h" 49#include "chrome/browser/extensions/extension_tab_helper.h" 50#include "chrome/browser/extensions/extension_tabs_module.h" 51#include "chrome/browser/first_run/first_run.h" 52#include "chrome/browser/google/google_url_tracker.h" 53#include "chrome/browser/google/google_util.h" 54#include "chrome/browser/instant/instant_controller.h" 55#include "chrome/browser/instant/instant_unload_handler.h" 56#include "chrome/browser/metrics/user_metrics.h" 57#include "chrome/browser/net/browser_url_util.h" 58#include "chrome/browser/net/url_fixer_upper.h" 59#include "chrome/browser/notifications/notification_ui_manager.h" 60#include "chrome/browser/platform_util.h" 61#include "chrome/browser/prefs/pref_service.h" 62#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h" 63#include "chrome/browser/printing/print_preview_tab_controller.h" 64#include "chrome/browser/profiles/profile.h" 65#include "chrome/browser/sessions/session_service.h" 66#include "chrome/browser/sessions/session_types.h" 67#include "chrome/browser/sessions/tab_restore_service.h" 68#include "chrome/browser/sync/profile_sync_service.h" 69#include "chrome/browser/sync/sync_ui_util.h" 70#include "chrome/browser/tab_closeable_state_watcher.h" 71#include "chrome/browser/tab_contents/background_contents.h" 72#include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h" 73#include "chrome/browser/tabs/tab_finder.h" 74#include "chrome/browser/tabs/tab_strip_model.h" 75#include "chrome/browser/ui/browser_list.h" 76#include "chrome/browser/ui/browser_tab_restore_service_delegate.h" 77#include "chrome/browser/ui/browser_window.h" 78#include "chrome/browser/ui/download/download_tab_helper.h" 79#include "chrome/browser/ui/find_bar/find_bar.h" 80#include "chrome/browser/ui/find_bar/find_bar_controller.h" 81#include "chrome/browser/ui/find_bar/find_tab_helper.h" 82#include "chrome/browser/ui/omnibox/location_bar.h" 83#include "chrome/browser/ui/options/options_window.h" 84#include "chrome/browser/ui/panels/panel.h" 85#include "chrome/browser/ui/panels/panel_manager.h" 86#include "chrome/browser/ui/search_engines/search_engine_tab_helper.h" 87#include "chrome/browser/ui/status_bubble.h" 88#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 89#include "chrome/browser/ui/tabs/dock_info.h" 90#include "chrome/browser/ui/tabs/tab_menu_model.h" 91#include "chrome/browser/ui/web_applications/web_app_ui.h" 92#include "chrome/browser/ui/webui/active_downloads_ui.h" 93#include "chrome/browser/ui/webui/bug_report_ui.h" 94#include "chrome/browser/ui/webui/options/content_settings_handler.h" 95#include "chrome/browser/ui/window_sizer.h" 96#include "chrome/browser/upgrade_detector.h" 97#include "chrome/browser/web_applications/web_app.h" 98#include "chrome/common/chrome_constants.h" 99#include "chrome/common/chrome_switches.h" 100#include "chrome/common/content_restriction.h" 101#include "chrome/common/extensions/extension.h" 102#include "chrome/common/extensions/extension_constants.h" 103#include "chrome/common/pref_names.h" 104#include "chrome/common/profiling.h" 105#include "chrome/common/url_constants.h" 106#include "chrome/common/web_apps.h" 107#include "content/browser/host_zoom_map.h" 108#include "content/browser/renderer_host/render_view_host.h" 109#include "content/browser/site_instance.h" 110#include "content/browser/tab_contents/interstitial_page.h" 111#include "content/browser/tab_contents/navigation_controller.h" 112#include "content/browser/tab_contents/navigation_entry.h" 113#include "content/browser/tab_contents/tab_contents.h" 114#include "content/browser/tab_contents/tab_contents_view.h" 115#include "content/common/notification_service.h" 116#include "content/common/page_transition_types.h" 117#include "grit/chromium_strings.h" 118#include "grit/generated_resources.h" 119#include "grit/locale_settings.h" 120#include "net/base/cookie_monster.h" 121#include "net/base/net_util.h" 122#include "net/base/registry_controlled_domain.h" 123#include "net/base/static_cookie_policy.h" 124#include "net/url_request/url_request_context.h" 125#include "ui/base/animation/animation.h" 126#include "ui/base/l10n/l10n_util.h" 127#include "ui/gfx/point.h" 128#include "webkit/glue/webkit_glue.h" 129#include "webkit/glue/window_open_disposition.h" 130 131#if defined(OS_WIN) 132#include "app/win/shell.h" 133#include "chrome/browser/autofill/autofill_ie_toolbar_import_win.h" 134#include "chrome/browser/shell_integration.h" 135#include "chrome/browser/ssl/ssl_error_info.h" 136#include "chrome/browser/task_manager/task_manager.h" 137#include "chrome/browser/ui/view_ids.h" 138#include "chrome/browser/ui/views/location_bar/location_bar_view.h" 139#endif // OS_WIN 140 141#if defined(OS_MACOSX) 142#include "chrome/browser/ui/cocoa/find_pasteboard.h" 143#endif 144 145#if defined(OS_CHROMEOS) 146#include "chrome/browser/chromeos/boot_times_loader.h" 147#include "chrome/browser/extensions/file_manager_util.h" 148#endif 149 150using base::TimeDelta; 151 152/////////////////////////////////////////////////////////////////////////////// 153 154namespace { 155 156// The URL to be loaded to display Help. 157const char kHelpContentUrl[] = 158#if defined(OS_CHROMEOS) 159 #if defined(OFFICIAL_BUILD) 160 "chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html"; 161 #else 162 "https://www.google.com/support/chromeos/"; 163 #endif 164#else 165 "https://www.google.com/support/chrome/"; 166#endif 167 168// The URL to be opened when the Help link on the Autofill dialog is clicked. 169const char kAutofillHelpUrl[] = 170#if defined(OS_CHROMEOS) 171 "https://www.google.com/support/chromeos/bin/answer.py?answer=142893"; 172#else 173 "https://www.google.com/support/chrome/bin/answer.py?answer=142893"; 174#endif 175 176// The URL to be loaded to display the "Report a broken page" form. 177const char kBrokenPageUrl[] = 178 "https://www.google.com/support/chrome/bin/request.py?contact_type=" 179 "broken_website&format=inproduct&p.page_title=$1&p.page_url=$2"; 180 181// The URL for the privacy dashboard. 182const char kPrivacyDashboardUrl[] = "https://www.google.com/dashboard"; 183 184// How long we wait before updating the browser chrome while loading a page. 185const int kUIUpdateCoalescingTimeMS = 200; 186 187const char kHashMark[] = "#"; 188 189#if defined(OS_CHROMEOS) 190// If a popup window is bigger than this fraction of the screen on chrome os, 191// turn it into a tab 192const float kPopupMaxWidthFactor = 0.5; 193const float kPopupMaxHeightFactor = 0.6; 194#endif 195 196} // namespace 197 198extern bool g_log_bug53991; 199 200/////////////////////////////////////////////////////////////////////////////// 201// Browser, Constructors, Creation, Showing: 202 203Browser::Browser(Type type, Profile* profile) 204 : type_(type), 205 profile_(profile), 206 window_(NULL), 207 ALLOW_THIS_IN_INITIALIZER_LIST( 208 tab_handler_(TabHandler::CreateTabHandler(this))), 209 command_updater_(this), 210 toolbar_model_(this), 211 chrome_updater_factory_(this), 212 is_attempting_to_close_browser_(false), 213 cancel_download_confirmation_state_(NOT_PROMPTED), 214 maximized_state_(MAXIMIZED_STATE_DEFAULT), 215 method_factory_(this), 216 block_command_execution_(false), 217 last_blocked_command_id_(-1), 218 last_blocked_command_disposition_(CURRENT_TAB), 219 pending_web_app_action_(NONE), 220 ALLOW_THIS_IN_INITIALIZER_LIST( 221 tab_restore_service_delegate_( 222 new BrowserTabRestoreServiceDelegate(this))) { 223 registrar_.Add(this, NotificationType::SSL_VISIBLE_STATE_CHANGED, 224 NotificationService::AllSources()); 225 registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, 226 NotificationService::AllSources()); 227 registrar_.Add(this, NotificationType::EXTENSION_LOADED, 228 NotificationService::AllSources()); 229 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, 230 NotificationService::AllSources()); 231 registrar_.Add(this, NotificationType::EXTENSION_UNINSTALLED, 232 NotificationService::AllSources()); 233 registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED, 234 NotificationService::AllSources()); 235 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, 236 NotificationService::AllSources()); 237 238 // Need to know when to alert the user of theme install delay. 239 registrar_.Add(this, NotificationType::EXTENSION_READY_FOR_INSTALL, 240 NotificationService::AllSources()); 241 242 // NOTE: These prefs all need to be explicitly destroyed in the destructor 243 // or you'll get a nasty surprise when you run the incognito tests. 244 PrefService* local_state = g_browser_process->local_state(); 245 if (local_state) 246 printing_enabled_.Init(prefs::kPrintingEnabled, local_state, this); 247 dev_tools_disabled_.Init(prefs::kDevToolsDisabled, 248 profile_->GetPrefs(), this); 249 incognito_mode_allowed_.Init(prefs::kIncognitoEnabled, 250 profile_->GetPrefs(), this); 251 edit_bookmarks_enabled_.Init(prefs::kEditBookmarksEnabled, 252 profile_->GetPrefs(), this); 253 254 InitCommandState(); 255 BrowserList::AddBrowser(this); 256 257 encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector, 258 profile_->GetPrefs(), NULL); 259 use_vertical_tabs_.Init(prefs::kUseVerticalTabs, profile_->GetPrefs(), this); 260 instant_enabled_.Init(prefs::kInstantEnabled, profile_->GetPrefs(), this); 261 if (!TabMenuModel::AreVerticalTabsEnabled()) { 262 // If vertical tabs aren't enabled, explicitly turn them off. Otherwise we 263 // might show vertical tabs but not show an option to turn them off. 264 use_vertical_tabs_.SetValue(false); 265 } 266 UpdateTabStripModelInsertionPolicy(); 267 268 tab_restore_service_ = profile->GetTabRestoreService(); 269 if (tab_restore_service_) { 270 tab_restore_service_->AddObserver(this); 271 TabRestoreServiceChanged(tab_restore_service_); 272 } 273 274 if (profile_->GetProfileSyncService()) 275 profile_->GetProfileSyncService()->AddObserver(this); 276 277 CreateInstantIfNecessary(); 278 279 // Make sure TabFinder has been created. This does nothing if TabFinder is 280 // not enabled. 281 TabFinder::GetInstance(); 282} 283 284Browser::~Browser() { 285 VLOG_IF(1, g_log_bug53991) << "~Browser: " << profile_->IsOffTheRecord() 286 << "; stillActive=" 287 << BrowserList::IsOffTheRecordSessionActive(); 288 289 if (profile_->GetProfileSyncService()) 290 profile_->GetProfileSyncService()->RemoveObserver(this); 291 292 BrowserList::RemoveBrowser(this); 293 294#if defined(OS_WIN) || defined(OS_LINUX) 295 if (!BrowserList::HasBrowserWithProfile(profile_)) { 296 // We're the last browser window with this profile. We need to nuke the 297 // TabRestoreService, which will start the shutdown of the 298 // NavigationControllers and allow for proper shutdown. If we don't do this 299 // chrome won't shutdown cleanly, and may end up crashing when some 300 // thread tries to use the IO thread (or another thread) that is no longer 301 // valid. 302 // This isn't a valid assumption for Mac OS, as it stays running after 303 // the last browser has closed. The Mac equivalent is in its app 304 // controller. 305 profile_->ResetTabRestoreService(); 306 } 307#endif 308 309 SessionService* session_service = profile_->GetSessionService(); 310 if (session_service) 311 session_service->WindowClosed(session_id_); 312 313 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService(); 314 if (tab_restore_service) 315 tab_restore_service->BrowserClosed(tab_restore_service_delegate()); 316 317 encoding_auto_detect_.Destroy(); 318 printing_enabled_.Destroy(); 319 dev_tools_disabled_.Destroy(); 320 incognito_mode_allowed_.Destroy(); 321 instant_enabled_.Destroy(); 322 use_vertical_tabs_.Destroy(); 323 edit_bookmarks_enabled_.Destroy(); 324 325 if (profile_->IsOffTheRecord() && 326 !BrowserList::IsOffTheRecordSessionActive()) { 327 // An incognito profile is no longer needed, this indirectly 328 // frees its cache and cookies. 329 profile_->GetOriginalProfile()->DestroyOffTheRecordProfile(); 330 } 331 332 // There may be pending file dialogs, we need to tell them that we've gone 333 // away so they don't try and call back to us. 334 if (select_file_dialog_.get()) 335 select_file_dialog_->ListenerDestroyed(); 336 337 TabRestoreServiceDestroyed(tab_restore_service_); 338} 339 340// static 341Browser* Browser::Create(Profile* profile) { 342 Browser* browser = new Browser(TYPE_NORMAL, profile); 343 browser->InitBrowserWindow(); 344 return browser; 345} 346 347// static 348Browser* Browser::CreateForPopup(Type type, 349 Profile* profile, 350 TabContents* new_contents, 351 const gfx::Rect& initial_bounds) { 352 DCHECK(type & TYPE_POPUP); 353 Browser* browser = new Browser(type, profile); 354 browser->set_override_bounds(initial_bounds); 355 browser->InitBrowserWindow(); 356 TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents); 357 browser->tabstrip_model()->AppendTabContents(wrapper, true); 358 return browser; 359} 360 361// static 362Browser* Browser::CreateForType(Type type, Profile* profile) { 363 Browser* browser = new Browser(type, profile); 364 browser->InitBrowserWindow(); 365 return browser; 366} 367 368// static 369Browser* Browser::CreateForApp(const std::string& app_name, 370 const gfx::Size& window_size, 371 Profile* profile, 372 bool is_panel) { 373 Browser::Type type = TYPE_APP; 374 375 if (is_panel) { 376 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels)) { 377 type = TYPE_APP_PANEL; 378 } else { 379 // TYPE_APP_PANEL is the logical choice. However, the panel UI 380 // is not fully implemented. See crbug/55943. 381 type = TYPE_APP_POPUP; 382 } 383 } 384 385 Browser* browser = new Browser(type, profile); 386 browser->app_name_ = app_name; 387 388 if (!window_size.IsEmpty()) { 389 gfx::Rect initial_pos(window_size); 390 browser->set_override_bounds(initial_pos); 391 } 392 393 browser->InitBrowserWindow(); 394 395 return browser; 396} 397 398// static 399Browser* Browser::CreateForDevTools(Profile* profile) { 400 Browser* browser = new Browser(TYPE_DEVTOOLS, profile); 401 browser->app_name_ = DevToolsWindow::kDevToolsApp; 402 browser->InitBrowserWindow(); 403 return browser; 404} 405 406void Browser::InitBrowserWindow() { 407 DCHECK(!window_); 408 409 window_ = CreateBrowserWindow(); 410 411#if defined(OS_WIN) 412 { 413 // TODO: This might hit the disk 414 // http://code.google.com/p/chromium/issues/detail?id=61638 415 base::ThreadRestrictions::ScopedAllowIO allow_io; 416 417 // Set the app user model id for this application to that of the application 418 // name. See http://crbug.com/7028. 419 app::win::SetAppIdForWindow( 420 type_ & TYPE_APP ? 421 ShellIntegration::GetAppId(UTF8ToWide(app_name_), profile_->GetPath()) : 422 ShellIntegration::GetChromiumAppId(profile_->GetPath()), 423 window()->GetNativeHandle()); 424 } 425#endif 426 427 NotificationService::current()->Notify( 428 NotificationType::BROWSER_WINDOW_READY, 429 Source<Browser>(this), 430 NotificationService::NoDetails()); 431 432 // Show the First Run information bubble if we've been told to. 433 PrefService* local_state = g_browser_process->local_state(); 434 if (!local_state) 435 return; 436 if (local_state->FindPreference(prefs::kShouldShowFirstRunBubble) && 437 local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) { 438 FirstRun::BubbleType bubble_type = FirstRun::LARGE_BUBBLE; 439 if (local_state-> 440 FindPreference(prefs::kShouldUseOEMFirstRunBubble) && 441 local_state->GetBoolean(prefs::kShouldUseOEMFirstRunBubble)) { 442 bubble_type = FirstRun::OEM_BUBBLE; 443 } else if (local_state-> 444 FindPreference(prefs::kShouldUseMinimalFirstRunBubble) && 445 local_state->GetBoolean(prefs::kShouldUseMinimalFirstRunBubble)) { 446 bubble_type = FirstRun::MINIMAL_BUBBLE; 447 } 448 // Reset the preference so we don't show the bubble for subsequent windows. 449 local_state->ClearPref(prefs::kShouldShowFirstRunBubble); 450 window_->GetLocationBar()->ShowFirstRunBubble(bubble_type); 451 } 452 if (local_state->FindPreference( 453 prefs::kAutofillPersonalDataManagerFirstRun) && 454 local_state->GetBoolean(prefs::kAutofillPersonalDataManagerFirstRun)) { 455 // Notify PDM that this is a first run. 456#if defined(OS_WIN) 457 ImportAutofillDataWin(profile_->GetPersonalDataManager()); 458#endif // defined(OS_WIN) 459 // Reset the preference so we don't call it again for subsequent windows. 460 local_state->ClearPref(prefs::kAutofillPersonalDataManagerFirstRun); 461 } 462} 463 464/////////////////////////////////////////////////////////////////////////////// 465// Getters & Setters 466 467const std::vector<std::wstring>& Browser::user_data_dir_profiles() const { 468 return g_browser_process->user_data_dir_profiles(); 469} 470 471void Browser::set_user_data_dir_profiles( 472 const std::vector<std::wstring>& profiles) { 473 g_browser_process->user_data_dir_profiles() = profiles; 474} 475 476FindBarController* Browser::GetFindBarController() { 477 if (!find_bar_controller_.get()) { 478 FindBar* find_bar = BrowserWindow::CreateFindBar(this); 479 find_bar_controller_.reset(new FindBarController(find_bar)); 480 find_bar->SetFindBarController(find_bar_controller_.get()); 481 find_bar_controller_->ChangeTabContents(GetSelectedTabContentsWrapper()); 482 find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true); 483 } 484 return find_bar_controller_.get(); 485} 486 487bool Browser::HasFindBarController() const { 488 return find_bar_controller_.get() != NULL; 489} 490 491/////////////////////////////////////////////////////////////////////////////// 492// Browser, Creation Helpers: 493 494// static 495void Browser::OpenEmptyWindow(Profile* profile) { 496 Browser* browser = Browser::Create(profile); 497 browser->AddBlankTab(true); 498 browser->window()->Show(); 499} 500 501// static 502void Browser::OpenWindowWithRestoredTabs(Profile* profile) { 503 TabRestoreService* service = profile->GetTabRestoreService(); 504 if (service) 505 service->RestoreMostRecentEntry(NULL); 506} 507 508// static 509void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) { 510 Browser* browser = GetOrCreateTabbedBrowser( 511 profile->GetOffTheRecordProfile()); 512 browser->AddSelectedTabWithURL(url, PageTransition::LINK); 513 browser->window()->Show(); 514} 515 516// static 517TabContents* Browser::OpenApplication( 518 Profile* profile, 519 const Extension* extension, 520 extension_misc::LaunchContainer container, 521 TabContents* existing_tab) { 522 TabContents* tab = NULL; 523 ExtensionPrefs* prefs = profile->GetExtensionService()->extension_prefs(); 524 prefs->SetActiveBit(extension->id(), true); 525 526 UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchContainer", container, 100); 527 528 switch (container) { 529 case extension_misc::LAUNCH_WINDOW: 530 case extension_misc::LAUNCH_PANEL: 531 tab = Browser::OpenApplicationWindow(profile, extension, container, 532 GURL(), NULL); 533 break; 534 case extension_misc::LAUNCH_TAB: { 535 tab = Browser::OpenApplicationTab(profile, extension, existing_tab); 536 break; 537 } 538 default: 539 NOTREACHED(); 540 break; 541 } 542 return tab; 543} 544 545// static 546TabContents* Browser::OpenApplicationWindow( 547 Profile* profile, 548 const Extension* extension, 549 extension_misc::LaunchContainer container, 550 const GURL& url_input, 551 Browser** app_browser) { 552 GURL url; 553 if (!url_input.is_empty()) { 554 if (extension) 555 DCHECK(extension->web_extent().ContainsURL(url_input)); 556 url = url_input; 557 } else { 558 DCHECK(extension); // Empty url and no extension. Nothing to open. 559 url = extension->GetFullLaunchURL(); 560 } 561 562 std::string app_name; 563 if (extension) 564 app_name = 565 web_app::GenerateApplicationNameFromExtensionId(extension->id()); 566 else 567 app_name = web_app::GenerateApplicationNameFromURL(url); 568 569 RegisterAppPrefs(app_name, profile); 570 571 bool as_panel = extension && (container == extension_misc::LAUNCH_PANEL); 572 573 gfx::Size window_size; 574 if (extension) 575 window_size.SetSize(extension->launch_width(), 576 extension->launch_height()); 577 578 Browser* browser = Browser::CreateForApp(app_name, window_size, profile, 579 as_panel); 580 581 if (app_browser) 582 *app_browser = browser; 583 584 TabContentsWrapper* wrapper = 585 browser->AddSelectedTabWithURL(url, PageTransition::START_PAGE); 586 TabContents* contents = wrapper->tab_contents(); 587 contents->GetMutableRendererPrefs()->can_accept_load_drops = false; 588 contents->render_view_host()->SyncRendererPrefs(); 589 browser->window()->Show(); 590 591 // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial 592 // focus explicitly. 593 contents->view()->SetInitialFocus(); 594 return contents; 595} 596 597TabContents* Browser::OpenAppShortcutWindow(Profile* profile, 598 const GURL& url, 599 bool update_shortcut) { 600 Browser* app_browser; 601 TabContents* tab = OpenApplicationWindow( 602 profile, 603 NULL, // this is a URL app. No extension. 604 extension_misc::LAUNCH_WINDOW, 605 url, 606 &app_browser); 607 608 if (!tab) 609 return NULL; 610 611 if (update_shortcut) { 612 // Set UPDATE_SHORTCUT as the pending web app action. This action is picked 613 // up in LoadingStateChanged to schedule a GetApplicationInfo. And when 614 // the web app info is available, TabContents notifies Browser via 615 // OnDidGetApplicationInfo, which calls 616 // web_app::UpdateShortcutForTabContents when it sees UPDATE_SHORTCUT as 617 // pending web app action. 618 app_browser->pending_web_app_action_ = UPDATE_SHORTCUT; 619 } 620 return tab; 621} 622 623// static 624TabContents* Browser::OpenApplicationTab(Profile* profile, 625 const Extension* extension, 626 TabContents* existing_tab) { 627 Browser* browser = 628 BrowserList::FindBrowserWithType(profile, Browser::TYPE_NORMAL, false); 629 TabContents* contents = NULL; 630 if (!browser) 631 return contents; 632 633 // Check the prefs for overridden mode. 634 ExtensionService* extensions_service = profile->GetExtensionService(); 635 DCHECK(extensions_service); 636 637 ExtensionPrefs::LaunchType launch_type = 638 extensions_service->extension_prefs()->GetLaunchType( 639 extension->id(), ExtensionPrefs::LAUNCH_DEFAULT); 640 UMA_HISTOGRAM_ENUMERATION("Extensions.AppTabLaunchType", launch_type, 100); 641 int add_type = TabStripModel::ADD_ACTIVE; 642 if (launch_type == ExtensionPrefs::LAUNCH_PINNED) 643 add_type |= TabStripModel::ADD_PINNED; 644 645 // For extensions lacking launch urls, determine a reasonable fallback. 646 GURL extension_url = extension->GetFullLaunchURL(); 647 if (!extension_url.is_valid()) { 648 extension_url = extension->options_url(); 649 if (!extension_url.is_valid()) 650 extension_url = GURL(chrome::kChromeUIExtensionsURL); 651 } 652 653 // TODO(erikkay): START_PAGE doesn't seem like the right transition in all 654 // cases. 655 browser::NavigateParams params(browser, extension_url, 656 PageTransition::START_PAGE); 657 params.tabstrip_add_types = add_type; 658 659 // Launch the application in the existing TabContents, if it was supplied. 660 if (existing_tab) { 661 TabStripModel* model = browser->tabstrip_model(); 662 int tab_index = model->GetWrapperIndex(existing_tab); 663 664 existing_tab->OpenURL(extension->GetFullLaunchURL(), existing_tab->GetURL(), 665 CURRENT_TAB, PageTransition::LINK); 666 if (params.tabstrip_add_types & TabStripModel::ADD_PINNED) { 667 model->SetTabPinned(tab_index, true); 668 tab_index = model->GetWrapperIndex(existing_tab); 669 } 670 if (params.tabstrip_add_types & TabStripModel::ADD_ACTIVE) 671 model->ActivateTabAt(tab_index, true); 672 673 contents = existing_tab; 674 } else { 675 params.disposition = NEW_FOREGROUND_TAB; 676 browser::Navigate(¶ms); 677 contents = params.target_contents->tab_contents(); 678 } 679 680 // TODO(skerner): If we are already in full screen mode, and the user 681 // set the app to open as a regular or pinned tab, what should happen? 682 // Today we open the tab, but stay in full screen mode. Should we leave 683 // full screen mode in this case? 684 if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN && 685 !browser->window()->IsFullscreen()) 686 browser->ToggleFullscreenMode(); 687 688 return contents; 689} 690 691// static 692void Browser::OpenBookmarkManagerWindow(Profile* profile) { 693 Browser* browser = Browser::Create(profile); 694 browser->ShowBookmarkManagerTab(); 695 browser->window()->Show(); 696} 697 698#if defined(OS_MACOSX) 699// static 700void Browser::OpenHistoryWindow(Profile* profile) { 701 Browser* browser = Browser::Create(profile); 702 browser->ShowHistoryTab(); 703 browser->window()->Show(); 704} 705 706// static 707void Browser::OpenDownloadsWindow(Profile* profile) { 708 Browser* browser = Browser::Create(profile); 709 browser->ShowDownloadsTab(); 710 browser->window()->Show(); 711} 712 713// static 714void Browser::OpenHelpWindow(Profile* profile) { 715 Browser* browser = Browser::Create(profile); 716 browser->OpenHelpTab(); 717 browser->window()->Show(); 718} 719 720// static 721void Browser::OpenOptionsWindow(Profile* profile) { 722 Browser* browser = Browser::Create(profile); 723 browser->OpenOptionsDialog(); 724 browser->window()->Show(); 725} 726 727// static 728void Browser::OpenClearBrowingDataDialogWindow(Profile* profile) { 729 Browser* browser = Browser::Create(profile); 730 browser->OpenClearBrowsingDataDialog(); 731 browser->window()->Show(); 732} 733 734// static 735void Browser::OpenImportSettingsDialogWindow(Profile* profile) { 736 Browser* browser = Browser::Create(profile); 737 browser->OpenImportSettingsDialog(); 738 browser->window()->Show(); 739} 740 741// static 742void Browser::OpenInstantConfirmDialogWindow(Profile* profile) { 743 Browser* browser = Browser::Create(profile); 744 browser->OpenInstantConfirmDialog(); 745 browser->window()->Show(); 746} 747#endif 748 749// static 750void Browser::OpenExtensionsWindow(Profile* profile) { 751 Browser* browser = Browser::Create(profile); 752 browser->ShowExtensionsTab(); 753 browser->window()->Show(); 754} 755 756 757/////////////////////////////////////////////////////////////////////////////// 758// Browser, State Storage and Retrieval for UI: 759 760std::string Browser::GetWindowPlacementKey() const { 761 std::string name(prefs::kBrowserWindowPlacement); 762 if (!app_name_.empty()) { 763 name.append("_"); 764 name.append(app_name_); 765 } 766 return name; 767} 768 769bool Browser::ShouldSaveWindowPlacement() const { 770 // Only save the window placement of popups if they are restored. 771 return (type() & TYPE_POPUP) == 0 || browser_defaults::kRestorePopups; 772} 773 774void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) { 775 // Save to the session storage service, used when reloading a past session. 776 // Note that we don't want to be the ones who cause lazy initialization of 777 // the session service. This function gets called during initial window 778 // showing, and we don't want to bring in the session service this early. 779 if (profile()->HasSessionService()) { 780 SessionService* session_service = profile()->GetSessionService(); 781 if (session_service) 782 session_service->SetWindowBounds(session_id_, bounds, maximized); 783 } 784} 785 786gfx::Rect Browser::GetSavedWindowBounds() const { 787 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); 788 bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode); 789 bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode); 790 if (record_mode || playback_mode) { 791 // In playback/record mode we always fix the size of the browser and 792 // move it to (0,0). The reason for this is two reasons: First we want 793 // resize/moves in the playback to still work, and Second we want 794 // playbacks to work (as much as possible) on machines w/ different 795 // screen sizes. 796 return gfx::Rect(0, 0, 800, 600); 797 } 798 799 gfx::Rect restored_bounds = override_bounds_; 800 bool maximized; 801 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, this, 802 &restored_bounds, &maximized); 803 return restored_bounds; 804} 805 806// TODO(beng): obtain maximized state some other way so we don't need to go 807// through all this hassle. 808bool Browser::GetSavedMaximizedState() const { 809 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStartMaximized)) 810 return true; 811 812 if (maximized_state_ == MAXIMIZED_STATE_MAXIMIZED) 813 return true; 814 if (maximized_state_ == MAXIMIZED_STATE_UNMAXIMIZED) 815 return false; 816 817 // An explicit maximized state was not set. Query the window sizer. 818 gfx::Rect restored_bounds; 819 bool maximized = false; 820 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, this, 821 &restored_bounds, &maximized); 822 return maximized; 823} 824 825SkBitmap Browser::GetCurrentPageIcon() const { 826 TabContents* contents = GetSelectedTabContents(); 827 // |contents| can be NULL since GetCurrentPageIcon() is called by the window 828 // during the window's creation (before tabs have been added). 829 return contents ? contents->GetFavicon() : SkBitmap(); 830} 831 832string16 Browser::GetWindowTitleForCurrentTab() const { 833 TabContents* contents = GetSelectedTabContents(); 834 string16 title; 835 836 // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the 837 // window during the window's creation (before tabs have been added). 838 if (contents) { 839 title = contents->GetTitle(); 840 FormatTitleForDisplay(&title); 841 } 842 if (title.empty()) 843 title = TabContentsWrapper::GetDefaultTitle(); 844 845#if defined(OS_MACOSX) || defined(OS_CHROMEOS) 846 // On Mac or ChromeOS, we don't want to suffix the page title with 847 // the application name. 848 return title; 849#elif defined(OS_WIN) || defined(OS_LINUX) 850 int string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT; 851 // Don't append the app name to window titles on app frames and app popups 852 if (type_ & TYPE_APP) 853 string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT_NO_LOGO; 854 return l10n_util::GetStringFUTF16(string_id, title); 855#endif 856} 857 858// static 859void Browser::FormatTitleForDisplay(string16* title) { 860 size_t current_index = 0; 861 size_t match_index; 862 while ((match_index = title->find(L'\n', current_index)) != string16::npos) { 863 title->replace(match_index, 1, string16()); 864 current_index = match_index; 865 } 866} 867 868/////////////////////////////////////////////////////////////////////////////// 869// Browser, OnBeforeUnload handling: 870 871bool Browser::TabsNeedBeforeUnloadFired() { 872 if (tabs_needing_before_unload_fired_.empty()) { 873 for (int i = 0; i < tab_count(); ++i) { 874 TabContents* contents = GetTabContentsAt(i); 875 if (contents->NeedToFireBeforeUnload()) 876 tabs_needing_before_unload_fired_.insert(contents); 877 } 878 } 879 return !tabs_needing_before_unload_fired_.empty(); 880} 881 882bool Browser::ShouldCloseWindow() { 883 if (!CanCloseWithInProgressDownloads()) 884 return false; 885 886 if (HasCompletedUnloadProcessing()) 887 return IsClosingPermitted(); 888 889 is_attempting_to_close_browser_ = true; 890 891 if (!TabsNeedBeforeUnloadFired()) 892 return IsClosingPermitted(); 893 894 ProcessPendingTabs(); 895 return false; 896} 897 898void Browser::OnWindowClosing() { 899 if (!ShouldCloseWindow()) 900 return; 901 902 bool exiting = false; 903 904 // Application should shutdown on last window close if the user is explicitly 905 // trying to quit, or if there is nothing keeping the browser alive (such as 906 // AppController on the Mac, or BackgroundContentsService for background 907 // pages). 908 bool should_quit_if_last_browser = 909 browser_shutdown::IsTryingToQuit() || !BrowserList::WillKeepAlive(); 910 911 if (should_quit_if_last_browser && BrowserList::size() == 1) { 912 browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE); 913 exiting = true; 914 } 915 916 // Don't use HasSessionService here, we want to force creation of the 917 // session service so that user can restore what was open. 918 SessionService* session_service = profile()->GetSessionService(); 919 if (session_service) 920 session_service->WindowClosing(session_id()); 921 922 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService(); 923 if (tab_restore_service && type() == TYPE_NORMAL && tab_count()) 924 tab_restore_service->BrowserClosing(tab_restore_service_delegate()); 925 926 // TODO(sky): convert session/tab restore to use notification. 927 NotificationService::current()->Notify( 928 NotificationType::BROWSER_CLOSING, 929 Source<Browser>(this), 930 Details<bool>(&exiting)); 931 932 CloseAllTabs(); 933} 934 935//////////////////////////////////////////////////////////////////////////////// 936// In-progress download termination handling: 937 938void Browser::InProgressDownloadResponse(bool cancel_downloads) { 939 if (cancel_downloads) { 940 cancel_download_confirmation_state_ = RESPONSE_RECEIVED; 941 CloseWindow(); 942 return; 943 } 944 945 // Sets the confirmation state to NOT_PROMPTED so that if the user tries to 946 // close again we'll show the warning again. 947 cancel_download_confirmation_state_ = NOT_PROMPTED; 948 949 // Show the download page so the user can figure-out what downloads are still 950 // in-progress. 951 ShowDownloadsTab(); 952} 953 954//////////////////////////////////////////////////////////////////////////////// 955// Browser, TabStripModel pass-thrus: 956 957int Browser::tab_count() const { 958 return tab_handler_->GetTabStripModel()->count(); 959} 960 961int Browser::active_index() const { 962 return tab_handler_->GetTabStripModel()->active_index(); 963} 964 965int Browser::GetIndexOfController( 966 const NavigationController* controller) const { 967 return tab_handler_->GetTabStripModel()->GetIndexOfController(controller); 968} 969 970TabContentsWrapper* Browser::GetSelectedTabContentsWrapper() const { 971 return tabstrip_model()->GetSelectedTabContents(); 972} 973TabContentsWrapper* Browser::GetTabContentsWrapperAt(int index) const { 974 return tabstrip_model()->GetTabContentsAt(index); 975} 976 977TabContents* Browser::GetSelectedTabContents() const { 978 TabContentsWrapper* wrapper = GetSelectedTabContentsWrapper(); 979 if (wrapper) 980 return wrapper->tab_contents(); 981 return NULL; 982} 983 984TabContents* Browser::GetTabContentsAt(int index) const { 985 TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index); 986 if (wrapper) 987 return wrapper->tab_contents(); 988 return NULL; 989} 990 991void Browser::ActivateTabAt(int index, bool user_gesture) { 992 tab_handler_->GetTabStripModel()->ActivateTabAt(index, user_gesture); 993} 994 995bool Browser::IsTabPinned(int index) const { 996 return tabstrip_model()->IsTabPinned(index); 997} 998 999void Browser::CloseAllTabs() { 1000 tab_handler_->GetTabStripModel()->CloseAllTabs(); 1001} 1002 1003//////////////////////////////////////////////////////////////////////////////// 1004// Browser, Tab adding/showing functions: 1005 1006bool Browser::IsTabStripEditable() const { 1007 return window()->IsTabStripEditable(); 1008} 1009 1010int Browser::GetIndexForInsertionDuringRestore(int relative_index) { 1011 return (tab_handler_->GetTabStripModel()->insertion_policy() == 1012 TabStripModel::INSERT_AFTER) ? tab_count() : relative_index; 1013} 1014 1015TabContentsWrapper* Browser::AddSelectedTabWithURL(const GURL& url, 1016 PageTransition::Type transition) { 1017 browser::NavigateParams params(this, url, transition); 1018 params.disposition = NEW_FOREGROUND_TAB; 1019 browser::Navigate(¶ms); 1020 return params.target_contents; 1021} 1022 1023TabContents* Browser::AddTab(TabContentsWrapper* tab_contents, 1024 PageTransition::Type type) { 1025 tab_handler_->GetTabStripModel()->AddTabContents( 1026 tab_contents, -1, type, TabStripModel::ADD_ACTIVE); 1027 return tab_contents->tab_contents(); 1028} 1029 1030void Browser::AddTabContents(TabContents* new_contents, 1031 WindowOpenDisposition disposition, 1032 const gfx::Rect& initial_pos, 1033 bool user_gesture) { 1034 AddNewContents(NULL, new_contents, disposition, initial_pos, user_gesture); 1035} 1036 1037void Browser::CloseTabContents(TabContents* contents) { 1038 CloseContents(contents); 1039} 1040 1041void Browser::BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate, 1042 gfx::NativeWindow parent_window) { 1043 ShowHtmlDialog(delegate, parent_window); 1044} 1045 1046void Browser::BrowserRenderWidgetShowing() { 1047 RenderWidgetShowing(); 1048} 1049 1050void Browser::BookmarkBarSizeChanged(bool is_animating) { 1051 window_->ToolbarSizeChanged(is_animating); 1052} 1053 1054TabContents* Browser::AddRestoredTab( 1055 const std::vector<TabNavigation>& navigations, 1056 int tab_index, 1057 int selected_navigation, 1058 const std::string& extension_app_id, 1059 bool select, 1060 bool pin, 1061 bool from_last_session, 1062 SessionStorageNamespace* session_storage_namespace) { 1063 TabContentsWrapper* wrapper = TabContentsFactory(profile(), NULL, 1064 MSG_ROUTING_NONE, 1065 GetSelectedTabContents(), 1066 session_storage_namespace); 1067 TabContents* new_tab = wrapper->tab_contents(); 1068 wrapper->extension_tab_helper()->SetExtensionAppById(extension_app_id); 1069 new_tab->controller().RestoreFromState(navigations, selected_navigation, 1070 from_last_session); 1071 1072 int add_types = select ? TabStripModel::ADD_ACTIVE : 1073 TabStripModel::ADD_NONE; 1074 if (pin) { 1075 tab_index = std::min(tab_index, tabstrip_model()->IndexOfFirstNonMiniTab()); 1076 add_types |= TabStripModel::ADD_PINNED; 1077 } 1078 tab_handler_->GetTabStripModel()->InsertTabContentsAt(tab_index, wrapper, 1079 add_types); 1080 if (select) { 1081 window_->Activate(); 1082 } else { 1083 // We set the size of the view here, before WebKit does its initial 1084 // layout. If we don't, the initial layout of background tabs will be 1085 // performed with a view width of 0, which may cause script outputs and 1086 // anchor link location calculations to be incorrect even after a new 1087 // layout with proper view dimensions. TabStripModel::AddTabContents() 1088 // contains similar logic. 1089 new_tab->view()->SizeContents(window_->GetRestoredBounds().size()); 1090 new_tab->HideContents(); 1091 } 1092 if (profile_->HasSessionService()) { 1093 SessionService* session_service = profile_->GetSessionService(); 1094 if (session_service) 1095 session_service->TabRestored(&new_tab->controller(), pin); 1096 } 1097 return new_tab; 1098} 1099 1100void Browser::ReplaceRestoredTab( 1101 const std::vector<TabNavigation>& navigations, 1102 int selected_navigation, 1103 bool from_last_session, 1104 const std::string& extension_app_id, 1105 SessionStorageNamespace* session_storage_namespace) { 1106 TabContentsWrapper* wrapper = TabContentsFactory(profile(), NULL, 1107 MSG_ROUTING_NONE, 1108 GetSelectedTabContents(), 1109 session_storage_namespace); 1110 wrapper->extension_tab_helper()->SetExtensionAppById(extension_app_id); 1111 TabContents* replacement = wrapper->tab_contents(); 1112 replacement->controller().RestoreFromState(navigations, selected_navigation, 1113 from_last_session); 1114 1115 tab_handler_->GetTabStripModel()->ReplaceNavigationControllerAt( 1116 tab_handler_->GetTabStripModel()->active_index(), 1117 wrapper); 1118} 1119 1120bool Browser::CanRestoreTab() { 1121 return command_updater_.IsCommandEnabled(IDC_RESTORE_TAB); 1122} 1123 1124bool Browser::NavigateToIndexWithDisposition(int index, 1125 WindowOpenDisposition disp) { 1126 NavigationController& controller = 1127 GetOrCloneTabForDisposition(disp)->controller(); 1128 if (index < 0 || index >= controller.entry_count()) 1129 return false; 1130 controller.GoToIndex(index); 1131 return true; 1132} 1133 1134browser::NavigateParams Browser::GetSingletonTabNavigateParams( 1135 const GURL& url) { 1136 browser::NavigateParams params(this, url, PageTransition::AUTO_BOOKMARK); 1137 params.disposition = SINGLETON_TAB; 1138 params.window_action = browser::NavigateParams::SHOW_WINDOW; 1139 return params; 1140} 1141 1142void Browser::ShowSingletonTab(const GURL& url) { 1143 browser::NavigateParams params(GetSingletonTabNavigateParams(url)); 1144 browser::Navigate(¶ms); 1145} 1146 1147void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) { 1148#if !defined(OS_MACOSX) 1149 const bool show_main_ui = (type() == TYPE_NORMAL) && !is_fullscreen; 1150#else 1151 const bool show_main_ui = (type() == TYPE_NORMAL); 1152#endif 1153 1154 bool main_not_fullscreen_or_popup = 1155 show_main_ui && !is_fullscreen && (type() & TYPE_POPUP) == 0; 1156 1157 // Navigation commands 1158 command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui); 1159 1160 // Window management commands 1161 command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB, 1162 (type() & TYPE_POPUP) && !is_fullscreen); 1163 1164 // Focus various bits of UI 1165 command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui); 1166 command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui); 1167 command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui); 1168 command_updater_.UpdateCommandEnabled( 1169 IDC_FOCUS_MENU_BAR, main_not_fullscreen_or_popup); 1170 command_updater_.UpdateCommandEnabled( 1171 IDC_FOCUS_NEXT_PANE, main_not_fullscreen_or_popup); 1172 command_updater_.UpdateCommandEnabled( 1173 IDC_FOCUS_PREVIOUS_PANE, main_not_fullscreen_or_popup); 1174 command_updater_.UpdateCommandEnabled( 1175 IDC_FOCUS_BOOKMARKS, main_not_fullscreen_or_popup); 1176 command_updater_.UpdateCommandEnabled( 1177 IDC_FOCUS_CHROMEOS_STATUS, main_not_fullscreen_or_popup); 1178 1179 // Show various bits of UI 1180 command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui); 1181 command_updater_.UpdateCommandEnabled(IDC_FEEDBACK, show_main_ui); 1182 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, 1183 browser_defaults::bookmarks_enabled && show_main_ui); 1184 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui); 1185 command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, 1186 show_main_ui && profile_->IsSyncAccessible()); 1187 1188 command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui); 1189 command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui); 1190 command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui); 1191 command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui); 1192 command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui); 1193 command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, show_main_ui); 1194#if defined (ENABLE_PROFILING) && !defined(NO_TCMALLOC) 1195 command_updater_.UpdateCommandEnabled(IDC_PROFILING_ENABLED, show_main_ui); 1196#endif 1197} 1198 1199/////////////////////////////////////////////////////////////////////////////// 1200// Browser, Assorted browser commands: 1201 1202bool Browser::ShouldOpenNewTabForWindowDisposition( 1203 WindowOpenDisposition disposition) { 1204 return (disposition == NEW_FOREGROUND_TAB || 1205 disposition == NEW_BACKGROUND_TAB); 1206} 1207 1208TabContents* Browser::GetOrCloneTabForDisposition( 1209 WindowOpenDisposition disposition) { 1210 TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper(); 1211 if (ShouldOpenNewTabForWindowDisposition(disposition)) { 1212 current_tab = current_tab->Clone(); 1213 tab_handler_->GetTabStripModel()->AddTabContents( 1214 current_tab, -1, PageTransition::LINK, 1215 disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_ACTIVE : 1216 TabStripModel::ADD_NONE); 1217 } 1218 return current_tab->tab_contents(); 1219} 1220 1221void Browser::UpdateTabStripModelInsertionPolicy() { 1222 tab_handler_->GetTabStripModel()->SetInsertionPolicy(UseVerticalTabs() ? 1223 TabStripModel::INSERT_BEFORE : TabStripModel::INSERT_AFTER); 1224} 1225 1226void Browser::UseVerticalTabsChanged() { 1227 UpdateTabStripModelInsertionPolicy(); 1228 window()->ToggleTabStripMode(); 1229} 1230 1231bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, 1232 bool check_fullscreen) const { 1233 // On Mac, fullscreen mode has most normal things (in a slide-down panel). On 1234 // other platforms, we hide some controls when in fullscreen mode. 1235 bool hide_ui_for_fullscreen = false; 1236#if !defined(OS_MACOSX) 1237 hide_ui_for_fullscreen = check_fullscreen && window_ && 1238 window_->IsFullscreen(); 1239#endif 1240 1241 unsigned int features = FEATURE_INFOBAR | FEATURE_SIDEBAR; 1242 1243#if !defined(OS_CHROMEOS) 1244 // Chrome OS opens a FileBrowse pop up instead of using download shelf. 1245 // So FEATURE_DOWNLOADSHELF is only added for non-chromeos platforms. 1246 features |= FEATURE_DOWNLOADSHELF; 1247#endif // !defined(OS_CHROMEOS) 1248 1249 if (type() == TYPE_NORMAL) { 1250 features |= FEATURE_BOOKMARKBAR; 1251 } 1252 1253 if (!hide_ui_for_fullscreen) { 1254 if (type() != TYPE_NORMAL) 1255 features |= FEATURE_TITLEBAR; 1256 1257 if (type() == TYPE_NORMAL) 1258 features |= FEATURE_TABSTRIP; 1259 1260 if (type() == TYPE_NORMAL) 1261 features |= FEATURE_TOOLBAR; 1262 1263 if ((type() & Browser::TYPE_APP) == 0) 1264 features |= FEATURE_LOCATIONBAR; 1265 } 1266 return !!(features & feature); 1267} 1268 1269bool Browser::IsClosingPermitted() { 1270 TabCloseableStateWatcher* watcher = 1271 g_browser_process->tab_closeable_state_watcher(); 1272 bool can_close = !watcher || watcher->CanCloseBrowser(this); 1273 if (!can_close && is_attempting_to_close_browser_) 1274 CancelWindowClose(); 1275 return can_close; 1276} 1277 1278void Browser::GoBack(WindowOpenDisposition disposition) { 1279 UserMetrics::RecordAction(UserMetricsAction("Back"), profile_); 1280 1281 TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper(); 1282 if (current_tab->controller().CanGoBack()) { 1283 TabContents* new_tab = GetOrCloneTabForDisposition(disposition); 1284 // If we are on an interstitial page and clone the tab, it won't be copied 1285 // to the new tab, so we don't need to go back. 1286 if (current_tab->tab_contents()->showing_interstitial_page() && 1287 (new_tab != current_tab->tab_contents())) 1288 return; 1289 new_tab->controller().GoBack(); 1290 } 1291} 1292 1293void Browser::GoForward(WindowOpenDisposition disposition) { 1294 UserMetrics::RecordAction(UserMetricsAction("Forward"), profile_); 1295 if (GetSelectedTabContentsWrapper()->controller().CanGoForward()) 1296 GetOrCloneTabForDisposition(disposition)->controller().GoForward(); 1297} 1298 1299void Browser::Reload(WindowOpenDisposition disposition) { 1300 UserMetrics::RecordAction(UserMetricsAction("Reload"), profile_); 1301 ReloadInternal(disposition, false); 1302} 1303 1304void Browser::ReloadIgnoringCache(WindowOpenDisposition disposition) { 1305 UserMetrics::RecordAction(UserMetricsAction("ReloadIgnoringCache"), profile_); 1306 ReloadInternal(disposition, true); 1307} 1308 1309void Browser::ReloadInternal(WindowOpenDisposition disposition, 1310 bool ignore_cache) { 1311 // If we are showing an interstitial, treat this as an OpenURL. 1312 TabContents* current_tab = GetSelectedTabContents(); 1313 if (current_tab && current_tab->showing_interstitial_page()) { 1314 NavigationEntry* entry = current_tab->controller().GetActiveEntry(); 1315 DCHECK(entry); // Should exist if interstitial is showing. 1316 OpenURL(entry->url(), GURL(), disposition, PageTransition::RELOAD); 1317 return; 1318 } 1319 1320 // As this is caused by a user action, give the focus to the page. 1321 TabContents* tab = GetOrCloneTabForDisposition(disposition); 1322 if (!tab->FocusLocationBarByDefault()) 1323 tab->Focus(); 1324 if (ignore_cache) 1325 tab->controller().ReloadIgnoringCache(true); 1326 else 1327 tab->controller().Reload(true); 1328} 1329 1330void Browser::Home(WindowOpenDisposition disposition) { 1331 UserMetrics::RecordAction(UserMetricsAction("Home"), profile_); 1332 OpenURL(GetHomePage(), GURL(), disposition, PageTransition::AUTO_BOOKMARK); 1333} 1334 1335void Browser::OpenCurrentURL() { 1336 UserMetrics::RecordAction(UserMetricsAction("LoadURL"), profile_); 1337 LocationBar* location_bar = window_->GetLocationBar(); 1338 if (!location_bar) 1339 return; 1340 1341 WindowOpenDisposition open_disposition = 1342 location_bar->GetWindowOpenDisposition(); 1343 if (OpenInstant(open_disposition)) 1344 return; 1345 1346 GURL url(WideToUTF8(location_bar->GetInputString())); 1347 1348 if (open_disposition == CURRENT_TAB && TabFinder::IsEnabled()) { 1349 Browser* existing_browser = NULL; 1350 TabContents* existing_tab = TabFinder::GetInstance()->FindTab( 1351 this, url, &existing_browser); 1352 if (existing_tab) { 1353 existing_browser->ActivateContents(existing_tab); 1354 return; 1355 } 1356 } 1357 1358 browser::NavigateParams params(this, url, location_bar->GetPageTransition()); 1359 params.disposition = open_disposition; 1360 // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least 1361 // inherit the opener. In some cases the tabstrip will determine the group 1362 // should be inherited, in which case the group is inherited instead of the 1363 // opener. 1364 params.tabstrip_add_types = 1365 TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER; 1366 browser::Navigate(¶ms); 1367 1368 DCHECK(profile_->GetExtensionService()); 1369 if (profile_->GetExtensionService()->IsInstalledApp(url)) { 1370 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, 1371 extension_misc::APP_LAUNCH_OMNIBOX_LOCATION, 1372 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); 1373 } 1374} 1375 1376void Browser::Stop() { 1377 UserMetrics::RecordAction(UserMetricsAction("Stop"), profile_); 1378 GetSelectedTabContentsWrapper()->tab_contents()->Stop(); 1379} 1380 1381void Browser::NewWindow() { 1382 if (browser_defaults::kAlwaysOpenIncognitoWindow && 1383 CommandLine::ForCurrentProcess()->HasSwitch(switches::kIncognito) && 1384 incognito_mode_allowed_.GetValue()) { 1385 NewIncognitoWindow(); 1386 return; 1387 } 1388 UserMetrics::RecordAction(UserMetricsAction("NewWindow"), profile_); 1389 SessionService* session_service = 1390 profile_->GetOriginalProfile()->GetSessionService(); 1391 if (!session_service || 1392 !session_service->RestoreIfNecessary(std::vector<GURL>())) { 1393 Browser::OpenEmptyWindow(profile_->GetOriginalProfile()); 1394 } 1395} 1396 1397void Browser::NewIncognitoWindow() { 1398 if (!incognito_mode_allowed_.GetValue()) { 1399 NewWindow(); 1400 return; 1401 } 1402 1403 UserMetrics::RecordAction(UserMetricsAction("NewIncognitoWindow"), profile_); 1404 Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile()); 1405} 1406 1407void Browser::CloseWindow() { 1408 UserMetrics::RecordAction(UserMetricsAction("CloseWindow"), profile_); 1409 window_->Close(); 1410} 1411 1412void Browser::NewTab() { 1413 UserMetrics::RecordAction(UserMetricsAction("NewTab"), profile_); 1414 1415 if (type() == TYPE_NORMAL) { 1416 AddBlankTab(true); 1417 GetSelectedTabContentsWrapper()->view()->RestoreFocus(); 1418 } else { 1419 Browser* b = GetOrCreateTabbedBrowser(profile_); 1420 b->AddBlankTab(true); 1421 b->window()->Show(); 1422 // The call to AddBlankTab above did not set the focus to the tab as its 1423 // window was not active, so we have to do it explicitly. 1424 // See http://crbug.com/6380. 1425 b->GetSelectedTabContentsWrapper()->view()->RestoreFocus(); 1426 } 1427} 1428 1429void Browser::CloseTab() { 1430 UserMetrics::RecordAction(UserMetricsAction("CloseTab_Accelerator"), 1431 profile_); 1432 if (CanCloseTab()) 1433 tab_handler_->GetTabStripModel()->CloseSelectedTabs(); 1434} 1435 1436void Browser::SelectNextTab() { 1437 UserMetrics::RecordAction(UserMetricsAction("SelectNextTab"), profile_); 1438 tab_handler_->GetTabStripModel()->SelectNextTab(); 1439} 1440 1441void Browser::SelectPreviousTab() { 1442 UserMetrics::RecordAction(UserMetricsAction("SelectPrevTab"), profile_); 1443 tab_handler_->GetTabStripModel()->SelectPreviousTab(); 1444} 1445 1446void Browser::OpenTabpose() { 1447#if defined(OS_MACOSX) 1448 if (!CommandLine::ForCurrentProcess()->HasSwitch( 1449 switches::kEnableExposeForTabs)) { 1450 return; 1451 } 1452 1453 UserMetrics::RecordAction(UserMetricsAction("OpenTabpose"), profile_); 1454 window()->OpenTabpose(); 1455#else 1456 NOTREACHED(); 1457#endif 1458} 1459 1460void Browser::MoveTabNext() { 1461 UserMetrics::RecordAction(UserMetricsAction("MoveTabNext"), profile_); 1462 tab_handler_->GetTabStripModel()->MoveTabNext(); 1463} 1464 1465void Browser::MoveTabPrevious() { 1466 UserMetrics::RecordAction(UserMetricsAction("MoveTabPrevious"), profile_); 1467 tab_handler_->GetTabStripModel()->MoveTabPrevious(); 1468} 1469 1470void Browser::SelectNumberedTab(int index) { 1471 if (index < tab_count()) { 1472 UserMetrics::RecordAction(UserMetricsAction("SelectNumberedTab"), 1473 profile_); 1474 tab_handler_->GetTabStripModel()->ActivateTabAt(index, true); 1475 } 1476} 1477 1478void Browser::SelectLastTab() { 1479 UserMetrics::RecordAction(UserMetricsAction("SelectLastTab"), profile_); 1480 tab_handler_->GetTabStripModel()->SelectLastTab(); 1481} 1482 1483void Browser::DuplicateTab() { 1484 UserMetrics::RecordAction(UserMetricsAction("Duplicate"), profile_); 1485 DuplicateContentsAt(active_index()); 1486} 1487 1488void Browser::RestoreTab() { 1489 UserMetrics::RecordAction(UserMetricsAction("RestoreTab"), profile_); 1490 TabRestoreService* service = profile_->GetTabRestoreService(); 1491 if (!service) 1492 return; 1493 1494 service->RestoreMostRecentEntry(tab_restore_service_delegate()); 1495} 1496 1497void Browser::WriteCurrentURLToClipboard() { 1498 // TODO(ericu): There isn't currently a metric for this. Should there be? 1499 // We don't appear to track the action when it comes from the 1500 // RenderContextViewMenu. 1501 1502 TabContents* contents = GetSelectedTabContents(); 1503 if (!contents->ShouldDisplayURL()) 1504 return; 1505 1506 chrome_browser_net::WriteURLToClipboard( 1507 contents->GetURL(), 1508 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), 1509 g_browser_process->clipboard()); 1510} 1511 1512void Browser::ConvertPopupToTabbedBrowser() { 1513 UserMetrics::RecordAction(UserMetricsAction("ShowAsTab"), profile_); 1514 int tab_strip_index = tab_handler_->GetTabStripModel()->active_index(); 1515 TabContentsWrapper* contents = 1516 tab_handler_->GetTabStripModel()->DetachTabContentsAt(tab_strip_index); 1517 Browser* browser = Browser::Create(profile_); 1518 browser->tabstrip_model()->AppendTabContents(contents, true); 1519 browser->window()->Show(); 1520} 1521 1522void Browser::ToggleFullscreenMode() { 1523#if !defined(OS_MACOSX) 1524 // In kiosk mode, we always want to be fullscreen. When the browser first 1525 // starts we're not yet fullscreen, so let the initial toggle go through. 1526 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode) && 1527 window_->IsFullscreen()) 1528 return; 1529#endif 1530 1531 UserMetrics::RecordAction(UserMetricsAction("ToggleFullscreen"), profile_); 1532 window_->SetFullscreen(!window_->IsFullscreen()); 1533 // On Linux, setting fullscreen mode is an async call to the X server, which 1534 // may or may not support fullscreen mode. 1535#if !defined(OS_LINUX) 1536 UpdateCommandsForFullscreenMode(window_->IsFullscreen()); 1537#endif 1538} 1539 1540#if defined(OS_CHROMEOS) 1541void Browser::Search() { 1542 // If the NTP is showing, close it. 1543 if (StartsWithASCII(GetSelectedTabContents()->GetURL().spec(), 1544 chrome::kChromeUINewTabURL, true)) { 1545 CloseTab(); 1546 return; 1547 } 1548 1549 // Exit fullscreen to show omnibox. 1550 if (window_->IsFullscreen()) { 1551 ToggleFullscreenMode(); 1552 // ToggleFullscreenMode is asynchronous, so we don't have omnibox 1553 // visible at this point. Wait for next event cycle which toggles 1554 // the visibility of omnibox before creating new tab. 1555 MessageLoop::current()->PostTask( 1556 FROM_HERE, method_factory_.NewRunnableMethod(&Browser::Search)); 1557 return; 1558 } 1559 1560 // Otherwise just open it. 1561 NewTab(); 1562} 1563 1564void Browser::ShowKeyboardOverlay() { 1565 window_->ShowKeyboardOverlay(window_->GetNativeHandle()); 1566} 1567#endif 1568 1569void Browser::Exit() { 1570 UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_); 1571#if defined(OS_CHROMEOS) 1572 chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutStarted", false); 1573 // Write /tmp/uptime-logout-started as well. 1574 const char kLogoutStarted[] = "logout-started"; 1575 chromeos::BootTimesLoader::Get()->RecordCurrentStats(kLogoutStarted); 1576 1577 // Login screen should show up in owner's locale. 1578 PrefService* state = g_browser_process->local_state(); 1579 if (state) { 1580 std::string owner_locale = state->GetString(prefs::kOwnerLocale); 1581 if (!owner_locale.empty() && 1582 state->GetString(prefs::kApplicationLocale) != owner_locale && 1583 !state->IsManagedPreference(prefs::kApplicationLocale)) { 1584 state->SetString(prefs::kApplicationLocale, owner_locale); 1585 state->ScheduleSavePersistentPrefs(); 1586 } 1587 } 1588#endif 1589 BrowserList::Exit(); 1590} 1591 1592void Browser::BookmarkCurrentPage() { 1593 UserMetrics::RecordAction(UserMetricsAction("Star"), profile_); 1594 1595 BookmarkModel* model = profile()->GetBookmarkModel(); 1596 if (!model || !model->IsLoaded()) 1597 return; // Ignore requests until bookmarks are loaded. 1598 1599 GURL url; 1600 string16 title; 1601 TabContents* tab = GetSelectedTabContents(); 1602 bookmark_utils::GetURLAndTitleToBookmark(tab, &url, &title); 1603 bool was_bookmarked = model->IsBookmarked(url); 1604 if (!was_bookmarked && profile_->IsOffTheRecord()) { 1605 // If we're incognito the favicon may not have been saved. Save it now 1606 // so that bookmarks have an icon for the page. 1607 tab->SaveFavicon(); 1608 } 1609 model->SetURLStarred(url, title, true); 1610 // Make sure the model actually added a bookmark before showing the star. A 1611 // bookmark isn't created if the url is invalid. 1612 if (window_->IsActive() && model->IsBookmarked(url)) { 1613 // Only show the bubble if the window is active, otherwise we may get into 1614 // weird situations were the bubble is deleted as soon as it is shown. 1615 window_->ShowBookmarkBubble(url, was_bookmarked); 1616 } 1617} 1618 1619void Browser::SavePage() { 1620 UserMetrics::RecordAction(UserMetricsAction("SavePage"), profile_); 1621 TabContents* current_tab = GetSelectedTabContents(); 1622 if (current_tab && current_tab->contents_mime_type() == "application/pdf") 1623 UserMetrics::RecordAction(UserMetricsAction("PDF.SavePage"), profile_); 1624 GetSelectedTabContentsWrapper()->download_tab_helper()->OnSavePage(); 1625} 1626 1627void Browser::ViewSelectedSource() { 1628 ViewSource(GetSelectedTabContentsWrapper()); 1629} 1630 1631void Browser::ShowFindBar() { 1632 GetFindBarController()->Show(); 1633} 1634 1635bool Browser::SupportsWindowFeature(WindowFeature feature) const { 1636 return SupportsWindowFeatureImpl(feature, true); 1637} 1638 1639bool Browser::CanSupportWindowFeature(WindowFeature feature) const { 1640 return SupportsWindowFeatureImpl(feature, false); 1641} 1642 1643void Browser::EmailPageLocation() { 1644 UserMetrics::RecordAction(UserMetricsAction("EmailPageLocation"), profile_); 1645 GetSelectedTabContents()->EmailPageLocation(); 1646} 1647 1648void Browser::Print() { 1649 UserMetrics::RecordAction(UserMetricsAction("PrintPreview"), profile_); 1650 if (CommandLine::ForCurrentProcess()->HasSwitch( 1651 switches::kEnablePrintPreview)) { 1652 printing::PrintPreviewTabController::PrintPreview( 1653 GetSelectedTabContents()); 1654 } else { 1655 GetSelectedTabContentsWrapper()->print_view_manager()->PrintNow(); 1656 } 1657} 1658 1659void Browser::ToggleEncodingAutoDetect() { 1660 UserMetrics::RecordAction(UserMetricsAction("AutoDetectChange"), profile_); 1661 encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue()); 1662 // If "auto detect" is turned on, then any current override encoding 1663 // is cleared. This also implicitly performs a reload. 1664 // OTOH, if "auto detect" is turned off, we don't change the currently 1665 // active encoding. 1666 if (encoding_auto_detect_.GetValue()) { 1667 TabContents* contents = GetSelectedTabContents(); 1668 if (contents) 1669 contents->ResetOverrideEncoding(); 1670 } 1671} 1672 1673void Browser::OverrideEncoding(int encoding_id) { 1674 UserMetrics::RecordAction(UserMetricsAction("OverrideEncoding"), profile_); 1675 const std::string selected_encoding = 1676 CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id); 1677 TabContents* contents = GetSelectedTabContents(); 1678 if (!selected_encoding.empty() && contents) 1679 contents->SetOverrideEncoding(selected_encoding); 1680 // Update the list of recently selected encodings. 1681 std::string new_selected_encoding_list; 1682 if (CharacterEncoding::UpdateRecentlySelectedEncoding( 1683 profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding), 1684 encoding_id, 1685 &new_selected_encoding_list)) { 1686 profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding, 1687 new_selected_encoding_list); 1688 } 1689} 1690 1691void Browser::Cut() { 1692 UserMetrics::RecordAction(UserMetricsAction("Cut"), profile_); 1693 window()->Cut(); 1694} 1695 1696void Browser::Copy() { 1697 UserMetrics::RecordAction(UserMetricsAction("Copy"), profile_); 1698 window()->Copy(); 1699} 1700 1701void Browser::Paste() { 1702 UserMetrics::RecordAction(UserMetricsAction("Paste"), profile_); 1703 window()->Paste(); 1704} 1705 1706void Browser::Find() { 1707 UserMetrics::RecordAction(UserMetricsAction("Find"), profile_); 1708 FindInPage(false, false); 1709} 1710 1711void Browser::FindNext() { 1712 UserMetrics::RecordAction(UserMetricsAction("FindNext"), profile_); 1713 FindInPage(true, true); 1714} 1715 1716void Browser::FindPrevious() { 1717 UserMetrics::RecordAction(UserMetricsAction("FindPrevious"), profile_); 1718 FindInPage(true, false); 1719} 1720 1721void Browser::Zoom(PageZoom::Function zoom_function) { 1722 static const UserMetricsAction kActions[] = { 1723 UserMetricsAction("ZoomMinus"), 1724 UserMetricsAction("ZoomNormal"), 1725 UserMetricsAction("ZoomPlus") 1726 }; 1727 1728 UserMetrics::RecordAction(kActions[zoom_function - PageZoom::ZOOM_OUT], 1729 profile_); 1730 TabContentsWrapper* tab_contents = GetSelectedTabContentsWrapper(); 1731 tab_contents->render_view_host()->Zoom(zoom_function); 1732} 1733 1734void Browser::FocusToolbar() { 1735 UserMetrics::RecordAction(UserMetricsAction("FocusToolbar"), profile_); 1736 window_->FocusToolbar(); 1737} 1738 1739void Browser::FocusAppMenu() { 1740 UserMetrics::RecordAction(UserMetricsAction("FocusAppMenu"), profile_); 1741 window_->FocusAppMenu(); 1742} 1743 1744void Browser::FocusLocationBar() { 1745 UserMetrics::RecordAction(UserMetricsAction("FocusLocation"), profile_); 1746 window_->SetFocusToLocationBar(true); 1747} 1748 1749void Browser::FocusBookmarksToolbar() { 1750 UserMetrics::RecordAction(UserMetricsAction("FocusBookmarksToolbar"), 1751 profile_); 1752 window_->FocusBookmarksToolbar(); 1753} 1754 1755void Browser::FocusChromeOSStatus() { 1756 UserMetrics::RecordAction(UserMetricsAction("FocusChromeOSStatus"), profile_); 1757 window_->FocusChromeOSStatus(); 1758} 1759 1760void Browser::FocusNextPane() { 1761 UserMetrics::RecordAction(UserMetricsAction("FocusNextPane"), profile_); 1762 window_->RotatePaneFocus(true); 1763} 1764 1765void Browser::FocusPreviousPane() { 1766 UserMetrics::RecordAction(UserMetricsAction("FocusPreviousPane"), profile_); 1767 window_->RotatePaneFocus(false); 1768} 1769 1770void Browser::FocusSearch() { 1771 // TODO(beng): replace this with FocusLocationBar 1772 UserMetrics::RecordAction(UserMetricsAction("FocusSearch"), profile_); 1773 window_->GetLocationBar()->FocusSearch(); 1774} 1775 1776void Browser::OpenFile() { 1777 UserMetrics::RecordAction(UserMetricsAction("OpenFile"), profile_); 1778#if defined(OS_CHROMEOS) && !defined(FILE_MANAGER_EXTENSION) 1779 FileBrowseUI::OpenPopup(profile_, 1780 "", 1781 FileBrowseUI::kPopupWidth, 1782 FileBrowseUI::kPopupHeight); 1783#else 1784 if (!select_file_dialog_.get()) 1785 select_file_dialog_ = SelectFileDialog::Create(this); 1786 1787 const FilePath directory = profile_->last_selected_directory(); 1788 1789 // TODO(beng): figure out how to juggle this. 1790 gfx::NativeWindow parent_window = window_->GetNativeHandle(); 1791 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE, 1792 string16(), directory, 1793 NULL, 0, FILE_PATH_LITERAL(""), 1794 GetSelectedTabContents(), 1795 parent_window, NULL); 1796#endif 1797} 1798 1799void Browser::OpenCreateShortcutsDialog() { 1800 UserMetrics::RecordAction(UserMetricsAction("CreateShortcut"), profile_); 1801#if defined(OS_WIN) || defined(OS_LINUX) 1802 TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper(); 1803 DCHECK(current_tab && 1804 web_app::IsValidUrl(current_tab->tab_contents()->GetURL())) << 1805 "Menu item should be disabled."; 1806 1807 NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry(); 1808 if (!entry) 1809 return; 1810 1811 // RVH's GetApplicationInfo should not be called before it returns. 1812 DCHECK(pending_web_app_action_ == NONE); 1813 pending_web_app_action_ = CREATE_SHORTCUT; 1814 1815 // Start fetching web app info for CreateApplicationShortcut dialog and show 1816 // the dialog when the data is available in OnDidGetApplicationInfo. 1817 current_tab->extension_tab_helper()->GetApplicationInfo(entry->page_id()); 1818#else 1819 NOTIMPLEMENTED(); 1820#endif 1821} 1822 1823void Browser::ToggleDevToolsWindow(DevToolsToggleAction action) { 1824 std::string uma_string; 1825 switch (action) { 1826 case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE: 1827 uma_string = "DevTools_ToggleConsole"; 1828 break; 1829 case DEVTOOLS_TOGGLE_ACTION_NONE: 1830 case DEVTOOLS_TOGGLE_ACTION_INSPECT: 1831 default: 1832 uma_string = "DevTools_ToggleWindow"; 1833 break; 1834 } 1835 UserMetrics::RecordAction(UserMetricsAction(uma_string.c_str()), profile_); 1836 DevToolsManager::GetInstance()->ToggleDevToolsWindow( 1837 GetSelectedTabContentsWrapper()->render_view_host(), action); 1838} 1839 1840void Browser::OpenTaskManager(bool highlight_background_resources) { 1841 UserMetrics::RecordAction(UserMetricsAction("TaskManager"), profile_); 1842 if (highlight_background_resources) 1843 window_->ShowBackgroundPages(); 1844 else 1845 window_->ShowTaskManager(); 1846} 1847 1848void Browser::OpenBugReportDialog() { 1849 UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_); 1850 browser::ShowHtmlBugReportView(this); 1851} 1852 1853void Browser::ToggleBookmarkBar() { 1854 UserMetrics::RecordAction(UserMetricsAction("ShowBookmarksBar"), profile_); 1855 window_->ToggleBookmarkBar(); 1856} 1857 1858void Browser::OpenBookmarkManager() { 1859 UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"), profile_); 1860 ShowBookmarkManagerTab(); 1861} 1862 1863void Browser::ShowAppMenu() { 1864 // We record the user metric for this event in WrenchMenu::RunMenu. 1865 window_->ShowAppMenu(); 1866} 1867 1868void Browser::ShowBookmarkManagerTab() { 1869 UserMetrics::RecordAction(UserMetricsAction("ShowBookmarks"), profile_); 1870 ShowSingletonTab(GURL(chrome::kChromeUIBookmarksURL)); 1871} 1872 1873void Browser::ShowHistoryTab() { 1874 UserMetrics::RecordAction(UserMetricsAction("ShowHistory"), profile_); 1875 ShowSingletonTab(GURL(chrome::kChromeUIHistoryURL)); 1876} 1877 1878void Browser::ShowDownloadsTab() { 1879 UserMetrics::RecordAction(UserMetricsAction("ShowDownloads"), profile_); 1880 if (window()) { 1881 DownloadShelf* shelf = window()->GetDownloadShelf(); 1882 if (shelf->IsShowing()) 1883 shelf->Close(); 1884 } 1885 ShowSingletonTab(GURL(chrome::kChromeUIDownloadsURL)); 1886} 1887 1888void Browser::ShowExtensionsTab() { 1889 UserMetrics::RecordAction(UserMetricsAction("ShowExtensions"), profile_); 1890 ShowSingletonTab(GURL(chrome::kChromeUIExtensionsURL)); 1891} 1892 1893void Browser::ShowAboutConflictsTab() { 1894 UserMetrics::RecordAction(UserMetricsAction("AboutConflicts"), profile_); 1895 ShowSingletonTab(GURL(chrome::kChromeUIConflictsURL)); 1896} 1897 1898void Browser::ShowBrokenPageTab(TabContents* contents) { 1899 UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_); 1900 string16 page_title = contents->GetTitle(); 1901 NavigationEntry* entry = contents->controller().GetActiveEntry(); 1902 if (!entry) 1903 return; 1904 std::string page_url = entry->url().spec(); 1905 std::vector<std::string> subst; 1906 subst.push_back(UTF16ToASCII(page_title)); 1907 subst.push_back(page_url); 1908 std::string report_page_url = 1909 ReplaceStringPlaceholders(kBrokenPageUrl, subst, NULL); 1910 ShowSingletonTab(GURL(report_page_url)); 1911} 1912 1913void Browser::ShowOptionsTab(const std::string& sub_page) { 1914 GURL url(chrome::kChromeUISettingsURL + sub_page); 1915 browser::NavigateParams params(GetSingletonTabNavigateParams(url)); 1916 params.path_behavior = browser::NavigateParams::IGNORE_AND_NAVIGATE; 1917 browser::Navigate(¶ms); 1918} 1919 1920void Browser::OpenClearBrowsingDataDialog() { 1921 UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_ShowDlg"), 1922 profile_); 1923 ShowOptionsTab(chrome::kClearBrowserDataSubPage); 1924} 1925 1926void Browser::OpenOptionsDialog() { 1927 UserMetrics::RecordAction(UserMetricsAction("ShowOptions"), profile_); 1928 GURL url(chrome::kChromeUISettingsURL); 1929 browser::NavigateParams params(GetSingletonTabNavigateParams(url)); 1930 params.path_behavior = browser::NavigateParams::IGNORE_AND_STAY_PUT; 1931 browser::Navigate(¶ms); 1932} 1933 1934void Browser::OpenPasswordManager() { 1935 UserMetrics::RecordAction(UserMetricsAction("Options_ShowPasswordManager"), 1936 profile_); 1937 ShowOptionsTab(chrome::kPasswordManagerSubPage); 1938} 1939 1940void Browser::OpenImportSettingsDialog() { 1941 UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg"), profile_); 1942 ShowOptionsTab(chrome::kImportDataSubPage); 1943} 1944 1945void Browser::OpenInstantConfirmDialog() { 1946 ShowOptionsTab(chrome::kInstantConfirmPage); 1947} 1948 1949void Browser::OpenSyncMyBookmarksDialog() { 1950 sync_ui_util::OpenSyncMyBookmarksDialog( 1951 profile_, this, ProfileSyncService::START_FROM_WRENCH); 1952} 1953 1954void Browser::OpenAboutChromeDialog() { 1955 UserMetrics::RecordAction(UserMetricsAction("AboutChrome"), profile_); 1956#if defined(OS_CHROMEOS) 1957 ShowSingletonTab(GURL(chrome::kChromeUIAboutURL)); 1958#else 1959 window_->ShowAboutChromeDialog(); 1960#endif 1961} 1962 1963void Browser::OpenUpdateChromeDialog() { 1964 UserMetrics::RecordAction(UserMetricsAction("UpdateChrome"), profile_); 1965 window_->ShowUpdateChromeDialog(); 1966} 1967 1968void Browser::OpenHelpTab() { 1969 GURL help_url(kHelpContentUrl); 1970 GURL localized_help_url = google_util::AppendGoogleLocaleParam(help_url); 1971 AddSelectedTabWithURL(localized_help_url, PageTransition::AUTO_BOOKMARK); 1972} 1973 1974void Browser::OpenThemeGalleryTabAndActivate() { 1975 AddSelectedTabWithURL(GURL(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)), 1976 PageTransition::LINK); 1977} 1978 1979void Browser::OpenPrivacyDashboardTabAndActivate() { 1980 OpenURL(GURL(kPrivacyDashboardUrl), GURL(), 1981 NEW_FOREGROUND_TAB, PageTransition::LINK); 1982 window_->Activate(); 1983} 1984 1985void Browser::OpenAutofillHelpTabAndActivate() { 1986 GURL help_url = google_util::AppendGoogleLocaleParam(GURL(kAutofillHelpUrl)); 1987 AddSelectedTabWithURL(help_url, PageTransition::LINK); 1988} 1989 1990void Browser::OpenSearchEngineOptionsDialog() { 1991 UserMetrics::RecordAction(UserMetricsAction("EditSearchEngines"), profile_); 1992 ShowOptionsTab(chrome::kSearchEnginesSubPage); 1993} 1994 1995#if defined(OS_CHROMEOS) 1996void Browser::OpenFileManager() { 1997 UserMetrics::RecordAction(UserMetricsAction("OpenFileManager")); 1998 ShowSingletonTab(FileManagerUtil::GetFileBrowserUrl()); 1999} 2000 2001void Browser::OpenSystemOptionsDialog() { 2002 UserMetrics::RecordAction(UserMetricsAction("OpenSystemOptionsDialog"), 2003 profile_); 2004 ShowOptionsTab(chrome::kSystemOptionsSubPage); 2005} 2006 2007void Browser::OpenInternetOptionsDialog() { 2008 UserMetrics::RecordAction(UserMetricsAction("OpenInternetOptionsDialog"), 2009 profile_); 2010 ShowOptionsTab(chrome::kInternetOptionsSubPage); 2011} 2012 2013void Browser::OpenLanguageOptionsDialog() { 2014 UserMetrics::RecordAction(UserMetricsAction("OpenLanguageOptionsDialog"), 2015 profile_); 2016 ShowOptionsTab(chrome::kLanguageOptionsSubPage); 2017} 2018 2019void Browser::OpenSystemTabAndActivate() { 2020 OpenURL(GURL(chrome::kChromeUISystemInfoURL), GURL(), 2021 NEW_FOREGROUND_TAB, PageTransition::LINK); 2022 window_->Activate(); 2023} 2024 2025void Browser::OpenMobilePlanTabAndActivate() { 2026 OpenURL(GURL(chrome::kChromeUIMobileSetupURL), GURL(), 2027 NEW_FOREGROUND_TAB, PageTransition::LINK); 2028 window_->Activate(); 2029} 2030#endif 2031 2032void Browser::OpenPluginsTabAndActivate() { 2033 OpenURL(GURL(chrome::kAboutPluginsURL), GURL(), 2034 NEW_FOREGROUND_TAB, PageTransition::LINK); 2035 window_->Activate(); 2036} 2037 2038/////////////////////////////////////////////////////////////////////////////// 2039 2040// static 2041void Browser::SetNewHomePagePrefs(PrefService* prefs) { 2042 const PrefService::Preference* home_page_pref = 2043 prefs->FindPreference(prefs::kHomePage); 2044 if (home_page_pref && 2045 !home_page_pref->IsManaged() && 2046 !prefs->HasPrefPath(prefs::kHomePage)) { 2047 prefs->SetString(prefs::kHomePage, 2048 GoogleURLTracker::kDefaultGoogleHomepage); 2049 } 2050 const PrefService::Preference* home_page_is_new_tab_page_pref = 2051 prefs->FindPreference(prefs::kHomePageIsNewTabPage); 2052 if (home_page_is_new_tab_page_pref && 2053 !home_page_is_new_tab_page_pref->IsManaged() && 2054 !prefs->HasPrefPath(prefs::kHomePageIsNewTabPage)) 2055 prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false); 2056} 2057 2058// static 2059void Browser::RegisterPrefs(PrefService* prefs) { 2060 prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0); 2061 prefs->RegisterIntegerPref(prefs::kExtensionSidebarWidth, -1); 2062 prefs->RegisterIntegerPref(prefs::kMultipleProfilePrefMigration, 0); 2063 prefs->RegisterBooleanPref(prefs::kAllowFileSelectionDialogs, true); 2064 // Educated guess: Chrome has a bundled Flash version supporting 2065 // clearing LSO data, Chromium hasn't. 2066#if defined(GOOGLE_CHROME_BUILD) 2067 prefs->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, true); 2068#else 2069 prefs->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, false); 2070#endif 2071} 2072 2073// static 2074void Browser::RegisterUserPrefs(PrefService* prefs) { 2075 prefs->RegisterStringPref(prefs::kHomePage, 2076 chrome::kChromeUINewTabURL); 2077 prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true); 2078 prefs->RegisterBooleanPref(prefs::kShowHomeButton, false); 2079#if defined(OS_MACOSX) 2080 // This really belongs in platform code, but there's no good place to 2081 // initialize it between the time when the AppController is created 2082 // (where there's no profile) and the time the controller gets another 2083 // crack at the start of the main event loop. By that time, BrowserInit 2084 // has already created the browser window, and it's too late: we need the 2085 // pref to be already initialized. Doing it here also saves us from having 2086 // to hard-code pref registration in the several unit tests that use 2087 // this preference. 2088 prefs->RegisterBooleanPref(prefs::kConfirmToQuitEnabled, false); 2089 prefs->RegisterBooleanPref(prefs::kShowUpdatePromotionInfoBar, true); 2090#endif 2091 prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true); 2092 prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true); 2093 prefs->RegisterBooleanPref(prefs::kDeleteCache, true); 2094 prefs->RegisterBooleanPref(prefs::kDeleteCookies, true); 2095 prefs->RegisterBooleanPref(prefs::kDeletePasswords, false); 2096 prefs->RegisterBooleanPref(prefs::kDeleteFormData, false); 2097 prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0); 2098 prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true); 2099 prefs->RegisterBooleanPref(prefs::kShowOmniboxSearchHint, true); 2100 prefs->RegisterBooleanPref(prefs::kWebAppCreateOnDesktop, true); 2101 prefs->RegisterBooleanPref(prefs::kWebAppCreateInAppsMenu, true); 2102 prefs->RegisterBooleanPref(prefs::kWebAppCreateInQuickLaunchBar, true); 2103 prefs->RegisterBooleanPref(prefs::kUseVerticalTabs, false); 2104 prefs->RegisterBooleanPref(prefs::kEnableTranslate, true); 2105 prefs->RegisterBooleanPref(prefs::kEnableBookmarkBar, true); 2106 prefs->RegisterBooleanPref(prefs::kRemotingHasSetupCompleted, false); 2107 prefs->RegisterStringPref(prefs::kCloudPrintEmail, std::string()); 2108 prefs->RegisterBooleanPref(prefs::kCloudPrintProxyEnabled, true); 2109 prefs->RegisterBooleanPref(prefs::kDevToolsDisabled, false); 2110 prefs->RegisterBooleanPref(prefs::kIncognitoEnabled, true); 2111 prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, -1); 2112 prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement); 2113 prefs->RegisterDictionaryPref(prefs::kPreferencesWindowPlacement); 2114 // We need to register the type of these preferences in order to query 2115 // them even though they're typically only controlled via policy or command 2116 // line switches. 2117 prefs->RegisterBooleanPref(prefs::kDisable3DAPIs, false); 2118 prefs->RegisterBooleanPref(prefs::kPluginsAllowOutdated, false); 2119 prefs->RegisterBooleanPref(prefs::kEnableHyperlinkAuditing, true); 2120 prefs->RegisterBooleanPref(prefs::kEnableReferrers, true); 2121} 2122 2123// static 2124bool Browser::RunUnloadEventsHelper(TabContents* contents) { 2125 // If the TabContents is not connected yet, then there's no unload 2126 // handler we can fire even if the TabContents has an unload listener. 2127 // One case where we hit this is in a tab that has an infinite loop 2128 // before load. 2129 if (contents->NeedToFireBeforeUnload()) { 2130 // If the page has unload listeners, then we tell the renderer to fire 2131 // them. Once they have fired, we'll get a message back saying whether 2132 // to proceed closing the page or not, which sends us back to this method 2133 // with the NeedToFireBeforeUnload bit cleared. 2134 contents->render_view_host()->FirePageBeforeUnload(false); 2135 return true; 2136 } 2137 return false; 2138} 2139 2140// static 2141Browser* Browser::GetBrowserForController( 2142 const NavigationController* controller, int* index_result) { 2143 BrowserList::const_iterator it; 2144 for (it = BrowserList::begin(); it != BrowserList::end(); ++it) { 2145 int index = (*it)->tab_handler_->GetTabStripModel()->GetIndexOfController( 2146 controller); 2147 if (index != TabStripModel::kNoTab) { 2148 if (index_result) 2149 *index_result = index; 2150 return *it; 2151 } 2152 } 2153 2154 return NULL; 2155} 2156 2157void Browser::ExecuteCommandWithDisposition( 2158 int id, WindowOpenDisposition disposition) { 2159 // No commands are enabled if there is not yet any selected tab. 2160 // TODO(pkasting): It seems like we should not need this, because either 2161 // most/all commands should not have been enabled yet anyway or the ones that 2162 // are enabled should be global, or safe themselves against having no selected 2163 // tab. However, Ben says he tried removing this before and got lots of 2164 // crashes, e.g. from Windows sending WM_COMMANDs at random times during 2165 // window construction. This probably could use closer examination someday. 2166 if (!GetSelectedTabContentsWrapper()) 2167 return; 2168 2169 DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command " 2170 << id; 2171 2172 // If command execution is blocked then just record the command and return. 2173 if (block_command_execution_) { 2174 // We actually only allow no more than one blocked command, otherwise some 2175 // commands maybe lost. 2176 DCHECK_EQ(last_blocked_command_id_, -1); 2177 last_blocked_command_id_ = id; 2178 last_blocked_command_disposition_ = disposition; 2179 return; 2180 } 2181 2182 // The order of commands in this switch statement must match the function 2183 // declaration order in browser.h! 2184 switch (id) { 2185 // Navigation commands 2186 case IDC_BACK: GoBack(disposition); break; 2187 case IDC_FORWARD: GoForward(disposition); break; 2188 case IDC_RELOAD: Reload(disposition); break; 2189 case IDC_RELOAD_IGNORING_CACHE: ReloadIgnoringCache(disposition); break; 2190 case IDC_HOME: Home(disposition); break; 2191 case IDC_OPEN_CURRENT_URL: OpenCurrentURL(); break; 2192 case IDC_STOP: Stop(); break; 2193 2194 // Window management commands 2195 case IDC_NEW_WINDOW: NewWindow(); break; 2196 case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(); break; 2197 case IDC_CLOSE_WINDOW: CloseWindow(); break; 2198 case IDC_NEW_TAB: NewTab(); break; 2199 case IDC_CLOSE_TAB: CloseTab(); break; 2200 case IDC_SELECT_NEXT_TAB: SelectNextTab(); break; 2201 case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break; 2202 case IDC_TABPOSE: OpenTabpose(); break; 2203 case IDC_MOVE_TAB_NEXT: MoveTabNext(); break; 2204 case IDC_MOVE_TAB_PREVIOUS: MoveTabPrevious(); break; 2205 case IDC_SELECT_TAB_0: 2206 case IDC_SELECT_TAB_1: 2207 case IDC_SELECT_TAB_2: 2208 case IDC_SELECT_TAB_3: 2209 case IDC_SELECT_TAB_4: 2210 case IDC_SELECT_TAB_5: 2211 case IDC_SELECT_TAB_6: 2212 case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0); 2213 break; 2214 case IDC_SELECT_LAST_TAB: SelectLastTab(); break; 2215 case IDC_DUPLICATE_TAB: DuplicateTab(); break; 2216 case IDC_RESTORE_TAB: RestoreTab(); break; 2217 case IDC_COPY_URL: WriteCurrentURLToClipboard(); break; 2218 case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break; 2219 case IDC_FULLSCREEN: ToggleFullscreenMode(); break; 2220 case IDC_EXIT: Exit(); break; 2221 case IDC_TOGGLE_VERTICAL_TABS: ToggleUseVerticalTabs(); break; 2222#if defined(OS_CHROMEOS) 2223 case IDC_SEARCH: Search(); break; 2224 case IDC_SHOW_KEYBOARD_OVERLAY: ShowKeyboardOverlay(); break; 2225#endif 2226 2227 // Page-related commands 2228 case IDC_SAVE_PAGE: SavePage(); break; 2229 case IDC_BOOKMARK_PAGE: BookmarkCurrentPage(); break; 2230 case IDC_BOOKMARK_ALL_TABS: BookmarkAllTabs(); break; 2231 case IDC_VIEW_SOURCE: ViewSelectedSource(); break; 2232 case IDC_EMAIL_PAGE_LOCATION: EmailPageLocation(); break; 2233 case IDC_PRINT: Print(); break; 2234 case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break; 2235 case IDC_ENCODING_UTF8: 2236 case IDC_ENCODING_UTF16LE: 2237 case IDC_ENCODING_ISO88591: 2238 case IDC_ENCODING_WINDOWS1252: 2239 case IDC_ENCODING_GBK: 2240 case IDC_ENCODING_GB18030: 2241 case IDC_ENCODING_BIG5HKSCS: 2242 case IDC_ENCODING_BIG5: 2243 case IDC_ENCODING_KOREAN: 2244 case IDC_ENCODING_SHIFTJIS: 2245 case IDC_ENCODING_ISO2022JP: 2246 case IDC_ENCODING_EUCJP: 2247 case IDC_ENCODING_THAI: 2248 case IDC_ENCODING_ISO885915: 2249 case IDC_ENCODING_MACINTOSH: 2250 case IDC_ENCODING_ISO88592: 2251 case IDC_ENCODING_WINDOWS1250: 2252 case IDC_ENCODING_ISO88595: 2253 case IDC_ENCODING_WINDOWS1251: 2254 case IDC_ENCODING_KOI8R: 2255 case IDC_ENCODING_KOI8U: 2256 case IDC_ENCODING_ISO88597: 2257 case IDC_ENCODING_WINDOWS1253: 2258 case IDC_ENCODING_ISO88594: 2259 case IDC_ENCODING_ISO885913: 2260 case IDC_ENCODING_WINDOWS1257: 2261 case IDC_ENCODING_ISO88593: 2262 case IDC_ENCODING_ISO885910: 2263 case IDC_ENCODING_ISO885914: 2264 case IDC_ENCODING_ISO885916: 2265 case IDC_ENCODING_WINDOWS1254: 2266 case IDC_ENCODING_ISO88596: 2267 case IDC_ENCODING_WINDOWS1256: 2268 case IDC_ENCODING_ISO88598: 2269 case IDC_ENCODING_ISO88598I: 2270 case IDC_ENCODING_WINDOWS1255: 2271 case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break; 2272 2273 // Clipboard commands 2274 case IDC_CUT: Cut(); break; 2275 case IDC_COPY: Copy(); break; 2276 case IDC_PASTE: Paste(); break; 2277 2278 // Find-in-page 2279 case IDC_FIND: Find(); break; 2280 case IDC_FIND_NEXT: FindNext(); break; 2281 case IDC_FIND_PREVIOUS: FindPrevious(); break; 2282 2283 // Zoom 2284 case IDC_ZOOM_PLUS: Zoom(PageZoom::ZOOM_IN); break; 2285 case IDC_ZOOM_NORMAL: Zoom(PageZoom::RESET); break; 2286 case IDC_ZOOM_MINUS: Zoom(PageZoom::ZOOM_OUT); break; 2287 2288 // Focus various bits of UI 2289 case IDC_FOCUS_TOOLBAR: FocusToolbar(); break; 2290 case IDC_FOCUS_LOCATION: FocusLocationBar(); break; 2291 case IDC_FOCUS_SEARCH: FocusSearch(); break; 2292 case IDC_FOCUS_MENU_BAR: FocusAppMenu(); break; 2293 case IDC_FOCUS_BOOKMARKS: FocusBookmarksToolbar(); break; 2294 case IDC_FOCUS_CHROMEOS_STATUS: FocusChromeOSStatus(); break; 2295 case IDC_FOCUS_NEXT_PANE: FocusNextPane(); break; 2296 case IDC_FOCUS_PREVIOUS_PANE: FocusPreviousPane(); break; 2297 2298 // Show various bits of UI 2299 case IDC_OPEN_FILE: OpenFile(); break; 2300 case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break; 2301 case IDC_DEV_TOOLS: ToggleDevToolsWindow( 2302 DEVTOOLS_TOGGLE_ACTION_NONE); 2303 break; 2304 case IDC_DEV_TOOLS_CONSOLE: ToggleDevToolsWindow( 2305 DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE); 2306 break; 2307 case IDC_DEV_TOOLS_INSPECT: ToggleDevToolsWindow( 2308 DEVTOOLS_TOGGLE_ACTION_INSPECT); 2309 break; 2310 case IDC_TASK_MANAGER: OpenTaskManager(false); break; 2311 case IDC_VIEW_BACKGROUND_PAGES: OpenTaskManager(true); break; 2312 case IDC_FEEDBACK: OpenBugReportDialog(); break; 2313 2314 case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break; 2315 case IDC_PROFILING_ENABLED: Profiling::Toggle(); break; 2316 2317 case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break; 2318 case IDC_SHOW_APP_MENU: ShowAppMenu(); break; 2319 case IDC_SHOW_HISTORY: ShowHistoryTab(); break; 2320 case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break; 2321 case IDC_MANAGE_EXTENSIONS: ShowExtensionsTab(); break; 2322 case IDC_SYNC_BOOKMARKS: OpenSyncMyBookmarksDialog(); break; 2323 case IDC_OPTIONS: OpenOptionsDialog(); break; 2324 case IDC_EDIT_SEARCH_ENGINES: OpenSearchEngineOptionsDialog(); break; 2325 case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break; 2326 case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break; 2327 case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break; 2328 case IDC_ABOUT: OpenAboutChromeDialog(); break; 2329 case IDC_UPGRADE_DIALOG: OpenUpdateChromeDialog(); break; 2330 case IDC_VIEW_INCOMPATIBILITIES: ShowAboutConflictsTab(); break; 2331 case IDC_HELP_PAGE: OpenHelpTab(); break; 2332#if defined(OS_CHROMEOS) 2333 case IDC_FILE_MANAGER: OpenFileManager(); break; 2334 case IDC_SYSTEM_OPTIONS: OpenSystemOptionsDialog(); break; 2335 case IDC_INTERNET_OPTIONS: OpenInternetOptionsDialog(); break; 2336 case IDC_LANGUAGE_OPTIONS: OpenLanguageOptionsDialog(); break; 2337#endif 2338 2339 default: 2340 LOG(WARNING) << "Received Unimplemented Command: " << id; 2341 break; 2342 } 2343} 2344 2345bool Browser::ExecuteCommandIfEnabled(int id) { 2346 if (command_updater_.SupportsCommand(id) && 2347 command_updater_.IsCommandEnabled(id)) { 2348 ExecuteCommand(id); 2349 return true; 2350 } 2351 return false; 2352} 2353 2354bool Browser::IsReservedCommandOrKey(int command_id, 2355 const NativeWebKeyboardEvent& event) { 2356#if defined(OS_CHROMEOS) 2357 // Chrome OS's top row of keys produces F1-10. Make sure that web pages 2358 // aren't able to block Chrome from performing the standard actions for F1-F4 2359 // (F5-7 are grabbed by other X clients and hence don't need this protection, 2360 // and F8-10 are handled separately in Chrome via a GDK event filter, but 2361 // let's future-proof this). 2362 ui::KeyboardCode key_code = 2363 static_cast<ui::KeyboardCode>(event.windowsKeyCode); 2364 if (key_code == ui::VKEY_F1 || 2365 key_code == ui::VKEY_F2 || 2366 key_code == ui::VKEY_F3 || 2367 key_code == ui::VKEY_F4 || 2368 key_code == ui::VKEY_F5 || 2369 key_code == ui::VKEY_F6 || 2370 key_code == ui::VKEY_F7 || 2371 key_code == ui::VKEY_F8 || 2372 key_code == ui::VKEY_F9 || 2373 key_code == ui::VKEY_F10) { 2374 return true; 2375 } 2376#endif 2377 2378 return command_id == IDC_CLOSE_TAB || 2379 command_id == IDC_CLOSE_WINDOW || 2380 command_id == IDC_NEW_INCOGNITO_WINDOW || 2381 command_id == IDC_NEW_TAB || 2382 command_id == IDC_NEW_WINDOW || 2383 command_id == IDC_RESTORE_TAB || 2384 command_id == IDC_SELECT_NEXT_TAB || 2385 command_id == IDC_SELECT_PREVIOUS_TAB || 2386 command_id == IDC_TABPOSE || 2387 command_id == IDC_EXIT || 2388 command_id == IDC_SEARCH; 2389} 2390 2391void Browser::SetBlockCommandExecution(bool block) { 2392 block_command_execution_ = block; 2393 if (block) { 2394 last_blocked_command_id_ = -1; 2395 last_blocked_command_disposition_ = CURRENT_TAB; 2396 } 2397} 2398 2399int Browser::GetLastBlockedCommand(WindowOpenDisposition* disposition) { 2400 if (disposition) 2401 *disposition = last_blocked_command_disposition_; 2402 return last_blocked_command_id_; 2403} 2404 2405void Browser::UpdateUIForNavigationInTab(TabContentsWrapper* contents, 2406 PageTransition::Type transition, 2407 bool user_initiated) { 2408 tabstrip_model()->TabNavigating(contents, transition); 2409 2410 bool contents_is_selected = contents == GetSelectedTabContentsWrapper(); 2411 if (user_initiated && contents_is_selected && window()->GetLocationBar()) { 2412 // Forcibly reset the location bar if the url is going to change in the 2413 // current tab, since otherwise it won't discard any ongoing user edits, 2414 // since it doesn't realize this is a user-initiated action. 2415 window()->GetLocationBar()->Revert(); 2416 } 2417 2418 if (GetStatusBubble()) 2419 GetStatusBubble()->Hide(); 2420 2421 // Update the location bar. This is synchronous. We specifically don't 2422 // update the load state since the load hasn't started yet and updating it 2423 // will put it out of sync with the actual state like whether we're 2424 // displaying a favicon, which controls the throbber. If we updated it here, 2425 // the throbber will show the default favicon for a split second when 2426 // navigating away from the new tab page. 2427 ScheduleUIUpdate(contents->tab_contents(), TabContents::INVALIDATE_URL); 2428 2429 if (contents_is_selected) 2430 contents->tab_contents()->Focus(); 2431} 2432 2433GURL Browser::GetHomePage() const { 2434 // --homepage overrides any preferences. 2435 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 2436 if (command_line.HasSwitch(switches::kHomePage)) { 2437 // TODO(evanm): clean up usage of DIR_CURRENT. 2438 // http://code.google.com/p/chromium/issues/detail?id=60630 2439 // For now, allow this code to call getcwd(). 2440 base::ThreadRestrictions::ScopedAllowIO allow_io; 2441 2442 FilePath browser_directory; 2443 PathService::Get(base::DIR_CURRENT, &browser_directory); 2444 GURL home_page(URLFixerUpper::FixupRelativeFile(browser_directory, 2445 command_line.GetSwitchValuePath(switches::kHomePage))); 2446 if (home_page.is_valid()) 2447 return home_page; 2448 } 2449 2450 if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage)) 2451 return GURL(chrome::kChromeUINewTabURL); 2452 GURL home_page(URLFixerUpper::FixupURL( 2453 profile_->GetPrefs()->GetString(prefs::kHomePage), 2454 std::string())); 2455 if (!home_page.is_valid()) 2456 return GURL(chrome::kChromeUINewTabURL); 2457 return home_page; 2458} 2459 2460/////////////////////////////////////////////////////////////////////////////// 2461// Browser, PageNavigator implementation: 2462 2463void Browser::OpenURL(const GURL& url, const GURL& referrer, 2464 WindowOpenDisposition disposition, 2465 PageTransition::Type transition) { 2466 OpenURLFromTab(NULL, url, referrer, disposition, transition); 2467} 2468 2469/////////////////////////////////////////////////////////////////////////////// 2470// Browser, CommandUpdater::CommandUpdaterDelegate implementation: 2471 2472void Browser::ExecuteCommand(int id) { 2473 ExecuteCommandWithDisposition(id, CURRENT_TAB); 2474} 2475 2476/////////////////////////////////////////////////////////////////////////////// 2477// Browser, TabHandlerDelegate implementation: 2478 2479Profile* Browser::GetProfile() const { 2480 return profile(); 2481} 2482 2483Browser* Browser::AsBrowser() { 2484 return this; 2485} 2486 2487/////////////////////////////////////////////////////////////////////////////// 2488// Browser, TabStripModelDelegate implementation: 2489 2490TabContentsWrapper* Browser::AddBlankTab(bool foreground) { 2491 return AddBlankTabAt(-1, foreground); 2492} 2493 2494TabContentsWrapper* Browser::AddBlankTabAt(int index, bool foreground) { 2495 // Time new tab page creation time. We keep track of the timing data in 2496 // TabContents, but we want to include the time it takes to create the 2497 // TabContents object too. 2498 base::TimeTicks new_tab_start_time = base::TimeTicks::Now(); 2499 browser::NavigateParams params(this, GURL(chrome::kChromeUINewTabURL), 2500 PageTransition::TYPED); 2501 params.disposition = foreground ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB; 2502 params.tabstrip_index = index; 2503 browser::Navigate(¶ms); 2504 params.target_contents->tab_contents()->set_new_tab_start_time( 2505 new_tab_start_time); 2506 return params.target_contents; 2507} 2508 2509Browser* Browser::CreateNewStripWithContents( 2510 TabContentsWrapper* detached_contents, 2511 const gfx::Rect& window_bounds, 2512 const DockInfo& dock_info, 2513 bool maximize) { 2514 DCHECK(CanSupportWindowFeature(FEATURE_TABSTRIP)); 2515 2516 gfx::Rect new_window_bounds = window_bounds; 2517 if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize)) 2518 dock_info.AdjustOtherWindowBounds(); 2519 2520 // Create an empty new browser window the same size as the old one. 2521 Browser* browser = new Browser(TYPE_NORMAL, profile_); 2522 browser->set_override_bounds(new_window_bounds); 2523 browser->set_maximized_state( 2524 maximize ? MAXIMIZED_STATE_MAXIMIZED : MAXIMIZED_STATE_UNMAXIMIZED); 2525 browser->InitBrowserWindow(); 2526 browser->tabstrip_model()->AppendTabContents(detached_contents, true); 2527 // Make sure the loading state is updated correctly, otherwise the throbber 2528 // won't start if the page is loading. 2529 browser->LoadingStateChanged(detached_contents->tab_contents()); 2530 return browser; 2531} 2532 2533int Browser::GetDragActions() const { 2534 return TabStripModelDelegate::TAB_TEAROFF_ACTION | (tab_count() > 1 ? 2535 TabStripModelDelegate::TAB_MOVE_ACTION : 0); 2536} 2537 2538TabContentsWrapper* Browser::CreateTabContentsForURL( 2539 const GURL& url, const GURL& referrer, Profile* profile, 2540 PageTransition::Type transition, bool defer_load, 2541 SiteInstance* instance) const { 2542 TabContentsWrapper* contents = TabContentsFactory(profile, instance, 2543 MSG_ROUTING_NONE, 2544 GetSelectedTabContents(), NULL); 2545 if (!defer_load) { 2546 // Load the initial URL before adding the new tab contents to the tab strip 2547 // so that the tab contents has navigation state. 2548 contents->controller().LoadURL(url, referrer, transition); 2549 } 2550 2551 return contents; 2552} 2553 2554bool Browser::CanDuplicateContentsAt(int index) { 2555 NavigationController& nc = GetTabContentsAt(index)->controller(); 2556 return nc.tab_contents() && nc.GetLastCommittedEntry(); 2557} 2558 2559void Browser::DuplicateContentsAt(int index) { 2560 TabContentsWrapper* contents = GetTabContentsWrapperAt(index); 2561 CHECK(contents); 2562 TabContentsWrapper* contents_dupe = contents->Clone(); 2563 TabContents* new_contents = contents_dupe->tab_contents(); 2564 2565 bool pinned = false; 2566 if (CanSupportWindowFeature(FEATURE_TABSTRIP)) { 2567 // If this is a tabbed browser, just create a duplicate tab inside the same 2568 // window next to the tab being duplicated. 2569 int index = tab_handler_->GetTabStripModel()-> 2570 GetIndexOfTabContents(contents); 2571 pinned = tab_handler_->GetTabStripModel()->IsTabPinned(index); 2572 int add_types = TabStripModel::ADD_ACTIVE | 2573 TabStripModel::ADD_INHERIT_GROUP | 2574 (pinned ? TabStripModel::ADD_PINNED : 0); 2575 tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1, 2576 contents_dupe, 2577 add_types); 2578 } else { 2579 Browser* browser = NULL; 2580 if (type_ & TYPE_APP) { 2581 CHECK_EQ((type_ & TYPE_POPUP), 0); 2582 CHECK_NE(type_, TYPE_APP_PANEL); 2583 browser = Browser::CreateForApp(app_name_, gfx::Size(), profile_, 2584 false); 2585 } else if (type_ == TYPE_POPUP) { 2586 browser = Browser::CreateForType(TYPE_POPUP, profile_); 2587 } 2588 2589 // Preserve the size of the original window. The new window has already 2590 // been given an offset by the OS, so we shouldn't copy the old bounds. 2591 BrowserWindow* new_window = browser->window(); 2592 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(), 2593 window()->GetRestoredBounds().size())); 2594 2595 // We need to show the browser now. Otherwise ContainerWin assumes the 2596 // TabContents is invisible and won't size it. 2597 browser->window()->Show(); 2598 2599 // The page transition below is only for the purpose of inserting the tab. 2600 browser->AddTab(contents_dupe, PageTransition::LINK); 2601 } 2602 2603 if (profile_->HasSessionService()) { 2604 SessionService* session_service = profile_->GetSessionService(); 2605 if (session_service) 2606 session_service->TabRestored(&new_contents->controller(), pinned); 2607 } 2608} 2609 2610void Browser::CloseFrameAfterDragSession() { 2611#if defined(OS_WIN) || defined(OS_LINUX) 2612 // This is scheduled to run after we return to the message loop because 2613 // otherwise the frame will think the drag session is still active and ignore 2614 // the request. 2615 // TODO(port): figure out what is required here in a cross-platform world 2616 MessageLoop::current()->PostTask( 2617 FROM_HERE, method_factory_.NewRunnableMethod(&Browser::CloseFrame)); 2618#endif 2619} 2620 2621void Browser::CreateHistoricalTab(TabContentsWrapper* contents) { 2622 // We don't create historical tabs for incognito windows or windows without 2623 // profiles. 2624 if (!profile() || profile()->IsOffTheRecord() || 2625 !profile()->GetTabRestoreService()) { 2626 return; 2627 } 2628 2629 // We only create historical tab entries for tabbed browser windows. 2630 if (CanSupportWindowFeature(FEATURE_TABSTRIP)) { 2631 profile()->GetTabRestoreService()->CreateHistoricalTab( 2632 &contents->controller(), 2633 tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents)); 2634 } 2635} 2636 2637bool Browser::RunUnloadListenerBeforeClosing(TabContentsWrapper* contents) { 2638 return Browser::RunUnloadEventsHelper(contents->tab_contents()); 2639} 2640 2641bool Browser::CanReloadContents(TabContents* source) const { 2642 return type() != TYPE_DEVTOOLS; 2643} 2644 2645bool Browser::CanCloseContentsAt(int index) { 2646 if (!CanCloseTab()) 2647 return false; 2648 if (tab_handler_->GetTabStripModel()->count() > 1) 2649 return true; 2650 // We are closing the last tab for this browser. Make sure to check for 2651 // in-progress downloads. 2652 // Note that the next call when it returns false will ask the user for 2653 // confirmation before closing the browser if the user decides so. 2654 return CanCloseWithInProgressDownloads(); 2655} 2656 2657bool Browser::CanBookmarkAllTabs() const { 2658 BookmarkModel* model = profile()->GetBookmarkModel(); 2659 return (model && model->IsLoaded()) && 2660 tab_count() > 1 && 2661 edit_bookmarks_enabled_.GetValue(); 2662} 2663 2664void Browser::BookmarkAllTabs() { 2665 BookmarkModel* model = profile()->GetBookmarkModel(); 2666 DCHECK(model && model->IsLoaded()); 2667 2668 BookmarkEditor::EditDetails details; 2669 details.type = BookmarkEditor::EditDetails::NEW_FOLDER; 2670 bookmark_utils::GetURLsForOpenTabs(this, &(details.urls)); 2671 DCHECK(!details.urls.empty()); 2672 2673 BookmarkEditor::Show(window()->GetNativeHandle(), profile_, 2674 model->GetParentForNewNodes(), details, 2675 BookmarkEditor::SHOW_TREE); 2676} 2677 2678bool Browser::CanCloseTab() const { 2679 TabCloseableStateWatcher* watcher = 2680 g_browser_process->tab_closeable_state_watcher(); 2681 return !watcher || watcher->CanCloseTab(this); 2682} 2683 2684void Browser::ToggleUseVerticalTabs() { 2685 use_vertical_tabs_.SetValue(!UseVerticalTabs()); 2686 UseVerticalTabsChanged(); 2687} 2688 2689bool Browser::LargeIconsPermitted() const { 2690 // We don't show the big icons in tabs for TYPE_EXTENSION_APP windows because 2691 // for those windows, we already have a big icon in the top-left outside any 2692 // tab. Having big tab icons too looks kinda redonk. 2693 return true; 2694} 2695 2696/////////////////////////////////////////////////////////////////////////////// 2697// Browser, TabStripModelObserver implementation: 2698 2699void Browser::TabInsertedAt(TabContentsWrapper* contents, 2700 int index, 2701 bool foreground) { 2702 SetAsDelegate(contents, this); 2703 contents->controller().SetWindowID(session_id()); 2704 2705 // Each renderer holds the ID of the window that hosts it. Notify the 2706 // renderer that the window ID changed. 2707 contents->render_view_host()->UpdateBrowserWindowId( 2708 contents->controller().window_id().id()); 2709 2710 SyncHistoryWithTabs(index); 2711 2712 // Make sure the loading state is updated correctly, otherwise the throbber 2713 // won't start if the page is loading. 2714 LoadingStateChanged(contents->tab_contents()); 2715 2716 // If the tab crashes in the beforeunload or unload handler, it won't be 2717 // able to ack. But we know we can close it. 2718 registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED, 2719 Source<TabContentsWrapper>(contents)); 2720} 2721 2722void Browser::TabClosingAt(TabStripModel* tab_strip_model, 2723 TabContentsWrapper* contents, 2724 int index) { 2725 NotificationService::current()->Notify( 2726 NotificationType::TAB_CLOSING, 2727 Source<NavigationController>(&contents->controller()), 2728 NotificationService::NoDetails()); 2729 2730 // Sever the TabContents' connection back to us. 2731 SetAsDelegate(contents, NULL); 2732} 2733 2734void Browser::TabDetachedAt(TabContentsWrapper* contents, int index) { 2735 TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH); 2736} 2737 2738void Browser::TabDeselected(TabContentsWrapper* contents) { 2739 if (instant()) 2740 instant()->DestroyPreviewContents(); 2741 2742 // Save what the user's currently typing, so it can be restored when we 2743 // switch back to this tab. 2744 window_->GetLocationBar()->SaveStateToContents(contents->tab_contents()); 2745} 2746 2747void Browser::TabSelectedAt(TabContentsWrapper* old_contents, 2748 TabContentsWrapper* new_contents, 2749 int index, 2750 bool user_gesture) { 2751 if (old_contents == new_contents) 2752 return; 2753 2754 // On some platforms we want to automatically reload tabs that are 2755 // killed when the user selects them. 2756 if (user_gesture && new_contents->tab_contents()->crashed_status() == 2757 base::TERMINATION_STATUS_PROCESS_WAS_KILLED) { 2758 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); 2759 if (parsed_command_line.HasSwitch(switches::kReloadKilledTabs)) { 2760 Reload(CURRENT_TAB); 2761 return; 2762 } 2763 } 2764 2765 // If we have any update pending, do it now. 2766 if (!chrome_updater_factory_.empty() && old_contents) 2767 ProcessPendingUIUpdates(); 2768 2769 // Propagate the profile to the location bar. 2770 UpdateToolbar(true); 2771 2772 // Update reload/stop state. 2773 UpdateReloadStopState(new_contents->tab_contents()->is_loading(), true); 2774 2775 // Update commands to reflect current state. 2776 UpdateCommandsForTabState(); 2777 2778 // Reset the status bubble. 2779 StatusBubble* status_bubble = GetStatusBubble(); 2780 if (status_bubble) { 2781 status_bubble->Hide(); 2782 2783 // Show the loading state (if any). 2784 status_bubble->SetStatus(GetSelectedTabContentsWrapper()->GetStatusText()); 2785 } 2786 2787 if (HasFindBarController()) { 2788 find_bar_controller_->ChangeTabContents(new_contents); 2789 find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true); 2790 } 2791 2792 // Update sessions. Don't force creation of sessions. If sessions doesn't 2793 // exist, the change will be picked up by sessions when created. 2794 if (profile_->HasSessionService()) { 2795 SessionService* session_service = profile_->GetSessionService(); 2796 if (session_service && !tab_handler_->GetTabStripModel()->closing_all()) { 2797 session_service->SetSelectedTabInWindow( 2798 session_id(), tab_handler_->GetTabStripModel()->active_index()); 2799 } 2800 } 2801} 2802 2803void Browser::TabMoved(TabContentsWrapper* contents, 2804 int from_index, 2805 int to_index) { 2806 DCHECK(from_index >= 0 && to_index >= 0); 2807 // Notify the history service. 2808 SyncHistoryWithTabs(std::min(from_index, to_index)); 2809} 2810 2811void Browser::TabReplacedAt(TabStripModel* tab_strip_model, 2812 TabContentsWrapper* old_contents, 2813 TabContentsWrapper* new_contents, 2814 int index) { 2815 TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE); 2816 TabInsertedAt(new_contents, index, 2817 (index == tab_handler_->GetTabStripModel()->active_index())); 2818 2819 int entry_count = new_contents->controller().entry_count(); 2820 if (entry_count > 0) { 2821 // Send out notification so that observers are updated appropriately. 2822 new_contents->controller().NotifyEntryChanged( 2823 new_contents->controller().GetEntryAtIndex(entry_count - 1), 2824 entry_count - 1); 2825 } 2826 2827 SessionService* session_service = profile()->GetSessionService(); 2828 if (session_service) { 2829 // The new_contents may end up with a different navigation stack. Force 2830 // the session service to update itself. 2831 session_service->TabRestored( 2832 &new_contents->controller(), 2833 tab_handler_->GetTabStripModel()->IsTabPinned(index)); 2834 } 2835 2836 DevToolsManager* devtools_manager = DevToolsManager::GetInstance(); 2837 if (devtools_manager) // NULL in unit tests. 2838 devtools_manager->TabReplaced(old_contents, new_contents); 2839} 2840 2841void Browser::TabPinnedStateChanged(TabContentsWrapper* contents, int index) { 2842 if (!profile()->HasSessionService()) 2843 return; 2844 SessionService* session_service = profile()->GetSessionService(); 2845 if (session_service) { 2846 session_service->SetPinnedState( 2847 session_id(), 2848 GetTabContentsAt(index)->controller().session_id(), 2849 tab_handler_->GetTabStripModel()->IsTabPinned(index)); 2850 } 2851} 2852 2853void Browser::TabStripEmpty() { 2854 // Close the frame after we return to the message loop (not immediately, 2855 // otherwise it will destroy this object before the stack has a chance to 2856 // cleanly unwind.) 2857 // Note: This will be called several times if TabStripEmpty is called several 2858 // times. This is because it does not close the window if tabs are 2859 // still present. 2860 // NOTE: If you change to be immediate (no invokeLater) then you'll need to 2861 // update BrowserList::CloseAllBrowsers. 2862 MessageLoop::current()->PostTask( 2863 FROM_HERE, method_factory_.NewRunnableMethod(&Browser::CloseFrame)); 2864} 2865 2866/////////////////////////////////////////////////////////////////////////////// 2867// Browser, TabContentsDelegate implementation: 2868 2869void Browser::OpenURLFromTab(TabContents* source, 2870 const GURL& url, 2871 const GURL& referrer, 2872 WindowOpenDisposition disposition, 2873 PageTransition::Type transition) { 2874 browser::NavigateParams params(this, url, transition); 2875 params.source_contents = 2876 tabstrip_model()->GetTabContentsAt( 2877 tabstrip_model()->GetWrapperIndex(source)); 2878 params.referrer = referrer; 2879 params.disposition = disposition; 2880 params.tabstrip_add_types = TabStripModel::ADD_NONE; 2881 params.window_action = browser::NavigateParams::SHOW_WINDOW; 2882 browser::Navigate(¶ms); 2883} 2884 2885void Browser::NavigationStateChanged(const TabContents* source, 2886 unsigned changed_flags) { 2887 // Only update the UI when something visible has changed. 2888 if (changed_flags) 2889 ScheduleUIUpdate(source, changed_flags); 2890 2891 // We don't schedule updates to commands since they will only change once per 2892 // navigation, so we don't have to worry about flickering. 2893 if (changed_flags & TabContents::INVALIDATE_URL) 2894 UpdateCommandsForTabState(); 2895} 2896 2897void Browser::AddNewContents(TabContents* source, 2898 TabContents* new_contents, 2899 WindowOpenDisposition disposition, 2900 const gfx::Rect& initial_pos, 2901 bool user_gesture) { 2902 // No code for this yet 2903 DCHECK(disposition != SAVE_TO_DISK); 2904 // Can't create a new contents for the current tab - invalid case. 2905 DCHECK(disposition != CURRENT_TAB); 2906 2907 // TODO(beng): This belongs behind the platform-specific View interface. 2908 // That's why it's there. http://crbug.com/78853 2909#if defined(OS_CHROMEOS) 2910 if (disposition == NEW_POPUP) { 2911 // If the popup is bigger than a given factor of the screen, then 2912 // turn it into a foreground tab (on chrome os only) 2913 // Also check for width or height == 0, which would otherwise indicate 2914 // a tab sized popup window. 2915 GdkScreen* screen = gdk_screen_get_default(); 2916 int max_width = gdk_screen_get_width(screen) * kPopupMaxWidthFactor; 2917 int max_height = gdk_screen_get_height(screen) * kPopupMaxHeightFactor; 2918 if (initial_pos.width() > max_width || initial_pos.width() == 0 || 2919 initial_pos.height() > max_height || initial_pos.height() == 0) { 2920 disposition = NEW_FOREGROUND_TAB; 2921 } 2922 } 2923#endif 2924 2925 TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents); 2926 browser::NavigateParams params(this, wrapper); 2927 params.source_contents = 2928 tabstrip_model()->GetTabContentsAt( 2929 tabstrip_model()->GetWrapperIndex(source)); 2930 params.disposition = disposition; 2931 params.window_bounds = initial_pos; 2932 // If we create a popup or panel from a non user-gesture, don't activate 2933 // the new window / panel. 2934 if (disposition == NEW_POPUP && !user_gesture) 2935 params.window_action = browser::NavigateParams::SHOW_WINDOW_INACTIVE; 2936 else 2937 params.window_action = browser::NavigateParams::SHOW_WINDOW; 2938 browser::Navigate(¶ms); 2939} 2940 2941void Browser::ActivateContents(TabContents* contents) { 2942 tab_handler_->GetTabStripModel()->ActivateTabAt( 2943 tab_handler_->GetTabStripModel()->GetWrapperIndex(contents), false); 2944 window_->Activate(); 2945} 2946 2947void Browser::DeactivateContents(TabContents* contents) { 2948 window_->Deactivate(); 2949} 2950 2951void Browser::LoadingStateChanged(TabContents* source) { 2952 window_->UpdateLoadingAnimations( 2953 tab_handler_->GetTabStripModel()->TabsAreLoading()); 2954 window_->UpdateTitleBar(); 2955 2956 TabContents* selected_contents = GetSelectedTabContents(); 2957 if (source == selected_contents) { 2958 UpdateReloadStopState(source->is_loading(), false); 2959 if (GetStatusBubble()) { 2960 GetStatusBubble()->SetStatus( 2961 GetSelectedTabContentsWrapper()->GetStatusText()); 2962 } 2963 2964 if (!source->is_loading() && 2965 pending_web_app_action_ == UPDATE_SHORTCUT) { 2966 // Schedule a shortcut update when web application info is available if 2967 // last committed entry is not NULL. Last committed entry could be NULL 2968 // when an interstitial page is injected (e.g. bad https certificate, 2969 // malware site etc). When this happens, we abort the shortcut update. 2970 NavigationEntry* entry = source->controller().GetLastCommittedEntry(); 2971 if (entry) { 2972 TabContentsWrapper::GetCurrentWrapperForContents(source)-> 2973 extension_tab_helper()->GetApplicationInfo(entry->page_id()); 2974 } else { 2975 pending_web_app_action_ = NONE; 2976 } 2977 } 2978 } 2979} 2980 2981void Browser::CloseContents(TabContents* source) { 2982 if (is_attempting_to_close_browser_) { 2983 // If we're trying to close the browser, just clear the state related to 2984 // waiting for unload to fire. Don't actually try to close the tab as it 2985 // will go down the slow shutdown path instead of the fast path of killing 2986 // all the renderer processes. 2987 ClearUnloadState(source, true); 2988 return; 2989 } 2990 2991 int index = tab_handler_->GetTabStripModel()->GetWrapperIndex(source); 2992 if (index == TabStripModel::kNoTab) { 2993 NOTREACHED() << "CloseContents called for tab not in our strip"; 2994 return; 2995 } 2996 tab_handler_->GetTabStripModel()->CloseTabContentsAt( 2997 index, 2998 TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); 2999} 3000 3001void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) { 3002 if ((type() & TYPE_POPUP) == 0) { 3003 NOTREACHED() << "moving invalid browser type"; 3004 return; 3005 } 3006 window_->SetBounds(pos); 3007} 3008 3009void Browser::DetachContents(TabContents* source) { 3010 int index = tab_handler_->GetTabStripModel()->GetWrapperIndex(source); 3011 if (index >= 0) 3012 tab_handler_->GetTabStripModel()->DetachTabContentsAt(index); 3013} 3014 3015bool Browser::IsPopup(const TabContents* source) const { 3016 // A non-tabbed BROWSER is an unconstrained popup. 3017 return !!(type() & TYPE_POPUP); 3018} 3019 3020void Browser::ContentsMouseEvent( 3021 TabContents* source, const gfx::Point& location, bool motion) { 3022 if (!GetStatusBubble()) 3023 return; 3024 3025 if (source == GetSelectedTabContents()) { 3026 GetStatusBubble()->MouseMoved(location, !motion); 3027 if (!motion) 3028 GetStatusBubble()->SetURL(GURL(), string16()); 3029 } 3030} 3031 3032void Browser::UpdateTargetURL(TabContents* source, const GURL& url) { 3033 if (!GetStatusBubble()) 3034 return; 3035 3036 if (source == GetSelectedTabContents()) { 3037 PrefService* prefs = profile_->GetPrefs(); 3038 GetStatusBubble()->SetURL( 3039 url, UTF8ToUTF16(prefs->GetString(prefs::kAcceptLanguages))); 3040 } 3041} 3042 3043void Browser::UpdateDownloadShelfVisibility(bool visible) { 3044 if (GetStatusBubble()) 3045 GetStatusBubble()->UpdateDownloadShelfVisibility(visible); 3046} 3047 3048bool Browser::UseVerticalTabs() const { 3049 return use_vertical_tabs_.GetValue(); 3050} 3051 3052void Browser::ContentsZoomChange(bool zoom_in) { 3053 ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS); 3054} 3055 3056void Browser::OnContentSettingsChange(TabContents* source) { 3057 if (source == GetSelectedTabContents()) { 3058 LocationBar* location_bar = window()->GetLocationBar(); 3059 if (location_bar) 3060 location_bar->UpdateContentSettingsIcons(); 3061 } 3062} 3063 3064void Browser::SetTabContentBlocked(TabContents* contents, bool blocked) { 3065 int index = tabstrip_model()->GetWrapperIndex(contents); 3066 if (index == TabStripModel::kNoTab) { 3067 NOTREACHED(); 3068 return; 3069 } 3070 tabstrip_model()->SetTabBlocked(index, blocked); 3071} 3072 3073void Browser::TabContentsFocused(TabContents* tab_content) { 3074 window_->TabContentsFocused(tab_content); 3075} 3076 3077bool Browser::TakeFocus(bool reverse) { 3078 NotificationService::current()->Notify( 3079 NotificationType::FOCUS_RETURNED_TO_BROWSER, 3080 Source<Browser>(this), 3081 NotificationService::NoDetails()); 3082 return false; 3083} 3084 3085bool Browser::IsApplication() const { 3086 return (type_ & TYPE_APP) != 0; 3087} 3088 3089void Browser::ConvertContentsToApplication(TabContents* contents) { 3090 const GURL& url = contents->controller().GetActiveEntry()->url(); 3091 std::string app_name = web_app::GenerateApplicationNameFromURL(url); 3092 RegisterAppPrefs(app_name, contents->profile()); 3093 3094 DetachContents(contents); 3095 Browser* app_browser = Browser::CreateForApp( 3096 app_name, gfx::Size(), profile_, false); 3097 TabContentsWrapper* wrapper = new TabContentsWrapper(contents); 3098 app_browser->tabstrip_model()->AppendTabContents(wrapper, true); 3099 3100 contents->GetMutableRendererPrefs()->can_accept_load_drops = false; 3101 contents->render_view_host()->SyncRendererPrefs(); 3102 app_browser->window()->Show(); 3103} 3104 3105bool Browser::ShouldDisplayURLField() { 3106 return !IsApplication(); 3107} 3108 3109void Browser::BeforeUnloadFired(TabContents* tab, 3110 bool proceed, 3111 bool* proceed_to_fire_unload) { 3112 if (!is_attempting_to_close_browser_) { 3113 *proceed_to_fire_unload = proceed; 3114 if (!proceed) 3115 tab->set_closed_by_user_gesture(false); 3116 return; 3117 } 3118 3119 if (!proceed) { 3120 CancelWindowClose(); 3121 *proceed_to_fire_unload = false; 3122 tab->set_closed_by_user_gesture(false); 3123 return; 3124 } 3125 3126 if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) { 3127 // Now that beforeunload has fired, put the tab on the queue to fire 3128 // unload. 3129 tabs_needing_unload_fired_.insert(tab); 3130 ProcessPendingTabs(); 3131 // We want to handle firing the unload event ourselves since we want to 3132 // fire all the beforeunload events before attempting to fire the unload 3133 // events should the user cancel closing the browser. 3134 *proceed_to_fire_unload = false; 3135 return; 3136 } 3137 3138 *proceed_to_fire_unload = true; 3139} 3140 3141void Browser::ShowHtmlDialog(HtmlDialogUIDelegate* delegate, 3142 gfx::NativeWindow parent_window) { 3143 window_->ShowHTMLDialog(delegate, parent_window); 3144} 3145 3146void Browser::SetFocusToLocationBar(bool select_all) { 3147 // Two differences between this and FocusLocationBar(): 3148 // (1) This doesn't get recorded in user metrics, since it's called 3149 // internally. 3150 // (2) This checks whether the location bar can be focused, and if not, clears 3151 // the focus. FocusLocationBar() is only reached when the location bar is 3152 // focusable, but this may be reached at other times, e.g. while in 3153 // fullscreen mode, where we need to leave focus in a consistent state. 3154 window_->SetFocusToLocationBar(select_all); 3155} 3156 3157void Browser::RenderWidgetShowing() { 3158 window_->DisableInactiveFrame(); 3159} 3160 3161int Browser::GetExtraRenderViewHeight() const { 3162 return window_->GetExtraRenderViewHeight(); 3163} 3164 3165void Browser::OnStartDownload(DownloadItem* download, TabContents* tab) { 3166 if (!window()) 3167 return; 3168 3169#if defined(OS_CHROMEOS) 3170 // Don't show content browser for extension/theme downloads from gallery. 3171 if (download->is_extension_install()) { 3172 ExtensionService* service = profile_->GetExtensionService(); 3173 if (service && service->IsDownloadFromGallery(download->url(), 3174 download->referrer_url())) { 3175 return; 3176 } 3177 } 3178 // Open the Active Downloads ui for chromeos. 3179 ActiveDownloadsUI::OpenPopup(profile_); 3180#else 3181 // GetDownloadShelf creates the download shelf if it was not yet created. 3182 window()->GetDownloadShelf()->AddDownload(new DownloadItemModel(download)); 3183 3184 // Don't show the animation for "Save file" downloads. 3185 if (download->total_bytes() <= 0) 3186 return; 3187 3188 // For non-theme extensions, we don't show the download animation. 3189 if (download->is_extension_install() && 3190 !ExtensionService::IsDownloadFromMiniGallery(download->url())) 3191 return; 3192 3193 TabContents* current_tab = GetSelectedTabContents(); 3194 // We make this check for the case of minimized windows, unit tests, etc. 3195 if (platform_util::IsVisible(current_tab->GetNativeView()) && 3196 ui::Animation::ShouldRenderRichAnimation()) { 3197 DownloadStartedAnimation::Show(current_tab); 3198 } 3199#endif 3200 3201 // If the download occurs in a new tab, close it 3202 if (tab->controller().IsInitialNavigation() && 3203 GetConstrainingContents(tab) == tab && tab_count() > 1) { 3204 CloseContents(tab); 3205 } 3206} 3207 3208void Browser::ShowPageInfo(Profile* profile, 3209 const GURL& url, 3210 const NavigationEntry::SSLStatus& ssl, 3211 bool show_history) { 3212 window()->ShowPageInfo(profile, url, ssl, show_history); 3213} 3214 3215void Browser::ViewSourceForTab(TabContents* source, const GURL& page_url) { 3216 DCHECK(source); 3217 int index = tabstrip_model()->GetWrapperIndex(source); 3218 TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index); 3219 ViewSource(wrapper); 3220} 3221 3222void Browser::ViewSourceForFrame(TabContents* source, 3223 const GURL& frame_url, 3224 const std::string& frame_content_state) { 3225 DCHECK(source); 3226 int index = tabstrip_model()->GetWrapperIndex(source); 3227 TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index); 3228 ViewSource(wrapper, frame_url, frame_content_state); 3229} 3230 3231bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, 3232 bool* is_keyboard_shortcut) { 3233 return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut); 3234} 3235 3236void Browser::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { 3237 window()->HandleKeyboardEvent(event); 3238} 3239 3240void Browser::ShowRepostFormWarningDialog(TabContents *tab_contents) { 3241 window()->ShowRepostFormWarningDialog(tab_contents); 3242} 3243 3244void Browser::ShowContentSettingsPage(ContentSettingsType content_type) { 3245 ShowOptionsTab( 3246 chrome::kContentSettingsExceptionsSubPage + std::string(kHashMark) + 3247 ContentSettingsHandler::ContentSettingsTypeToGroupName(content_type)); 3248} 3249 3250void Browser::ShowCollectedCookiesDialog(TabContents *tab_contents) { 3251 window()->ShowCollectedCookiesDialog(tab_contents); 3252} 3253 3254bool Browser::ShouldAddNavigationToHistory( 3255 const history::HistoryAddPageArgs& add_page_args, 3256 NavigationType::Type navigation_type) { 3257 // Don't update history if running as app. 3258 return !IsApplication(); 3259} 3260 3261void Browser::ContentRestrictionsChanged(TabContents* source) { 3262 UpdateCommandsForContentRestrictionState(); 3263} 3264 3265void Browser::WorkerCrashed() { 3266 TabContents* tab_contents = GetSelectedTabContents(); 3267 if (!tab_contents) 3268 return; 3269 tab_contents->AddInfoBar(new SimpleAlertInfoBarDelegate(tab_contents, NULL, 3270 l10n_util::GetStringUTF16(IDS_WEBWORKER_CRASHED_PROMPT), true)); 3271} 3272 3273/////////////////////////////////////////////////////////////////////////////// 3274// Browser, TabContentsWrapperDelegate implementation: 3275 3276void Browser::URLStarredChanged(TabContentsWrapper* source, bool starred) { 3277 if (source == GetSelectedTabContentsWrapper()) 3278 window_->SetStarredState(starred); 3279} 3280 3281void Browser::OnDidGetApplicationInfo(TabContentsWrapper* source, 3282 int32 page_id) { 3283 if (GetSelectedTabContentsWrapper() != source) 3284 return; 3285 3286 NavigationEntry* entry = source->controller().GetLastCommittedEntry(); 3287 if (!entry || (entry->page_id() != page_id)) 3288 return; 3289 3290 switch (pending_web_app_action_) { 3291 case CREATE_SHORTCUT: { 3292 window()->ShowCreateWebAppShortcutsDialog(source); 3293 break; 3294 } 3295 case UPDATE_SHORTCUT: { 3296 web_app::UpdateShortcutForTabContents(source); 3297 break; 3298 } 3299 default: 3300 NOTREACHED(); 3301 break; 3302 } 3303 3304 pending_web_app_action_ = NONE; 3305} 3306 3307void Browser::OnInstallApplication(TabContentsWrapper* source, 3308 const WebApplicationInfo& web_app) { 3309 ExtensionService* extensions_service = profile()->GetExtensionService(); 3310 if (!extensions_service) 3311 return; 3312 3313 scoped_refptr<CrxInstaller> installer( 3314 new CrxInstaller(extensions_service, 3315 extensions_service->show_extensions_prompts() ? 3316 new ExtensionInstallUI(profile()) : NULL)); 3317 installer->InstallWebApp(web_app); 3318} 3319 3320/////////////////////////////////////////////////////////////////////////////// 3321// Browser, SearchEngineTabHelperDelegate implementation: 3322 3323void Browser::ConfirmSetDefaultSearchProvider( 3324 TabContents* tab_contents, 3325 TemplateURL* template_url, 3326 TemplateURLModel* template_url_model) { 3327 window()->ConfirmSetDefaultSearchProvider(tab_contents, template_url, 3328 template_url_model); 3329} 3330 3331void Browser::ConfirmAddSearchProvider(const TemplateURL* template_url, 3332 Profile* profile) { 3333 window()->ConfirmAddSearchProvider(template_url, profile); 3334} 3335 3336/////////////////////////////////////////////////////////////////////////////// 3337// Browser, SelectFileDialog::Listener implementation: 3338 3339void Browser::FileSelected(const FilePath& path, int index, void* params) { 3340 profile_->set_last_selected_directory(path.DirName()); 3341 GURL file_url = net::FilePathToFileURL(path); 3342 if (!file_url.is_empty()) 3343 OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED); 3344} 3345 3346/////////////////////////////////////////////////////////////////////////////// 3347// Browser, NotificationObserver implementation: 3348 3349void Browser::Observe(NotificationType type, 3350 const NotificationSource& source, 3351 const NotificationDetails& details) { 3352 switch (type.value) { 3353 case NotificationType::TAB_CONTENTS_DISCONNECTED: 3354 if (is_attempting_to_close_browser_) { 3355 // Pass in false so that we delay processing. We need to delay the 3356 // processing as it may close the tab, which is currently on the call 3357 // stack above us. 3358 ClearUnloadState(Source<TabContents>(source).ptr(), false); 3359 } 3360 break; 3361 3362 case NotificationType::SSL_VISIBLE_STATE_CHANGED: 3363 // When the current tab's SSL state changes, we need to update the URL 3364 // bar to reflect the new state. Note that it's possible for the selected 3365 // tab contents to be NULL. This is because we listen for all sources 3366 // (NavigationControllers) for convenience, so the notification could 3367 // actually be for a different window while we're doing asynchronous 3368 // closing of this one. 3369 if (GetSelectedTabContents() && 3370 &GetSelectedTabContents()->controller() == 3371 Source<NavigationController>(source).ptr()) 3372 UpdateToolbar(false); 3373 break; 3374 3375 case NotificationType::EXTENSION_UPDATE_DISABLED: { 3376 // Show the UI if the extension was disabled for escalated permissions. 3377 Profile* profile = Source<Profile>(source).ptr(); 3378 if (profile_->IsSameProfile(profile)) { 3379 ExtensionService* service = profile->GetExtensionService(); 3380 DCHECK(service); 3381 const Extension* extension = Details<const Extension>(details).ptr(); 3382 if (service->extension_prefs()->DidExtensionEscalatePermissions( 3383 extension->id())) 3384 ShowExtensionDisabledUI(service, profile_, extension); 3385 } 3386 break; 3387 } 3388 3389 case NotificationType::EXTENSION_UNLOADED: { 3390 window()->GetLocationBar()->UpdatePageActions(); 3391 3392 // Close any tabs from the unloaded extension. 3393 const Extension* extension = 3394 Details<UnloadedExtensionInfo>(details)->extension; 3395 TabStripModel* model = tab_handler_->GetTabStripModel(); 3396 for (int i = model->count() - 1; i >= 0; --i) { 3397 TabContents* tc = model->GetTabContentsAt(i)->tab_contents(); 3398 if (tc->GetURL().SchemeIs(chrome::kExtensionScheme) && 3399 tc->GetURL().host() == extension->id()) { 3400 CloseTabContents(tc); 3401 } 3402 } 3403 3404 break; 3405 } 3406 3407 case NotificationType::EXTENSION_PROCESS_TERMINATED: { 3408 window()->GetLocationBar()->InvalidatePageActions(); 3409 break; 3410 } 3411 3412 case NotificationType::EXTENSION_UNINSTALLED: 3413 case NotificationType::EXTENSION_LOADED: 3414 window()->GetLocationBar()->UpdatePageActions(); 3415 break; 3416 3417 case NotificationType::BROWSER_THEME_CHANGED: 3418 window()->UserChangedTheme(); 3419 break; 3420 3421 case NotificationType::EXTENSION_READY_FOR_INSTALL: { 3422 // Handle EXTENSION_READY_FOR_INSTALL for last active normal browser. 3423 if (BrowserList::FindBrowserWithType(profile(), 3424 Browser::TYPE_NORMAL, 3425 true) != this) 3426 break; 3427 3428 // We only want to show the loading dialog for themes, but we don't want 3429 // to wait until unpack to find out an extension is a theme, so we test 3430 // the download_url GURL instead. This means that themes in the extensions 3431 // gallery won't get the loading dialog. 3432 GURL download_url = *(Details<GURL>(details).ptr()); 3433 if (ExtensionService::IsDownloadFromMiniGallery(download_url)) 3434 window()->ShowThemeInstallBubble(); 3435 break; 3436 } 3437 3438 case NotificationType::PREF_CHANGED: { 3439 const std::string& pref_name = *Details<std::string>(details).ptr(); 3440 if (pref_name == prefs::kUseVerticalTabs) { 3441 UseVerticalTabsChanged(); 3442 } else if (pref_name == prefs::kPrintingEnabled) { 3443 UpdatePrintingState(0); 3444 } else if (pref_name == prefs::kInstantEnabled) { 3445 if (!InstantController::IsEnabled(profile())) { 3446 if (instant()) { 3447 instant()->DestroyPreviewContents(); 3448 instant_.reset(); 3449 instant_unload_handler_.reset(); 3450 } 3451 } else { 3452 CreateInstantIfNecessary(); 3453 } 3454 } else if (pref_name == prefs::kDevToolsDisabled) { 3455 UpdateCommandsForDevTools(); 3456 if (dev_tools_disabled_.GetValue()) 3457 g_browser_process->devtools_manager()->CloseAllClientHosts(); 3458 } else if (pref_name == prefs::kIncognitoEnabled) { 3459 break; // No further action is required. 3460 } else if (pref_name == prefs::kEditBookmarksEnabled) { 3461 UpdateCommandsForBookmarkEditing(); 3462 } else { 3463 NOTREACHED(); 3464 } 3465 break; 3466 } 3467 3468 default: 3469 NOTREACHED() << "Got a notification we didn't register for."; 3470 } 3471} 3472 3473/////////////////////////////////////////////////////////////////////////////// 3474// Browser, ProfileSyncServiceObserver implementation: 3475 3476void Browser::OnStateChanged() { 3477 DCHECK(profile_->GetProfileSyncService()); 3478 3479#if !defined(OS_MACOSX) 3480 const bool show_main_ui = (type() == TYPE_NORMAL) && !window_->IsFullscreen(); 3481#else 3482 const bool show_main_ui = (type() == TYPE_NORMAL); 3483#endif 3484 3485 command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, 3486 show_main_ui && profile_->IsSyncAccessible()); 3487} 3488 3489/////////////////////////////////////////////////////////////////////////////// 3490// Browser, InstantDelegate implementation: 3491 3492void Browser::PrepareForInstant() { 3493 window_->PrepareForInstant(); 3494} 3495 3496void Browser::ShowInstant(TabContentsWrapper* preview_contents) { 3497 DCHECK(instant_->tab_contents() == GetSelectedTabContentsWrapper()); 3498 window_->ShowInstant(preview_contents); 3499} 3500 3501void Browser::HideInstant() { 3502 window_->HideInstant(instant_->is_active()); 3503} 3504 3505void Browser::CommitInstant(TabContentsWrapper* preview_contents) { 3506 TabContentsWrapper* tab_contents = instant_->tab_contents(); 3507 int index = 3508 tab_handler_->GetTabStripModel()->GetIndexOfTabContents(tab_contents); 3509 DCHECK_NE(TabStripModel::kNoTab, index); 3510 // TabStripModel takes ownership of preview_contents. 3511 tab_handler_->GetTabStripModel()->ReplaceTabContentsAt( 3512 index, preview_contents); 3513 // InstantUnloadHandler takes ownership of tab_contents. 3514 instant_unload_handler_->RunUnloadListenersOrDestroy(tab_contents, index); 3515 3516 GURL url = preview_contents->tab_contents()->GetURL(); 3517 DCHECK(profile_->GetExtensionService()); 3518 if (profile_->GetExtensionService()->IsInstalledApp(url)) { 3519 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, 3520 extension_misc::APP_LAUNCH_OMNIBOX_INSTANT, 3521 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); 3522 } 3523} 3524 3525void Browser::SetSuggestedText(const string16& text, 3526 InstantCompleteBehavior behavior) { 3527 window()->GetLocationBar()->SetSuggestedText(text, behavior); 3528} 3529 3530gfx::Rect Browser::GetInstantBounds() { 3531 return window()->GetInstantBounds(); 3532} 3533 3534/////////////////////////////////////////////////////////////////////////////// 3535// Browser, protected: 3536 3537BrowserWindow* Browser::CreateBrowserWindow() { 3538 if (type() == Browser::TYPE_APP_PANEL && 3539 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels)) 3540 return PanelManager::GetInstance()->CreatePanel(this); 3541 3542 return BrowserWindow::CreateBrowserWindow(this); 3543} 3544 3545 3546/////////////////////////////////////////////////////////////////////////////// 3547// Browser, Command and state updating (private): 3548 3549void Browser::InitCommandState() { 3550 // All browser commands whose state isn't set automagically some other way 3551 // (like Back & Forward with initial page load) must have their state 3552 // initialized here, otherwise they will be forever disabled. 3553 3554 // Navigation commands 3555 command_updater_.UpdateCommandEnabled(IDC_RELOAD, true); 3556 command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, true); 3557 3558 // Window management commands 3559 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW, true); 3560 command_updater_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, 3561 incognito_mode_allowed_.GetValue()); 3562 command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true); 3563 command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true); 3564 command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true); 3565 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true); 3566 command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, false); 3567 command_updater_.UpdateCommandEnabled(IDC_EXIT, true); 3568 command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, true); 3569 3570 // Page-related commands 3571 command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, true); 3572 command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true); 3573 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true); 3574 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true); 3575 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true); 3576 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true); 3577 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true); 3578 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true); 3579 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true); 3580 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true); 3581 command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true); 3582 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true); 3583 command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true); 3584 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true); 3585 command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true); 3586 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true); 3587 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true); 3588 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true); 3589 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true); 3590 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true); 3591 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true); 3592 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true); 3593 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true); 3594 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true); 3595 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true); 3596 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true); 3597 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true); 3598 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true); 3599 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true); 3600 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true); 3601 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true); 3602 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true); 3603 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true); 3604 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true); 3605 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true); 3606 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true); 3607 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598I, true); 3608 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true); 3609 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true); 3610 3611 // Zoom 3612 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true); 3613 command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true); 3614 command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true); 3615 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true); 3616 3617 // Show various bits of UI 3618 command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, true); 3619 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false); 3620 UpdateCommandsForDevTools(); 3621 command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true); 3622 command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true); 3623 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, 3624 browser_defaults::bookmarks_enabled); 3625 command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true); 3626 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true); 3627 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, true); 3628 3629#if defined(OS_CHROMEOS) 3630 command_updater_.UpdateCommandEnabled(IDC_FILE_MANAGER, true); 3631 command_updater_.UpdateCommandEnabled(IDC_SEARCH, true); 3632 command_updater_.UpdateCommandEnabled(IDC_SHOW_KEYBOARD_OVERLAY, true); 3633 command_updater_.UpdateCommandEnabled(IDC_SYSTEM_OPTIONS, true); 3634 command_updater_.UpdateCommandEnabled(IDC_INTERNET_OPTIONS, true); 3635#endif 3636 3637 ExtensionService* extensions_service = profile()->GetExtensionService(); 3638 bool enable_extensions = 3639 extensions_service && extensions_service->extensions_enabled(); 3640 command_updater_.UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS, 3641 enable_extensions); 3642 3643 // Initialize other commands based on the window type. 3644 bool normal_window = type() == TYPE_NORMAL; 3645 bool non_devtools_window = type() != TYPE_DEVTOOLS; 3646 3647 // Navigation commands 3648 command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window); 3649 3650 // Window management commands 3651 command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, 3652 type() != TYPE_APP_PANEL); 3653 command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window); 3654 command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, 3655 normal_window); 3656 command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_NEXT, normal_window); 3657 command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_PREVIOUS, normal_window); 3658 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window); 3659 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window); 3660 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window); 3661 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window); 3662 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window); 3663 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window); 3664 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window); 3665 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window); 3666 command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window); 3667#if defined(OS_MACOSX) 3668 command_updater_.UpdateCommandEnabled(IDC_TABPOSE, normal_window); 3669#endif 3670 3671 // Clipboard commands 3672 command_updater_.UpdateCommandEnabled(IDC_COPY_URL, non_devtools_window); 3673 3674 // Find-in-page 3675 command_updater_.UpdateCommandEnabled(IDC_FIND, non_devtools_window); 3676 command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, non_devtools_window); 3677 command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, non_devtools_window); 3678 3679 // Autofill 3680 command_updater_.UpdateCommandEnabled(IDC_AUTOFILL_DEFAULT, 3681 non_devtools_window); 3682 3683 // Show various bits of UI 3684 command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window); 3685 3686 // The upgrade entry and the view incompatibility entry should always be 3687 // enabled. Whether they are visible is a separate matter determined on menu 3688 // show. 3689 command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true); 3690 command_updater_.UpdateCommandEnabled(IDC_VIEW_INCOMPATIBILITIES, true); 3691 3692 // View Background Pages entry is always enabled, but is hidden if there are 3693 // no background pages. 3694 command_updater_.UpdateCommandEnabled(IDC_VIEW_BACKGROUND_PAGES, true); 3695 3696 // Initialize other commands whose state changes based on fullscreen mode. 3697 UpdateCommandsForFullscreenMode(false); 3698 3699 UpdateCommandsForContentRestrictionState(); 3700 3701 UpdateCommandsForBookmarkEditing(); 3702} 3703 3704void Browser::UpdateCommandsForTabState() { 3705 TabContents* current_tab = GetSelectedTabContents(); 3706 TabContentsWrapper* current_tab_wrapper = GetSelectedTabContentsWrapper(); 3707 if (!current_tab || !current_tab_wrapper) // May be NULL during tab restore. 3708 return; 3709 3710 // Navigation commands 3711 NavigationController& nc = current_tab->controller(); 3712 command_updater_.UpdateCommandEnabled(IDC_BACK, nc.CanGoBack()); 3713 command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc.CanGoForward()); 3714 command_updater_.UpdateCommandEnabled(IDC_RELOAD, 3715 CanReloadContents(current_tab)); 3716 command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, 3717 CanReloadContents(current_tab)); 3718 3719 // Window management commands 3720 bool non_app_window = !(type() & TYPE_APP); 3721 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, 3722 non_app_window && CanDuplicateContentsAt(active_index())); 3723 3724 // Page-related commands 3725 window_->SetStarredState(current_tab_wrapper->is_starred()); 3726 command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE, 3727 current_tab->controller().CanViewSource()); 3728 command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, 3729 current_tab->ShouldDisplayURL() && current_tab->GetURL().is_valid()); 3730 3731 // Changing the encoding is not possible on Chrome-internal webpages. 3732 // Instead of using GetURL here, we use url() (which is the "real" url of the 3733 // page) from the NavigationEntry because its reflects their origin rather 3734 // than the display one (returned by GetURL) which may be different (like 3735 // having "view-source:" on the front). 3736 NavigationEntry* active_entry = nc.GetActiveEntry(); 3737 bool is_chrome_internal = (active_entry ? 3738 active_entry->url().SchemeIs(chrome::kChromeUIScheme) : false); 3739 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU, 3740 !is_chrome_internal && SavePackage::IsSavableContents( 3741 current_tab->contents_mime_type())); 3742 3743 // Show various bits of UI 3744 // TODO(pinkerton): Disable app-mode in the model until we implement it 3745 // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148 3746#if !defined(OS_MACOSX) 3747 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, 3748 web_app::IsValidUrl(current_tab->GetURL())); 3749#endif 3750 3751 UpdateCommandsForContentRestrictionState(); 3752 UpdateCommandsForBookmarkEditing(); 3753} 3754 3755void Browser::UpdateCommandsForContentRestrictionState() { 3756 int restrictions = 0; 3757 TabContents* current_tab = GetSelectedTabContents(); 3758 if (current_tab) { 3759 restrictions = current_tab->content_restrictions(); 3760 NavigationEntry* active_entry = current_tab->controller().GetActiveEntry(); 3761 // See comment in UpdateCommandsForTabState about why we call url(). 3762 if (!SavePackage::IsSavableURL(active_entry ? active_entry->url() : GURL())) 3763 restrictions |= CONTENT_RESTRICTION_SAVE; 3764 } 3765 3766 command_updater_.UpdateCommandEnabled( 3767 IDC_COPY, !(restrictions & CONTENT_RESTRICTION_COPY)); 3768 command_updater_.UpdateCommandEnabled( 3769 IDC_CUT, !(restrictions & CONTENT_RESTRICTION_CUT)); 3770 command_updater_.UpdateCommandEnabled( 3771 IDC_PASTE, !(restrictions & CONTENT_RESTRICTION_PASTE)); 3772 command_updater_.UpdateCommandEnabled( 3773 IDC_SAVE_PAGE, !(restrictions & CONTENT_RESTRICTION_SAVE)); 3774 UpdatePrintingState(restrictions); 3775} 3776 3777void Browser::UpdatePrintingState(int content_restrictions) { 3778 bool enabled = true; 3779 if (content_restrictions & CONTENT_RESTRICTION_PRINT) { 3780 enabled = false; 3781 } else if (g_browser_process->local_state()) { 3782 enabled = printing_enabled_.GetValue(); 3783 } 3784 command_updater_.UpdateCommandEnabled(IDC_PRINT, enabled); 3785} 3786 3787void Browser::UpdateReloadStopState(bool is_loading, bool force) { 3788 window_->UpdateReloadStopState(is_loading, force); 3789 command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading); 3790} 3791 3792void Browser::UpdateCommandsForDevTools() { 3793 bool dev_tools_enabled = !dev_tools_disabled_.GetValue(); 3794 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS, 3795 dev_tools_enabled); 3796 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE, 3797 dev_tools_enabled); 3798 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT, 3799 dev_tools_enabled); 3800} 3801 3802void Browser::UpdateCommandsForBookmarkEditing() { 3803 bool enabled = edit_bookmarks_enabled_.GetValue() && 3804 browser_defaults::bookmarks_enabled; 3805 3806 command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_PAGE, 3807 enabled && type() == TYPE_NORMAL); 3808 command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS, 3809 enabled && CanBookmarkAllTabs()); 3810} 3811 3812/////////////////////////////////////////////////////////////////////////////// 3813// Browser, UI update coalescing and handling (private): 3814 3815void Browser::UpdateToolbar(bool should_restore_state) { 3816 window_->UpdateToolbar(GetSelectedTabContentsWrapper(), should_restore_state); 3817} 3818 3819void Browser::ScheduleUIUpdate(const TabContents* source, 3820 unsigned changed_flags) { 3821 if (!source) 3822 return; 3823 3824 // Do some synchronous updates. 3825 if (changed_flags & TabContents::INVALIDATE_URL && 3826 source == GetSelectedTabContents()) { 3827 // Only update the URL for the current tab. Note that we do not update 3828 // the navigation commands since those would have already been updated 3829 // synchronously by NavigationStateChanged. 3830 UpdateToolbar(false); 3831 changed_flags &= ~TabContents::INVALIDATE_URL; 3832 } 3833 if (changed_flags & TabContents::INVALIDATE_LOAD) { 3834 // Update the loading state synchronously. This is so the throbber will 3835 // immediately start/stop, which gives a more snappy feel. We want to do 3836 // this for any tab so they start & stop quickly. 3837 tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( 3838 tab_handler_->GetTabStripModel()->GetIndexOfController( 3839 &source->controller()), 3840 TabStripModelObserver::LOADING_ONLY); 3841 // The status bubble needs to be updated during INVALIDATE_LOAD too, but 3842 // we do that asynchronously by not stripping INVALIDATE_LOAD from 3843 // changed_flags. 3844 } 3845 3846 if (changed_flags & TabContents::INVALIDATE_TITLE && !source->is_loading()) { 3847 // To correctly calculate whether the title changed while not loading 3848 // we need to process the update synchronously. This state only matters for 3849 // the TabStripModel, so we notify the TabStripModel now and notify others 3850 // asynchronously. 3851 tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( 3852 tab_handler_->GetTabStripModel()->GetIndexOfController( 3853 &source->controller()), 3854 TabStripModelObserver::TITLE_NOT_LOADING); 3855 } 3856 3857 if (changed_flags & TabContents::INVALIDATE_BOOKMARK_BAR) { 3858 window()->ShelfVisibilityChanged(); 3859 changed_flags &= ~TabContents::INVALIDATE_BOOKMARK_BAR; 3860 } 3861 3862 // If the only updates were synchronously handled above, we're done. 3863 if (changed_flags == 0) 3864 return; 3865 3866 // Save the dirty bits. 3867 scheduled_updates_[source] |= changed_flags; 3868 3869 if (chrome_updater_factory_.empty()) { 3870 // No task currently scheduled, start another. 3871 MessageLoop::current()->PostDelayedTask( 3872 FROM_HERE, 3873 chrome_updater_factory_.NewRunnableMethod( 3874 &Browser::ProcessPendingUIUpdates), 3875 kUIUpdateCoalescingTimeMS); 3876 } 3877} 3878 3879void Browser::ProcessPendingUIUpdates() { 3880#ifndef NDEBUG 3881 // Validate that all tabs we have pending updates for exist. This is scary 3882 // because the pending list must be kept in sync with any detached or 3883 // deleted tabs. 3884 for (UpdateMap::const_iterator i = scheduled_updates_.begin(); 3885 i != scheduled_updates_.end(); ++i) { 3886 bool found = false; 3887 for (int tab = 0; tab < tab_count(); tab++) { 3888 if (GetTabContentsAt(tab) == i->first) { 3889 found = true; 3890 break; 3891 } 3892 } 3893 DCHECK(found); 3894 } 3895#endif 3896 3897 chrome_updater_factory_.RevokeAll(); 3898 3899 for (UpdateMap::const_iterator i = scheduled_updates_.begin(); 3900 i != scheduled_updates_.end(); ++i) { 3901 // Do not dereference |contents|, it may be out-of-date! 3902 const TabContents* contents = i->first; 3903 unsigned flags = i->second; 3904 3905 if (contents == GetSelectedTabContents()) { 3906 // Updates that only matter when the tab is selected go here. 3907 3908 if (flags & TabContents::INVALIDATE_PAGE_ACTIONS) { 3909 LocationBar* location_bar = window()->GetLocationBar(); 3910 if (location_bar) 3911 location_bar->UpdatePageActions(); 3912 } 3913 // Updating the URL happens synchronously in ScheduleUIUpdate. 3914 if (flags & TabContents::INVALIDATE_LOAD && GetStatusBubble()) { 3915 GetStatusBubble()->SetStatus( 3916 GetSelectedTabContentsWrapper()->GetStatusText()); 3917 } 3918 3919 if (flags & (TabContents::INVALIDATE_TAB | 3920 TabContents::INVALIDATE_TITLE)) { 3921// TODO(pinkerton): Disable app-mode in the model until we implement it 3922// on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148 3923#if !defined(OS_MACOSX) 3924 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, 3925 web_app::IsValidUrl(contents->GetURL())); 3926#endif 3927 window_->UpdateTitleBar(); 3928 } 3929 } 3930 3931 // Updates that don't depend upon the selected state go here. 3932 if (flags & (TabContents::INVALIDATE_TAB | TabContents::INVALIDATE_TITLE)) { 3933 tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( 3934 tab_handler_->GetTabStripModel()->GetWrapperIndex(contents), 3935 TabStripModelObserver::ALL); 3936 } 3937 3938 // We don't need to process INVALIDATE_STATE, since that's not visible. 3939 } 3940 3941 scheduled_updates_.clear(); 3942} 3943 3944void Browser::RemoveScheduledUpdatesFor(TabContents* contents) { 3945 if (!contents) 3946 return; 3947 3948 UpdateMap::iterator i = scheduled_updates_.find(contents); 3949 if (i != scheduled_updates_.end()) 3950 scheduled_updates_.erase(i); 3951} 3952 3953 3954/////////////////////////////////////////////////////////////////////////////// 3955// Browser, Getters for UI (private): 3956 3957StatusBubble* Browser::GetStatusBubble() { 3958#if !defined(OS_MACOSX) 3959 // In kiosk mode, we want to always hide the status bubble. 3960 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) 3961 return NULL; 3962#endif 3963 return window_ ? window_->GetStatusBubble() : NULL; 3964} 3965 3966/////////////////////////////////////////////////////////////////////////////// 3967// Browser, Session restore functions (private): 3968 3969void Browser::SyncHistoryWithTabs(int index) { 3970 if (!profile()->HasSessionService()) 3971 return; 3972 SessionService* session_service = profile()->GetSessionService(); 3973 if (session_service) { 3974 for (int i = index; i < tab_count(); ++i) { 3975 TabContents* contents = GetTabContentsAt(i); 3976 if (contents) { 3977 session_service->SetTabIndexInWindow( 3978 session_id(), contents->controller().session_id(), i); 3979 session_service->SetPinnedState( 3980 session_id(), 3981 contents->controller().session_id(), 3982 tab_handler_->GetTabStripModel()->IsTabPinned(i)); 3983 } 3984 } 3985 } 3986} 3987 3988/////////////////////////////////////////////////////////////////////////////// 3989// Browser, OnBeforeUnload handling (private): 3990 3991void Browser::ProcessPendingTabs() { 3992 if (!is_attempting_to_close_browser_) { 3993 // Because we might invoke this after a delay it's possible for the value of 3994 // is_attempting_to_close_browser_ to have changed since we scheduled the 3995 // task. 3996 return; 3997 } 3998 3999 if (HasCompletedUnloadProcessing()) { 4000 // We've finished all the unload events and can proceed to close the 4001 // browser. 4002 OnWindowClosing(); 4003 return; 4004 } 4005 4006 // Process beforeunload tabs first. When that queue is empty, process 4007 // unload tabs. 4008 if (!tabs_needing_before_unload_fired_.empty()) { 4009 TabContents* tab = *(tabs_needing_before_unload_fired_.begin()); 4010 // Null check render_view_host here as this gets called on a PostTask and 4011 // the tab's render_view_host may have been nulled out. 4012 if (tab->render_view_host()) { 4013 tab->render_view_host()->FirePageBeforeUnload(false); 4014 } else { 4015 ClearUnloadState(tab, true); 4016 } 4017 } else if (!tabs_needing_unload_fired_.empty()) { 4018 // We've finished firing all beforeunload events and can proceed with unload 4019 // events. 4020 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting 4021 // somewhere around here so that we have accurate measurements of shutdown 4022 // time. 4023 // TODO(ojan): We can probably fire all the unload events in parallel and 4024 // get a perf benefit from that in the cases where the tab hangs in it's 4025 // unload handler or takes a long time to page in. 4026 TabContents* tab = *(tabs_needing_unload_fired_.begin()); 4027 // Null check render_view_host here as this gets called on a PostTask and 4028 // the tab's render_view_host may have been nulled out. 4029 if (tab->render_view_host()) { 4030 tab->render_view_host()->ClosePage(false, -1, -1); 4031 } else { 4032 ClearUnloadState(tab, true); 4033 } 4034 } else { 4035 NOTREACHED(); 4036 } 4037} 4038 4039bool Browser::HasCompletedUnloadProcessing() const { 4040 return is_attempting_to_close_browser_ && 4041 tabs_needing_before_unload_fired_.empty() && 4042 tabs_needing_unload_fired_.empty(); 4043} 4044 4045void Browser::CancelWindowClose() { 4046 // Closing of window can be canceled from: 4047 // - canceling beforeunload 4048 // - disallowing closing from IsClosingPermitted. 4049 DCHECK(is_attempting_to_close_browser_); 4050 tabs_needing_before_unload_fired_.clear(); 4051 tabs_needing_unload_fired_.clear(); 4052 is_attempting_to_close_browser_ = false; 4053 4054 // Inform TabCloseableStateWatcher that closing of window has been canceled. 4055 TabCloseableStateWatcher* watcher = 4056 g_browser_process->tab_closeable_state_watcher(); 4057 if (watcher) 4058 watcher->OnWindowCloseCanceled(this); 4059} 4060 4061bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) { 4062 DCHECK(is_attempting_to_close_browser_); 4063 4064 UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab); 4065 if (iter != set->end()) { 4066 set->erase(iter); 4067 return true; 4068 } 4069 return false; 4070} 4071 4072void Browser::ClearUnloadState(TabContents* tab, bool process_now) { 4073 // Closing of browser could be canceled (via IsClosingPermitted) between the 4074 // time when request was initiated and when this method is called, so check 4075 // for is_attempting_to_close_browser_ flag before proceeding. 4076 if (is_attempting_to_close_browser_) { 4077 RemoveFromSet(&tabs_needing_before_unload_fired_, tab); 4078 RemoveFromSet(&tabs_needing_unload_fired_, tab); 4079 if (process_now) { 4080 ProcessPendingTabs(); 4081 } else { 4082 MessageLoop::current()->PostTask( 4083 FROM_HERE, 4084 method_factory_.NewRunnableMethod(&Browser::ProcessPendingTabs)); 4085 } 4086 } 4087} 4088 4089/////////////////////////////////////////////////////////////////////////////// 4090// Browser, In-progress download termination handling (private): 4091 4092void Browser::CheckDownloadsInProgress(bool* normal_downloads_are_present, 4093 bool* incognito_downloads_are_present) { 4094 *normal_downloads_are_present = false; 4095 *incognito_downloads_are_present = false; 4096 4097 // If there are no download in-progress, our job is done. 4098 DownloadManager* download_manager = NULL; 4099 // But first we need to check for the existance of the download manager, as 4100 // GetDownloadManager() will unnecessarily try to create one if it does not 4101 // exist. 4102 if (profile()->HasCreatedDownloadManager()) 4103 download_manager = profile()->GetDownloadManager(); 4104 if (profile()->IsOffTheRecord()) { 4105 // Browser is incognito and so download_manager if present is for incognito 4106 // downloads. 4107 *incognito_downloads_are_present = 4108 (download_manager && download_manager->in_progress_count() != 0); 4109 // Check original profile. 4110 if (profile()->GetOriginalProfile()->HasCreatedDownloadManager()) 4111 download_manager = profile()->GetOriginalProfile()->GetDownloadManager(); 4112 } 4113 4114 *normal_downloads_are_present = 4115 (download_manager && download_manager->in_progress_count() != 0); 4116} 4117 4118bool Browser::CanCloseWithInProgressDownloads() { 4119 if (cancel_download_confirmation_state_ != NOT_PROMPTED) { 4120 if (cancel_download_confirmation_state_ == WAITING_FOR_RESPONSE) { 4121 // We need to hear from the user before we can close. 4122 return false; 4123 } 4124 // RESPONSE_RECEIVED case, the user decided to go along with the closing. 4125 return true; 4126 } 4127 // Indicated that normal (non-incognito) downloads are pending. 4128 bool normal_downloads_are_present = false; 4129 bool incognito_downloads_are_present = false; 4130 CheckDownloadsInProgress(&normal_downloads_are_present, 4131 &incognito_downloads_are_present); 4132 if (!normal_downloads_are_present && !incognito_downloads_are_present) 4133 return true; 4134 4135 if (is_attempting_to_close_browser_) 4136 return true; 4137 4138 if ((!normal_downloads_are_present && !profile()->IsOffTheRecord()) || 4139 (!incognito_downloads_are_present && profile()->IsOffTheRecord())) 4140 return true; 4141 4142 // Let's figure out if we are the last window for our profile. 4143 // Note that we cannot just use BrowserList::GetBrowserCount as browser 4144 // windows closing is delayed and the returned count might include windows 4145 // that are being closed. 4146 // The browser allowed to be closed only if: 4147 // 1. It is a regular browser and there are no regular downloads present or 4148 // this is not the last regular browser window. 4149 // 2. It is an incognito browser and there are no incognito downloads present 4150 // or this is not the last incognito browser window. 4151 int count = 0; 4152 for (BrowserList::const_iterator iter = BrowserList::begin(); 4153 iter != BrowserList::end(); ++iter) { 4154 // Don't count this browser window or any other in the process of closing. 4155 // Only consider normal browser windows, not popups. 4156 Browser* const browser = *iter; 4157 if (browser == this 4158 || browser->is_attempting_to_close_browser_ 4159 || browser->type() != Browser::TYPE_NORMAL) 4160 continue; 4161 4162 // Verify that this is not the last non-incognito or incognito browser, 4163 // depending on the pending downloads. 4164 if (normal_downloads_are_present && !profile()->IsOffTheRecord() && 4165 browser->profile()->IsOffTheRecord()) 4166 continue; 4167 if (incognito_downloads_are_present && profile()->IsOffTheRecord() && 4168 !browser->profile()->IsOffTheRecord()) 4169 continue; 4170 4171 // We test the original profile, because an incognito browser window keeps 4172 // the original profile alive (and its DownloadManager). 4173 // We also need to test explicitly the profile directly so that 2 incognito 4174 // profiles count as a match. 4175 if ((*iter)->profile() == profile() || 4176 (*iter)->profile()->GetOriginalProfile() == profile()) 4177 count++; 4178 } 4179 if (count > 0) 4180 return true; 4181 4182 cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE; 4183 window_->ConfirmBrowserCloseWithPendingDownloads(); 4184 4185 // Return false so the browser does not close. We'll close if the user 4186 // confirms in the dialog. 4187 return false; 4188} 4189 4190/////////////////////////////////////////////////////////////////////////////// 4191// Browser, Assorted utility functions (private): 4192 4193// static 4194Browser* Browser::GetTabbedBrowser(Profile* profile, bool match_incognito) { 4195 return BrowserList::FindBrowserWithType(profile, TYPE_NORMAL, 4196 match_incognito); 4197} 4198 4199// static 4200Browser* Browser::GetOrCreateTabbedBrowser(Profile* profile) { 4201 Browser* browser = GetTabbedBrowser(profile, false); 4202 if (!browser) 4203 browser = Browser::Create(profile); 4204 return browser; 4205} 4206 4207void Browser::SetAsDelegate(TabContentsWrapper* tab, Browser* delegate) { 4208 tab->tab_contents()->set_delegate(delegate); 4209 tab->set_delegate(delegate); 4210 tab->search_engine_tab_helper()->set_delegate(delegate); 4211} 4212 4213void Browser::FindInPage(bool find_next, bool forward_direction) { 4214 ShowFindBar(); 4215 if (find_next) { 4216 string16 find_text; 4217#if defined(OS_MACOSX) 4218 // We always want to search for the contents of the find pasteboard on OS X. 4219 find_text = GetFindPboardText(); 4220#endif 4221 GetSelectedTabContentsWrapper()-> 4222 find_tab_helper()->StartFinding(find_text, 4223 forward_direction, 4224 false); // Not case sensitive. 4225 } 4226} 4227 4228void Browser::CloseFrame() { 4229 window_->Close(); 4230} 4231 4232void Browser::TabDetachedAtImpl(TabContentsWrapper* contents, int index, 4233 DetachType type) { 4234 if (type == DETACH_TYPE_DETACH) { 4235 // Save the current location bar state, but only if the tab being detached 4236 // is the selected tab. Because saving state can conditionally revert the 4237 // location bar, saving the current tab's location bar state to a 4238 // non-selected tab can corrupt both tabs. 4239 if (contents == GetSelectedTabContentsWrapper()) { 4240 LocationBar* location_bar = window()->GetLocationBar(); 4241 if (location_bar) 4242 location_bar->SaveStateToContents(contents->tab_contents()); 4243 } 4244 4245 if (!tab_handler_->GetTabStripModel()->closing_all()) 4246 SyncHistoryWithTabs(0); 4247 } 4248 4249 SetAsDelegate(contents, NULL); 4250 RemoveScheduledUpdatesFor(contents->tab_contents()); 4251 4252 if (find_bar_controller_.get() && 4253 index == tab_handler_->GetTabStripModel()->active_index()) { 4254 find_bar_controller_->ChangeTabContents(NULL); 4255 } 4256 4257 if (is_attempting_to_close_browser_) { 4258 // If this is the last tab with unload handlers, then ProcessPendingTabs 4259 // would call back into the TabStripModel (which is invoking this method on 4260 // us). Avoid that by passing in false so that the call to 4261 // ProcessPendingTabs is delayed. 4262 ClearUnloadState(contents->tab_contents(), false); 4263 } 4264 4265 registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED, 4266 Source<TabContentsWrapper>(contents)); 4267} 4268 4269// static 4270void Browser::RegisterAppPrefs(const std::string& app_name, Profile* profile) { 4271 // A set of apps that we've already started. 4272 static std::set<std::string>* g_app_names = NULL; 4273 4274 if (!g_app_names) 4275 g_app_names = new std::set<std::string>; 4276 4277 // Only register once for each app name. 4278 if (g_app_names->find(app_name) != g_app_names->end()) 4279 return; 4280 g_app_names->insert(app_name); 4281 4282 // We need to register the window position pref. 4283 std::string window_pref(prefs::kBrowserWindowPlacement); 4284 window_pref.append("_"); 4285 window_pref.append(app_name); 4286 profile->GetPrefs()->RegisterDictionaryPref(window_pref.c_str()); 4287} 4288 4289void Browser::TabRestoreServiceChanged(TabRestoreService* service) { 4290 command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, 4291 !service->entries().empty()); 4292} 4293 4294void Browser::TabRestoreServiceDestroyed(TabRestoreService* service) { 4295 if (!tab_restore_service_) 4296 return; 4297 4298 DCHECK_EQ(tab_restore_service_, service); 4299 tab_restore_service_->RemoveObserver(this); 4300 tab_restore_service_ = NULL; 4301} 4302 4303// Centralized method for creating a TabContents, configuring and installing 4304// all its supporting objects and observers. 4305TabContentsWrapper* Browser::TabContentsFactory( 4306 Profile* profile, 4307 SiteInstance* site_instance, 4308 int routing_id, 4309 const TabContents* base_tab_contents, 4310 SessionStorageNamespace* session_storage_namespace) { 4311 TabContents* new_contents = new TabContents(profile, site_instance, 4312 routing_id, base_tab_contents, 4313 session_storage_namespace); 4314 TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents); 4315 return wrapper; 4316} 4317 4318bool Browser::OpenInstant(WindowOpenDisposition disposition) { 4319 if (!instant() || !instant()->is_active() || !instant()->IsCurrent() || 4320 disposition == NEW_BACKGROUND_TAB) { 4321 // NEW_BACKGROUND_TAB results in leaving the omnibox open, so we don't 4322 // attempt to use the instant preview. 4323 return false; 4324 } 4325 4326 if (disposition == CURRENT_TAB) { 4327 instant()->CommitCurrentPreview(INSTANT_COMMIT_PRESSED_ENTER); 4328 return true; 4329 } 4330 if (disposition == NEW_FOREGROUND_TAB) { 4331 TabContentsWrapper* preview_contents = instant()->ReleasePreviewContents( 4332 INSTANT_COMMIT_PRESSED_ENTER); 4333 // HideInstant is invoked after release so that InstantController is not 4334 // active when HideInstant asks it for its state. 4335 HideInstant(); 4336 preview_contents->controller().PruneAllButActive(); 4337 tab_handler_->GetTabStripModel()->AddTabContents( 4338 preview_contents, 4339 -1, 4340 instant()->last_transition_type(), 4341 TabStripModel::ADD_ACTIVE); 4342 instant()->CompleteRelease(preview_contents->tab_contents()); 4343 return true; 4344 } 4345 // The omnibox currently doesn't use other dispositions, so we don't attempt 4346 // to handle them. If you hit this NOTREACHED file a bug and I'll (sky) add 4347 // support for the new disposition. 4348 NOTREACHED(); 4349 return false; 4350} 4351 4352void Browser::CreateInstantIfNecessary() { 4353 if (type() == TYPE_NORMAL && InstantController::IsEnabled(profile()) && 4354 !profile()->IsOffTheRecord()) { 4355 instant_.reset(new InstantController(profile_, this)); 4356 instant_unload_handler_.reset(new InstantUnloadHandler(this)); 4357 } 4358} 4359 4360void Browser::ViewSource(TabContentsWrapper* contents) { 4361 DCHECK(contents); 4362 4363 NavigationEntry* active_entry = contents->controller().GetActiveEntry(); 4364 if (!active_entry) 4365 return; 4366 4367 ViewSource(contents, active_entry->url(), active_entry->content_state()); 4368} 4369 4370void Browser::ViewSource(TabContentsWrapper* contents, 4371 const GURL& url, 4372 const std::string& content_state) { 4373 UserMetrics::RecordAction(UserMetricsAction("ViewSource"), profile_); 4374 DCHECK(contents); 4375 4376 TabContentsWrapper* view_source_contents = contents->Clone(); 4377 view_source_contents->controller().PruneAllButActive(); 4378 NavigationEntry* active_entry = 4379 view_source_contents->controller().GetActiveEntry(); 4380 if (!active_entry) 4381 return; 4382 4383 GURL view_source_url = GURL(chrome::kViewSourceScheme + std::string(":") + 4384 url.spec()); 4385 active_entry->set_virtual_url(view_source_url); 4386 4387 // Do not restore scroller position. 4388 active_entry->set_content_state( 4389 webkit_glue::RemoveScrollOffsetFromHistoryState(content_state)); 4390 4391 // Do not restore title, derive it from the url. 4392 active_entry->set_title(string16()); 4393 4394 // Now show view-source entry. 4395 if (CanSupportWindowFeature(FEATURE_TABSTRIP)) { 4396 // If this is a tabbed browser, just create a duplicate tab inside the same 4397 // window next to the tab being duplicated. 4398 int index = tab_handler_->GetTabStripModel()-> 4399 GetIndexOfTabContents(contents); 4400 int add_types = TabStripModel::ADD_ACTIVE | 4401 TabStripModel::ADD_INHERIT_GROUP; 4402 tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1, 4403 view_source_contents, 4404 add_types); 4405 } else { 4406 Browser* browser = Browser::CreateForType(TYPE_NORMAL, profile_); 4407 4408 // Preserve the size of the original window. The new window has already 4409 // been given an offset by the OS, so we shouldn't copy the old bounds. 4410 BrowserWindow* new_window = browser->window(); 4411 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(), 4412 window()->GetRestoredBounds().size())); 4413 4414 // We need to show the browser now. Otherwise ContainerWin assumes the 4415 // TabContents is invisible and won't size it. 4416 browser->window()->Show(); 4417 4418 // The page transition below is only for the purpose of inserting the tab. 4419 browser->AddTab(view_source_contents, PageTransition::LINK); 4420 } 4421 4422 if (profile_->HasSessionService()) { 4423 SessionService* session_service = profile_->GetSessionService(); 4424 if (session_service) 4425 session_service->TabRestored(&view_source_contents->controller(), false); 4426 } 4427} 4428