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