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