| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/browser.h" |
| |
| #if defined(OS_WIN) |
| #include <windows.h> |
| #include <shellapi.h> |
| #endif // OS_WIN |
| |
| #include <algorithm> |
| #include <string> |
| |
| #include "base/base_paths.h" |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/logging.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/metrics/histogram.h" |
| #include "base/path_service.h" |
| #include "base/string_number_conversions.h" |
| #include "base/string_util.h" |
| #include "base/stringprintf.h" |
| #include "base/threading/thread.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "base/time.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/browser/autofill/personal_data_manager_factory.h" |
| #include "chrome/browser/background/background_contents_service.h" |
| #include "chrome/browser/bookmarks/bookmark_model.h" |
| #include "chrome/browser/bookmarks/bookmark_utils.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/browser_shutdown.h" |
| #include "chrome/browser/character_encoding.h" |
| #include "chrome/browser/chrome_page_zoom.h" |
| #include "chrome/browser/content_settings/host_content_settings_map.h" |
| #include "chrome/browser/custom_handlers/protocol_handler_registry.h" |
| #include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h" |
| #include "chrome/browser/debugger/devtools_toggle_action.h" |
| #include "chrome/browser/debugger/devtools_window.h" |
| #include "chrome/browser/download/chrome_download_manager_delegate.h" |
| #include "chrome/browser/download/download_item_model.h" |
| #include "chrome/browser/download/download_service.h" |
| #include "chrome/browser/download/download_service_factory.h" |
| #include "chrome/browser/download/download_started_animation.h" |
| #include "chrome/browser/extensions/crx_installer.h" |
| #include "chrome/browser/extensions/default_apps_trial.h" |
| #include "chrome/browser/extensions/extension_browser_event_router.h" |
| #include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" |
| #include "chrome/browser/extensions/extension_host.h" |
| #include "chrome/browser/extensions/extension_prefs.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/extension_tab_helper.h" |
| #include "chrome/browser/extensions/extension_tabs_module.h" |
| #include "chrome/browser/favicon/favicon_tab_helper.h" |
| #include "chrome/browser/file_select_helper.h" |
| #include "chrome/browser/first_run/first_run.h" |
| #include "chrome/browser/google/google_url_tracker.h" |
| #include "chrome/browser/google/google_util.h" |
| #include "chrome/browser/infobars/infobar_tab_helper.h" |
| #include "chrome/browser/instant/instant_controller.h" |
| #include "chrome/browser/instant/instant_unload_handler.h" |
| #include "chrome/browser/intents/register_intent_handler_infobar_delegate.h" |
| #include "chrome/browser/intents/web_intents_registry_factory.h" |
| #include "chrome/browser/net/browser_url_util.h" |
| #include "chrome/browser/net/url_fixer_upper.h" |
| #include "chrome/browser/notifications/notification_ui_manager.h" |
| #include "chrome/browser/platform_util.h" |
| #include "chrome/browser/prefs/incognito_mode_prefs.h" |
| #include "chrome/browser/prefs/pref_service.h" |
| #include "chrome/browser/prerender/prerender_tab_helper.h" |
| #include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h" |
| #include "chrome/browser/printing/print_preview_tab_controller.h" |
| #include "chrome/browser/printing/print_view_manager.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/sessions/restore_tab_helper.h" |
| #include "chrome/browser/sessions/session_service.h" |
| #include "chrome/browser/sessions/session_service_factory.h" |
| #include "chrome/browser/sessions/session_types.h" |
| #include "chrome/browser/sessions/tab_restore_service.h" |
| #include "chrome/browser/sessions/tab_restore_service_factory.h" |
| #include "chrome/browser/sync/profile_sync_service.h" |
| #include "chrome/browser/sync/sync_ui_util.h" |
| #include "chrome/browser/tab_closeable_state_watcher.h" |
| #include "chrome/browser/tab_contents/background_contents.h" |
| #include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h" |
| #include "chrome/browser/tab_contents/tab_util.h" |
| #include "chrome/browser/tabs/tab_finder.h" |
| #include "chrome/browser/tabs/tab_strip_model.h" |
| #include "chrome/browser/themes/theme_service.h" |
| #include "chrome/browser/themes/theme_service_factory.h" |
| #include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h" |
| #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h" |
| #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h" |
| #include "chrome/browser/ui/browser_dialogs.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_navigator.h" |
| #include "chrome/browser/ui/browser_tab_restore_service_delegate.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/constrained_window_tab_helper.h" |
| #include "chrome/browser/ui/find_bar/find_bar.h" |
| #include "chrome/browser/ui/find_bar/find_bar_controller.h" |
| #include "chrome/browser/ui/find_bar/find_tab_helper.h" |
| #include "chrome/browser/ui/global_error.h" |
| #include "chrome/browser/ui/global_error_service.h" |
| #include "chrome/browser/ui/global_error_service_factory.h" |
| #include "chrome/browser/ui/intents/web_intent_picker_controller.h" |
| #include "chrome/browser/ui/omnibox/location_bar.h" |
| #include "chrome/browser/ui/panels/panel.h" |
| #include "chrome/browser/ui/panels/panel_manager.h" |
| #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h" |
| #include "chrome/browser/ui/status_bubble.h" |
| #include "chrome/browser/ui/sync/browser_synced_window_delegate.h" |
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| #include "chrome/browser/ui/tabs/dock_info.h" |
| #include "chrome/browser/ui/tabs/tab_menu_model.h" |
| #include "chrome/browser/ui/web_applications/web_app_ui.h" |
| #include "chrome/browser/ui/webui/bug_report_ui.h" |
| #include "chrome/browser/ui/webui/chrome_web_ui.h" |
| #include "chrome/browser/ui/webui/ntp/new_tab_page_handler.h" |
| #include "chrome/browser/ui/webui/options/content_settings_handler.h" |
| #include "chrome/browser/ui/window_sizer.h" |
| #include "chrome/browser/upgrade_detector.h" |
| #include "chrome/browser/web_applications/web_app.h" |
| #include "chrome/common/chrome_constants.h" |
| #include "chrome/common/chrome_notification_types.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/custom_handlers/protocol_handler.h" |
| #include "chrome/common/extensions/extension.h" |
| #include "chrome/common/extensions/extension_constants.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/profiling.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/common/web_apps.h" |
| #include "content/browser/browser_url_handler.h" |
| #include "content/browser/child_process_security_policy.h" |
| #include "content/browser/download/download_item.h" |
| #include "content/browser/download/download_manager.h" |
| #include "content/browser/download/save_package.h" |
| #include "content/browser/host_zoom_map.h" |
| #include "content/browser/plugin_service.h" |
| #include "content/browser/renderer_host/render_view_host.h" |
| #include "content/browser/site_instance.h" |
| #include "content/browser/tab_contents/interstitial_page.h" |
| #include "content/browser/tab_contents/navigation_controller.h" |
| #include "content/browser/tab_contents/navigation_entry.h" |
| #include "content/browser/tab_contents/tab_contents_view.h" |
| #include "content/browser/user_metrics.h" |
| #include "content/public/browser/devtools_manager.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/notification_details.h" |
| #include "content/public/browser/intents_host.h" |
| #include "content/public/common/content_restriction.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/page_zoom.h" |
| #include "grit/chromium_strings.h" |
| #include "grit/generated_resources.h" |
| #include "grit/locale_settings.h" |
| #include "grit/theme_resources_standard.h" |
| #include "net/base/cookie_monster.h" |
| #include "net/base/net_util.h" |
| #include "net/base/registry_controlled_domain.h" |
| #include "net/url_request/url_request_context.h" |
| #include "ui/base/animation/animation.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/gfx/point.h" |
| #include "webkit/glue/web_intent_data.h" |
| #include "webkit/glue/webkit_glue.h" |
| #include "webkit/glue/window_open_disposition.h" |
| |
| #if defined(OS_WIN) |
| #include "chrome/browser/autofill/autofill_ie_toolbar_import_win.h" |
| #include "chrome/browser/shell_integration.h" |
| #include "chrome/browser/ssl/ssl_error_info.h" |
| #include "chrome/browser/task_manager/task_manager.h" |
| #include "chrome/browser/ui/view_ids.h" |
| #include "chrome/browser/ui/views/location_bar/location_bar_view.h" |
| #include "ui/base/win/shell.h" |
| #endif // OS_WIN |
| |
| #if defined(OS_MACOSX) |
| #include "content/browser/find_pasteboard.h" |
| #endif |
| |
| #if defined(OS_CHROMEOS) |
| #include "chrome/browser/chromeos/boot_times_loader.h" |
| #include "chrome/browser/chromeos/cros/cros_library.h" |
| #include "chrome/browser/chromeos/cros/screen_lock_library.h" |
| #include "chrome/browser/ui/webui/active_downloads_ui.h" |
| #endif |
| |
| #if !defined(OS_CHROMEOS) || defined(USE_AURA) |
| #include "chrome/browser/download/download_shelf.h" |
| #endif |
| |
| #if defined(FILE_MANAGER_EXTENSION) |
| #include "chrome/browser/extensions/file_manager_util.h" |
| #endif |
| |
| using base::TimeDelta; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| namespace { |
| |
| // The URL to be loaded to display Help. |
| const char kHelpContentUrl[] = |
| #if defined(OS_CHROMEOS) |
| #if defined(OFFICIAL_BUILD) |
| "chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html"; |
| #else |
| "https://www.google.com/support/chromeos/"; |
| #endif |
| #else |
| "https://www.google.com/support/chrome/"; |
| #endif |
| |
| // The URL to be opened when the Help link on the Autofill dialog is clicked. |
| const char kAutofillHelpUrl[] = |
| #if defined(OS_CHROMEOS) |
| "https://www.google.com/support/chromeos/bin/answer.py?answer=142893"; |
| #else |
| "https://www.google.com/support/chrome/bin/answer.py?answer=142893"; |
| #endif |
| |
| // The URL to be loaded to display the "Report a broken page" form. |
| const char kBrokenPageUrl[] = |
| "https://www.google.com/support/chrome/bin/request.py?contact_type=" |
| "broken_website&format=inproduct&p.page_title=$1&p.page_url=$2"; |
| |
| // The URL for the privacy dashboard. |
| const char kPrivacyDashboardUrl[] = "https://www.google.com/dashboard"; |
| |
| // How long we wait before updating the browser chrome while loading a page. |
| const int kUIUpdateCoalescingTimeMS = 200; |
| |
| const char kHashMark[] = "#"; |
| |
| // Returns |true| if entry has an internal chrome:// URL, |false| otherwise. |
| bool HasInternalURL(const NavigationEntry* entry) { |
| if (!entry) |
| return false; |
| |
| // Check the |virtual_url()| first. This catches regular chrome:// URLs |
| // including URLs that were rewritten (such as chrome://bookmarks). |
| if (entry->virtual_url().SchemeIs(chrome::kChromeUIScheme)) |
| return true; |
| |
| // If the |virtual_url()| isn't a chrome:// URL, check if it's actually |
| // view-source: of a chrome:// URL. |
| if (entry->virtual_url().SchemeIs(chrome::kViewSourceScheme)) |
| return entry->url().SchemeIs(chrome::kChromeUIScheme); |
| |
| return false; |
| } |
| |
| // Get the launch URL for a given extension, with optional override/fallback. |
| // |override_url|, if non-empty, will be preferred over the extension's |
| // launch url. |
| GURL UrlForExtension(const Extension* extension, const GURL& override_url) { |
| if (!extension) |
| return override_url; |
| |
| GURL url; |
| if (!override_url.is_empty()) { |
| DCHECK(extension->web_extent().MatchesURL(override_url)); |
| url = override_url; |
| } else { |
| url = extension->GetFullLaunchURL(); |
| } |
| |
| // For extensions lacking launch urls, determine a reasonable fallback. |
| if (!url.is_valid()) { |
| url = extension->options_url(); |
| if (!url.is_valid()) { |
| url = GURL(std::string(chrome::kChromeUISettingsURL) + |
| chrome::kExtensionsSubPage); |
| } |
| } |
| |
| return url; |
| } |
| |
| } // namespace |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Browser, CreateParams: |
| |
| Browser::CreateParams::CreateParams(Type type, Profile* profile) |
| : type(type), |
| profile(profile) { |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, Constructors, Creation, Showing: |
| |
| Browser::Browser(Type type, Profile* profile) |
| : type_(type), |
| profile_(profile), |
| window_(NULL), |
| ALLOW_THIS_IN_INITIALIZER_LIST( |
| tab_handler_(TabHandler::CreateTabHandler(this))), |
| command_updater_(this), |
| toolbar_model_(this), |
| chrome_updater_factory_(this), |
| is_attempting_to_close_browser_(false), |
| cancel_download_confirmation_state_(NOT_PROMPTED), |
| show_state_(ui::SHOW_STATE_DEFAULT), |
| is_session_restore_(false), |
| weak_factory_(this), |
| block_command_execution_(false), |
| last_blocked_command_id_(-1), |
| last_blocked_command_disposition_(CURRENT_TAB), |
| pending_web_app_action_(NONE), |
| ALLOW_THIS_IN_INITIALIZER_LIST( |
| tab_restore_service_delegate_( |
| new BrowserTabRestoreServiceDelegate(this))), |
| ALLOW_THIS_IN_INITIALIZER_LIST( |
| synced_window_delegate_( |
| new BrowserSyncedWindowDelegate(this))), |
| bookmark_bar_state_(BookmarkBar::HIDDEN), |
| window_has_shown_(false) { |
| registrar_.Add(this, content::NOTIFICATION_SSL_VISIBLE_STATE_CHANGED, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, |
| content::Source<Profile>(profile_->GetOriginalProfile())); |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
| content::Source<Profile>(profile_->GetOriginalProfile())); |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| content::Source<Profile>(profile_->GetOriginalProfile())); |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, |
| content::Source<Profile>(profile_->GetOriginalProfile())); |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, |
| content::NotificationService::AllSources()); |
| registrar_.Add( |
| this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED, |
| content::Source<ThemeService>( |
| ThemeServiceFactory::GetForProfile(profile_))); |
| registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENT_SETTINGS_CHANGED, |
| content::NotificationService::AllSources()); |
| |
| PrefService* local_state = g_browser_process->local_state(); |
| if (local_state) { |
| local_pref_registrar_.Init(local_state); |
| local_pref_registrar_.Add(prefs::kPrintingEnabled, this); |
| local_pref_registrar_.Add(prefs::kAllowFileSelectionDialogs, this); |
| local_pref_registrar_.Add(prefs::kMetricsReportingEnabled, this); |
| } |
| |
| profile_pref_registrar_.Init(profile_->GetPrefs()); |
| profile_pref_registrar_.Add(prefs::kDevToolsDisabled, this); |
| profile_pref_registrar_.Add(prefs::kEditBookmarksEnabled, this); |
| profile_pref_registrar_.Add(prefs::kShowBookmarkBar, this); |
| profile_pref_registrar_.Add(prefs::kHomePage, this); |
| profile_pref_registrar_.Add(prefs::kInstantEnabled, this); |
| profile_pref_registrar_.Add(prefs::kIncognitoModeAvailability, this); |
| profile_pref_registrar_.Add(prefs::kSearchSuggestEnabled, this); |
| |
| InitCommandState(); |
| BrowserList::AddBrowser(this); |
| |
| // NOTE: These prefs all need to be explicitly destroyed in the destructor |
| // or you'll get a nasty surprise when you run the incognito tests. |
| encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector, |
| profile_->GetPrefs(), NULL); |
| |
| tab_restore_service_ = TabRestoreServiceFactory::GetForProfile(profile); |
| if (tab_restore_service_) { |
| tab_restore_service_->AddObserver(this); |
| TabRestoreServiceChanged(tab_restore_service_); |
| } |
| |
| if (profile_->GetProfileSyncService()) |
| profile_->GetProfileSyncService()->AddObserver(this); |
| |
| CreateInstantIfNecessary(); |
| |
| // Make sure TabFinder has been created. This does nothing if TabFinder is |
| // not enabled. |
| TabFinder::GetInstance(); |
| |
| UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_INIT); |
| } |
| |
| Browser::~Browser() { |
| if (profile_->GetProfileSyncService()) |
| profile_->GetProfileSyncService()->RemoveObserver(this); |
| |
| BrowserList::RemoveBrowser(this); |
| |
| #if !defined(OS_MACOSX) |
| if (!BrowserList::HasBrowserWithProfile(profile_)) { |
| // We're the last browser window with this profile. We need to nuke the |
| // TabRestoreService, which will start the shutdown of the |
| // NavigationControllers and allow for proper shutdown. If we don't do this |
| // chrome won't shutdown cleanly, and may end up crashing when some |
| // thread tries to use the IO thread (or another thread) that is no longer |
| // valid. |
| // This isn't a valid assumption for Mac OS, as it stays running after |
| // the last browser has closed. The Mac equivalent is in its app |
| // controller. |
| TabRestoreServiceFactory::ResetForProfile(profile_); |
| } |
| #endif |
| |
| SessionService* session_service = |
| SessionServiceFactory::GetForProfile(profile_); |
| if (session_service) |
| session_service->WindowClosed(session_id_); |
| |
| TabRestoreService* tab_restore_service = |
| TabRestoreServiceFactory::GetForProfile(profile()); |
| if (tab_restore_service) |
| tab_restore_service->BrowserClosed(tab_restore_service_delegate()); |
| |
| profile_pref_registrar_.RemoveAll(); |
| local_pref_registrar_.RemoveAll(); |
| |
| encoding_auto_detect_.Destroy(); |
| |
| if (profile_->IsOffTheRecord() && |
| !BrowserList::IsOffTheRecordSessionActiveForProfile(profile_)) { |
| // An incognito profile is no longer needed, this indirectly |
| // frees its cache and cookies. |
| profile_->GetOriginalProfile()->DestroyOffTheRecordProfile(); |
| } |
| |
| // There may be pending file dialogs, we need to tell them that we've gone |
| // away so they don't try and call back to us. |
| if (select_file_dialog_.get()) |
| select_file_dialog_->ListenerDestroyed(); |
| |
| TabRestoreServiceDestroyed(tab_restore_service_); |
| } |
| |
| bool Browser::IsFullscreenForTab() const { |
| return fullscreen_controller_->IsFullscreenForTab(); |
| } |
| |
| // static |
| Browser* Browser::Create(Profile* profile) { |
| Browser* browser = new Browser(TYPE_TABBED, profile); |
| browser->InitBrowserWindow(); |
| return browser; |
| } |
| |
| // static |
| Browser* Browser::CreateWithParams(const CreateParams& params) { |
| Browser* browser = new Browser(params.type, params.profile); |
| browser->app_name_ = params.app_name; |
| browser->set_override_bounds(params.initial_bounds); |
| browser->InitBrowserWindow(); |
| return browser; |
| } |
| |
| // static |
| Browser* Browser::CreateForType(Type type, Profile* profile) { |
| CreateParams params(type, profile); |
| return CreateWithParams(params); |
| } |
| |
| // static |
| Browser* Browser::CreateForApp(Type type, |
| const std::string& app_name, |
| const gfx::Rect& window_bounds, |
| Profile* profile) { |
| DCHECK(type != TYPE_TABBED); |
| DCHECK(!app_name.empty()); |
| |
| RegisterAppPrefs(app_name, profile); |
| |
| if (type == TYPE_PANEL && |
| CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisablePanels)) { |
| type = TYPE_POPUP; |
| } |
| #if defined(TOOLKIT_GTK) |
| // Panels are only supported on a white list of window managers for Linux. |
| if (type == TYPE_PANEL) { |
| ui::WindowManagerName wm_type = ui::GuessWindowManager(); |
| if (wm_type != ui::WM_COMPIZ && |
| wm_type != ui::WM_ICE_WM && |
| wm_type != ui::WM_KWIN && |
| wm_type != ui::WM_METACITY && |
| wm_type != ui::WM_MUTTER) { |
| type = TYPE_POPUP; |
| } |
| } |
| #endif // TOOLKIT_GTK |
| |
| CreateParams params(type, profile); |
| params.app_name = app_name; |
| params.initial_bounds = window_bounds; |
| return CreateWithParams(params); |
| } |
| |
| // static |
| Browser* Browser::CreateForDevTools(Profile* profile) { |
| #if defined(OS_CHROMEOS) |
| CreateParams params(TYPE_TABBED, profile); |
| #else |
| CreateParams params(TYPE_POPUP, profile); |
| #endif |
| params.app_name = DevToolsWindow::kDevToolsApp; |
| return CreateWithParams(params); |
| } |
| |
| void Browser::InitBrowserWindow() { |
| DCHECK(!window_); |
| |
| window_ = CreateBrowserWindow(); |
| fullscreen_controller_ = new FullscreenController(window_, profile_, this); |
| |
| #if defined(OS_WIN) && !defined(USE_AURA) |
| { |
| // TODO: This might hit the disk |
| // http://code.google.com/p/chromium/issues/detail?id=61638 |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| |
| // Set the app user model id for this application to that of the application |
| // name. See http://crbug.com/7028. |
| ui::win::SetAppIdForWindow( |
| is_app() && !is_type_panel() ? |
| ShellIntegration::GetAppId(UTF8ToWide(app_name_), profile_->GetPath()) : |
| ShellIntegration::GetChromiumAppId(profile_->GetPath()), |
| window()->GetNativeHandle()); |
| |
| if (is_type_panel()) { |
| ui::win::SetAppIconForWindow( |
| ShellIntegration::GetChromiumIconPath(), |
| window()->GetNativeHandle()); |
| } |
| } |
| #endif |
| |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_BROWSER_WINDOW_READY, |
| content::Source<Browser>(this), |
| content::NotificationService::NoDetails()); |
| |
| PrefService* local_state = g_browser_process->local_state(); |
| if (local_state && local_state->FindPreference( |
| prefs::kAutofillPersonalDataManagerFirstRun) && |
| local_state->GetBoolean(prefs::kAutofillPersonalDataManagerFirstRun)) { |
| // Notify PDM that this is a first run. |
| #if defined(OS_WIN) |
| ImportAutofillDataWin(PersonalDataManagerFactory::GetForProfile(profile_)); |
| #endif // defined(OS_WIN) |
| // Reset the preference so we don't call it again for subsequent windows. |
| local_state->ClearPref(prefs::kAutofillPersonalDataManagerFirstRun); |
| } |
| |
| // Permanently dismiss ntp4 bubble for new users. |
| if (FirstRun::IsChromeFirstRun()) |
| NewTabPageHandler::DismissIntroMessage(local_state); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Getters & Setters |
| |
| FindBarController* Browser::GetFindBarController() { |
| if (!find_bar_controller_.get()) { |
| FindBar* find_bar = window_->CreateFindBar(); |
| find_bar_controller_.reset(new FindBarController(find_bar)); |
| find_bar->SetFindBarController(find_bar_controller_.get()); |
| find_bar_controller_->ChangeTabContents(GetSelectedTabContentsWrapper()); |
| find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true); |
| } |
| return find_bar_controller_.get(); |
| } |
| |
| bool Browser::HasFindBarController() const { |
| return find_bar_controller_.get() != NULL; |
| } |
| |
| bool Browser::is_app() const { |
| return !app_name_.empty(); |
| } |
| |
| bool Browser::is_devtools() const { |
| return app_name_ == DevToolsWindow::kDevToolsApp; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, Creation Helpers: |
| |
| // static |
| void Browser::OpenEmptyWindow(Profile* profile) { |
| Browser* browser = Browser::Create(profile); |
| browser->AddBlankTab(true); |
| browser->window()->Show(); |
| } |
| |
| // static |
| void Browser::OpenWindowWithRestoredTabs(Profile* profile) { |
| TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile); |
| if (service) |
| service->RestoreMostRecentEntry(NULL); |
| } |
| |
| // static |
| void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) { |
| Browser* browser = GetOrCreateTabbedBrowser( |
| profile->GetOffTheRecordProfile()); |
| browser->AddSelectedTabWithURL(url, content::PAGE_TRANSITION_LINK); |
| browser->window()->Show(); |
| } |
| |
| // static |
| TabContents* Browser::OpenApplication( |
| Profile* profile, |
| const Extension* extension, |
| extension_misc::LaunchContainer container, |
| const GURL& override_url, |
| WindowOpenDisposition disposition) { |
| TabContents* tab = NULL; |
| ExtensionPrefs* prefs = profile->GetExtensionService()->extension_prefs(); |
| prefs->SetActiveBit(extension->id(), true); |
| |
| UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchContainer", container, 100); |
| |
| switch (container) { |
| case extension_misc::LAUNCH_WINDOW: |
| case extension_misc::LAUNCH_PANEL: |
| case extension_misc::LAUNCH_SHELL: |
| tab = Browser::OpenApplicationWindow(profile, extension, container, |
| override_url, NULL); |
| break; |
| case extension_misc::LAUNCH_TAB: { |
| tab = Browser::OpenApplicationTab(profile, extension, override_url, |
| disposition); |
| break; |
| } |
| default: |
| NOTREACHED(); |
| break; |
| } |
| return tab; |
| } |
| |
| // static |
| TabContents* Browser::OpenApplicationWindow( |
| Profile* profile, |
| const Extension* extension, |
| extension_misc::LaunchContainer container, |
| const GURL& url_input, |
| Browser** app_browser) { |
| DCHECK(!url_input.is_empty() || extension); |
| GURL url = UrlForExtension(extension, url_input); |
| |
| std::string app_name; |
| app_name = extension ? |
| web_app::GenerateApplicationNameFromExtensionId(extension->id()) : |
| web_app::GenerateApplicationNameFromURL(url); |
| |
| Type type = TYPE_POPUP; |
| if (extension) { |
| switch (container) { |
| case extension_misc::LAUNCH_PANEL: |
| type = TYPE_PANEL; |
| break; |
| case extension_misc::LAUNCH_SHELL: |
| type = TYPE_SHELL; |
| break; |
| default: break; |
| } |
| } |
| |
| gfx::Rect window_bounds; |
| if (extension) { |
| window_bounds.set_width(extension->launch_width()); |
| window_bounds.set_height(extension->launch_height()); |
| } |
| |
| Browser* browser = Browser::CreateForApp(type, app_name, window_bounds, |
| profile); |
| |
| if (app_browser) |
| *app_browser = browser; |
| |
| TabContentsWrapper* wrapper = |
| browser->AddSelectedTabWithURL(url, content::PAGE_TRANSITION_START_PAGE); |
| TabContents* contents = wrapper->tab_contents(); |
| contents->GetMutableRendererPrefs()->can_accept_load_drops = false; |
| contents->render_view_host()->SyncRendererPrefs(); |
| browser->window()->Show(); |
| |
| // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial |
| // focus explicitly. |
| contents->view()->SetInitialFocus(); |
| return contents; |
| } |
| |
| TabContents* Browser::OpenAppShortcutWindow(Profile* profile, |
| const GURL& url, |
| bool update_shortcut) { |
| Browser* app_browser; |
| TabContents* tab = OpenApplicationWindow( |
| profile, |
| NULL, // this is a URL app. No extension. |
| extension_misc::LAUNCH_WINDOW, |
| url, |
| &app_browser); |
| |
| if (!tab) |
| return NULL; |
| |
| if (update_shortcut) { |
| // Set UPDATE_SHORTCUT as the pending web app action. This action is picked |
| // up in LoadingStateChanged to schedule a GetApplicationInfo. And when |
| // the web app info is available, TabContents notifies Browser via |
| // OnDidGetApplicationInfo, which calls |
| // web_app::UpdateShortcutForTabContents when it sees UPDATE_SHORTCUT as |
| // pending web app action. |
| app_browser->pending_web_app_action_ = UPDATE_SHORTCUT; |
| } |
| return tab; |
| } |
| |
| // static |
| TabContents* Browser::OpenApplicationTab(Profile* profile, |
| const Extension* extension, |
| const GURL& override_url, |
| WindowOpenDisposition disposition) { |
| Browser* browser = BrowserList::FindTabbedBrowser(profile, false); |
| TabContents* contents = NULL; |
| if (!browser) { |
| // No browser for this profile, need to open a new one. |
| browser = Browser::Create(profile); |
| browser->window()->Show(); |
| // There's no current tab in this browser window, so add a new one. |
| disposition = NEW_FOREGROUND_TAB; |
| } |
| |
| // Check the prefs for overridden mode. |
| ExtensionService* extension_service = profile->GetExtensionService(); |
| DCHECK(extension_service); |
| |
| ExtensionPrefs::LaunchType launch_type = |
| extension_service->extension_prefs()->GetLaunchType( |
| extension->id(), ExtensionPrefs::LAUNCH_DEFAULT); |
| UMA_HISTOGRAM_ENUMERATION("Extensions.AppTabLaunchType", launch_type, 100); |
| |
| static bool default_apps_trial_exists = |
| base::FieldTrialList::TrialExists(kDefaultAppsTrial_Name); |
| if (default_apps_trial_exists) { |
| UMA_HISTOGRAM_ENUMERATION( |
| base::FieldTrial::MakeName("Extensions.AppTabLaunchType", |
| kDefaultAppsTrial_Name), |
| launch_type, 100); |
| } |
| |
| int add_type = TabStripModel::ADD_ACTIVE; |
| if (launch_type == ExtensionPrefs::LAUNCH_PINNED) |
| add_type |= TabStripModel::ADD_PINNED; |
| |
| GURL extension_url = UrlForExtension(extension, override_url); |
| // TODO(erikkay): START_PAGE doesn't seem like the right transition in all |
| // cases. |
| browser::NavigateParams params(browser, extension_url, |
| content::PAGE_TRANSITION_START_PAGE); |
| params.tabstrip_add_types = add_type; |
| params.disposition = disposition; |
| |
| if (disposition == CURRENT_TAB) { |
| TabContents* existing_tab = browser->GetSelectedTabContents(); |
| TabStripModel* model = browser->tabstrip_model(); |
| int tab_index = model->GetWrapperIndex(existing_tab); |
| |
| existing_tab->OpenURL(OpenURLParams(extension_url, existing_tab->GetURL(), |
| disposition, content::PAGE_TRANSITION_LINK, false)); |
| if (params.tabstrip_add_types & TabStripModel::ADD_PINNED) { |
| model->SetTabPinned(tab_index, true); |
| tab_index = model->GetWrapperIndex(existing_tab); |
| } |
| if (params.tabstrip_add_types & TabStripModel::ADD_ACTIVE) |
| model->ActivateTabAt(tab_index, true); |
| |
| contents = existing_tab; |
| } else { |
| browser::Navigate(¶ms); |
| contents = params.target_contents->tab_contents(); |
| } |
| |
| // TODO(skerner): If we are already in full screen mode, and the user |
| // set the app to open as a regular or pinned tab, what should happen? |
| // Today we open the tab, but stay in full screen mode. Should we leave |
| // full screen mode in this case? |
| if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN && |
| !browser->window()->IsFullscreen()) { |
| browser->ToggleFullscreenMode(false); |
| } |
| |
| return contents; |
| } |
| |
| // static |
| void Browser::OpenBookmarkManagerWindow(Profile* profile) { |
| Browser* browser = Browser::Create(profile); |
| browser->OpenBookmarkManager(); |
| browser->window()->Show(); |
| } |
| |
| #if defined(OS_MACOSX) |
| // static |
| void Browser::OpenHistoryWindow(Profile* profile) { |
| Browser* browser = Browser::Create(profile); |
| browser->ShowHistoryTab(); |
| browser->window()->Show(); |
| } |
| |
| // static |
| void Browser::OpenDownloadsWindow(Profile* profile) { |
| Browser* browser = Browser::Create(profile); |
| browser->ShowDownloadsTab(); |
| browser->window()->Show(); |
| } |
| |
| // static |
| void Browser::OpenHelpWindow(Profile* profile) { |
| Browser* browser = Browser::Create(profile); |
| browser->ShowHelpTab(); |
| browser->window()->Show(); |
| } |
| |
| // static |
| void Browser::OpenOptionsWindow(Profile* profile) { |
| Browser* browser = Browser::Create(profile); |
| browser->OpenOptionsDialog(); |
| browser->window()->Show(); |
| } |
| |
| // static |
| void Browser::OpenClearBrowsingDataDialogWindow(Profile* profile) { |
| Browser* browser = Browser::Create(profile); |
| browser->OpenClearBrowsingDataDialog(); |
| browser->window()->Show(); |
| } |
| |
| // static |
| void Browser::OpenImportSettingsDialogWindow(Profile* profile) { |
| Browser* browser = Browser::Create(profile); |
| browser->OpenImportSettingsDialog(); |
| browser->window()->Show(); |
| } |
| |
| // static |
| void Browser::OpenInstantConfirmDialogWindow(Profile* profile) { |
| Browser* browser = Browser::Create(profile); |
| browser->OpenInstantConfirmDialog(); |
| browser->window()->Show(); |
| } |
| #endif |
| |
| // static |
| void Browser::OpenExtensionsWindow(Profile* profile) { |
| Browser* browser = Browser::Create(profile); |
| browser->ShowExtensionsTab(); |
| browser->window()->Show(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, State Storage and Retrieval for UI: |
| |
| std::string Browser::GetWindowPlacementKey() const { |
| std::string name(prefs::kBrowserWindowPlacement); |
| if (!app_name_.empty()) { |
| name.append("_"); |
| name.append(app_name_); |
| } |
| return name; |
| } |
| |
| bool Browser::ShouldSaveWindowPlacement() const { |
| switch (type_) { |
| case TYPE_TABBED: |
| return true; |
| case TYPE_POPUP: |
| // Only save the window placement of popups if they are restored, |
| // or the window belongs to DevTools. |
| return browser_defaults::kRestorePopups || is_devtools(); |
| case TYPE_PANEL: |
| // Do not save the window placement of panels. |
| return false; |
| case TYPE_SHELL: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| void Browser::SaveWindowPlacement(const gfx::Rect& bounds, |
| ui::WindowShowState show_state) { |
| // Save to the session storage service, used when reloading a past session. |
| // Note that we don't want to be the ones who cause lazy initialization of |
| // the session service. This function gets called during initial window |
| // showing, and we don't want to bring in the session service this early. |
| SessionService* session_service = |
| SessionServiceFactory::GetForProfileIfExisting(profile()); |
| if (session_service) |
| session_service->SetWindowBounds(session_id_, bounds, show_state); |
| } |
| |
| gfx::Rect Browser::GetSavedWindowBounds() const { |
| const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode); |
| bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode); |
| if (record_mode || playback_mode) { |
| // In playback/record mode we always fix the size of the browser and |
| // move it to (0,0). The reason for this is two reasons: First we want |
| // resize/moves in the playback to still work, and Second we want |
| // playbacks to work (as much as possible) on machines w/ different |
| // screen sizes. |
| return gfx::Rect(0, 0, 800, 600); |
| } |
| |
| gfx::Rect restored_bounds = override_bounds_; |
| WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, this, |
| &restored_bounds); |
| return restored_bounds; |
| } |
| |
| ui::WindowShowState Browser::GetSavedWindowShowState() const { |
| if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStartMaximized)) |
| return ui::SHOW_STATE_MAXIMIZED; |
| |
| if (show_state_ != ui::SHOW_STATE_DEFAULT) |
| return show_state_; |
| |
| const DictionaryValue* window_pref = |
| profile()->GetPrefs()->GetDictionary(GetWindowPlacementKey().c_str()); |
| bool maximized = false; |
| window_pref->GetBoolean("maximized", &maximized); |
| |
| return maximized ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL; |
| } |
| |
| SkBitmap Browser::GetCurrentPageIcon() const { |
| TabContentsWrapper* contents = GetSelectedTabContentsWrapper(); |
| // |contents| can be NULL since GetCurrentPageIcon() is called by the window |
| // during the window's creation (before tabs have been added). |
| return contents ? contents->favicon_tab_helper()->GetFavicon() : SkBitmap(); |
| } |
| |
| string16 Browser::GetWindowTitleForCurrentTab() const { |
| TabContents* contents = GetSelectedTabContents(); |
| string16 title; |
| |
| // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the |
| // window during the window's creation (before tabs have been added). |
| if (contents) { |
| title = contents->GetTitle(); |
| FormatTitleForDisplay(&title); |
| } |
| if (title.empty()) |
| title = TabContentsWrapper::GetDefaultTitle(); |
| |
| #if defined(OS_MACOSX) || defined(OS_CHROMEOS) |
| // On Mac or ChromeOS, we don't want to suffix the page title with |
| // the application name. |
| return title; |
| #else |
| int string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT; |
| // Don't append the app name to window titles on app frames and app popups |
| if (is_app()) |
| string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT_NO_LOGO; |
| return l10n_util::GetStringFUTF16(string_id, title); |
| #endif |
| } |
| |
| // static |
| void Browser::FormatTitleForDisplay(string16* title) { |
| size_t current_index = 0; |
| size_t match_index; |
| while ((match_index = title->find(L'\n', current_index)) != string16::npos) { |
| title->replace(match_index, 1, string16()); |
| current_index = match_index; |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, OnBeforeUnload handling: |
| |
| bool Browser::TabsNeedBeforeUnloadFired() { |
| if (tabs_needing_before_unload_fired_.empty()) { |
| for (int i = 0; i < tab_count(); ++i) { |
| TabContents* contents = GetTabContentsAt(i); |
| if (contents->NeedToFireBeforeUnload()) |
| tabs_needing_before_unload_fired_.insert(contents); |
| } |
| } |
| return !tabs_needing_before_unload_fired_.empty(); |
| } |
| |
| bool Browser::ShouldCloseWindow() { |
| if (!CanCloseWithInProgressDownloads()) |
| return false; |
| |
| if (HasCompletedUnloadProcessing()) |
| return IsClosingPermitted(); |
| |
| is_attempting_to_close_browser_ = true; |
| |
| if (!TabsNeedBeforeUnloadFired()) |
| return IsClosingPermitted(); |
| |
| ProcessPendingTabs(); |
| return false; |
| } |
| |
| void Browser::OnWindowClosing() { |
| if (!ShouldCloseWindow()) |
| return; |
| |
| bool exiting = false; |
| |
| // Application should shutdown on last window close if the user is explicitly |
| // trying to quit, or if there is nothing keeping the browser alive (such as |
| // AppController on the Mac, or BackgroundContentsService for background |
| // pages). |
| bool should_quit_if_last_browser = |
| browser_shutdown::IsTryingToQuit() || !BrowserList::WillKeepAlive(); |
| |
| if (should_quit_if_last_browser && BrowserList::size() == 1) { |
| browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE); |
| exiting = true; |
| } |
| |
| // Don't use GetForProfileIfExisting here, we want to force creation of the |
| // session service so that user can restore what was open. |
| SessionService* session_service = |
| SessionServiceFactory::GetForProfile(profile()); |
| if (session_service) |
| session_service->WindowClosing(session_id()); |
| |
| TabRestoreService* tab_restore_service = |
| TabRestoreServiceFactory::GetForProfile(profile()); |
| if (tab_restore_service && is_type_tabbed() && tab_count()) |
| tab_restore_service->BrowserClosing(tab_restore_service_delegate()); |
| |
| // TODO(sky): convert session/tab restore to use notification. |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_BROWSER_CLOSING, |
| content::Source<Browser>(this), |
| content::Details<bool>(&exiting)); |
| |
| CloseAllTabs(); |
| } |
| |
| void Browser::OnWindowActivated() { |
| // On some platforms we want to automatically reload tabs that are |
| // killed when the user selects them. |
| TabContents* contents = GetSelectedTabContents(); |
| if (contents && contents->crashed_status() == |
| base::TERMINATION_STATUS_PROCESS_WAS_KILLED) { |
| if (CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kReloadKilledTabs)) { |
| Reload(CURRENT_TAB); |
| } |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // In-progress download termination handling: |
| |
| void Browser::InProgressDownloadResponse(bool cancel_downloads) { |
| if (cancel_downloads) { |
| cancel_download_confirmation_state_ = RESPONSE_RECEIVED; |
| CloseWindow(); |
| return; |
| } |
| |
| // Sets the confirmation state to NOT_PROMPTED so that if the user tries to |
| // close again we'll show the warning again. |
| cancel_download_confirmation_state_ = NOT_PROMPTED; |
| |
| // Show the download page so the user can figure-out what downloads are still |
| // in-progress. |
| ShowDownloadsTab(); |
| } |
| |
| Browser::DownloadClosePreventionType Browser::OkToCloseWithInProgressDownloads( |
| int* num_downloads_blocking) const { |
| DCHECK(num_downloads_blocking); |
| *num_downloads_blocking = 0; |
| |
| if (is_attempting_to_close_browser_) |
| return DOWNLOAD_CLOSE_OK; |
| |
| // If we're not running a full browser process with a profile manager |
| // (testing), it's ok to close the browser. |
| if (!g_browser_process->profile_manager()) |
| return DOWNLOAD_CLOSE_OK; |
| |
| int total_download_count = DownloadService::DownloadCountAllProfiles(); |
| if (total_download_count == 0) |
| return DOWNLOAD_CLOSE_OK; // No downloads; can definitely close. |
| |
| // Figure out how many windows are open total, and associated with this |
| // profile, that are relevant for the ok-to-close decision. |
| int profile_window_count = 0; |
| int total_window_count = 0; |
| for (BrowserList::const_iterator iter = BrowserList::begin(); |
| iter != BrowserList::end(); ++iter) { |
| // Don't count this browser window or any other in the process of closing. |
| Browser* const browser = *iter; |
| // Check is_attempting_to_close_browser_ as window closing may be |
| // delayed, and windows that are in the process of closing don't |
| // count against our totals. |
| if (browser == this || browser->is_attempting_to_close_browser_) |
| continue; |
| |
| if ((*iter)->profile() == profile()) |
| profile_window_count++; |
| total_window_count++; |
| } |
| |
| // If there aren't any other windows, we're at browser shutdown, |
| // which would cancel all current downloads. |
| if (total_window_count == 0) { |
| *num_downloads_blocking = total_download_count; |
| return DOWNLOAD_CLOSE_BROWSER_SHUTDOWN; |
| } |
| |
| // If there aren't any other windows on our profile, and we're an incognito |
| // profile, and there are downloads associated with that profile, |
| // those downloads would be cancelled by our window (-> profile) close. |
| DownloadService* download_service = |
| DownloadServiceFactory::GetForProfile(profile()); |
| if (profile_window_count == 0 && download_service->DownloadCount() > 0 && |
| profile()->IsOffTheRecord()) { |
| *num_downloads_blocking = download_service->DownloadCount(); |
| return DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE; |
| } |
| |
| // Those are the only conditions under which we will block shutdown. |
| return DOWNLOAD_CLOSE_OK; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Browser, TabStripModel pass-thrus: |
| |
| int Browser::tab_count() const { |
| return tab_handler_->GetTabStripModel()->count(); |
| } |
| |
| int Browser::active_index() const { |
| return tab_handler_->GetTabStripModel()->active_index(); |
| } |
| |
| int Browser::GetIndexOfController( |
| const NavigationController* controller) const { |
| return tab_handler_->GetTabStripModel()->GetIndexOfController(controller); |
| } |
| |
| TabContentsWrapper* Browser::GetSelectedTabContentsWrapper() const { |
| return tabstrip_model()->GetActiveTabContents(); |
| } |
| |
| TabContentsWrapper* Browser::GetTabContentsWrapperAt(int index) const { |
| return tabstrip_model()->GetTabContentsAt(index); |
| } |
| |
| TabContents* Browser::GetSelectedTabContents() const { |
| TabContentsWrapper* wrapper = GetSelectedTabContentsWrapper(); |
| if (wrapper) |
| return wrapper->tab_contents(); |
| return NULL; |
| } |
| |
| TabContents* Browser::GetTabContentsAt(int index) const { |
| TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index); |
| if (wrapper) |
| return wrapper->tab_contents(); |
| return NULL; |
| } |
| |
| void Browser::ActivateTabAt(int index, bool user_gesture) { |
| tab_handler_->GetTabStripModel()->ActivateTabAt(index, user_gesture); |
| } |
| |
| bool Browser::IsTabPinned(int index) const { |
| return tabstrip_model()->IsTabPinned(index); |
| } |
| |
| bool Browser::IsTabDiscarded(int index) const { |
| return tab_handler_->GetTabStripModel()->IsTabDiscarded(index); |
| } |
| |
| void Browser::CloseAllTabs() { |
| tab_handler_->GetTabStripModel()->CloseAllTabs(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Browser, Tab adding/showing functions: |
| |
| bool Browser::IsTabStripEditable() const { |
| return window()->IsTabStripEditable(); |
| } |
| |
| int Browser::GetIndexForInsertionDuringRestore(int relative_index) { |
| return (tab_handler_->GetTabStripModel()->insertion_policy() == |
| TabStripModel::INSERT_AFTER) ? tab_count() : relative_index; |
| } |
| |
| TabContentsWrapper* Browser::AddSelectedTabWithURL( |
| const GURL& url, |
| content::PageTransition transition) { |
| browser::NavigateParams params(this, url, transition); |
| params.disposition = NEW_FOREGROUND_TAB; |
| browser::Navigate(¶ms); |
| return params.target_contents; |
| } |
| |
| TabContents* Browser::AddTab(TabContentsWrapper* tab_contents, |
| content::PageTransition type) { |
| tab_handler_->GetTabStripModel()->AddTabContents( |
| tab_contents, -1, type, TabStripModel::ADD_ACTIVE); |
| return tab_contents->tab_contents(); |
| } |
| |
| void Browser::AddTabContents(TabContents* new_contents, |
| WindowOpenDisposition disposition, |
| const gfx::Rect& initial_pos, |
| bool user_gesture) { |
| AddNewContents(NULL, new_contents, disposition, initial_pos, user_gesture); |
| } |
| |
| void Browser::CloseTabContents(TabContents* contents) { |
| CloseContents(contents); |
| } |
| |
| gfx::NativeWindow Browser::BrowserShowHtmlDialog( |
| HtmlDialogUIDelegate* delegate, |
| gfx::NativeWindow parent_window, |
| DialogStyle style) { |
| #if defined(OS_CHROMEOS) |
| // For Chrome OS, first try to parent the dialog over the current browser -- |
| // it's likely to be maximized onscreen. If it isn't tabbed (e.g. it's a |
| // panel), find a browser that is. |
| parent_window = window_->GetNativeHandle(); |
| if (!is_type_tabbed()) { |
| Browser* tabbed_browser = BrowserList::FindTabbedBrowser(profile_, true); |
| if (tabbed_browser && tabbed_browser->window()) |
| parent_window = tabbed_browser->window()->GetNativeHandle(); |
| } |
| #endif // defined(OS_CHROMEOS) |
| if (!parent_window) |
| parent_window = window_->GetNativeHandle(); |
| |
| return browser::ShowHtmlDialog(parent_window, profile_, delegate, style); |
| } |
| |
| void Browser::BrowserRenderWidgetShowing() { |
| RenderWidgetShowing(); |
| } |
| |
| void Browser::BookmarkBarSizeChanged(bool is_animating) { |
| window_->ToolbarSizeChanged(is_animating); |
| } |
| |
| TabContents* Browser::AddRestoredTab( |
| const std::vector<TabNavigation>& navigations, |
| int tab_index, |
| int selected_navigation, |
| const std::string& extension_app_id, |
| bool select, |
| bool pin, |
| bool from_last_session, |
| SessionStorageNamespace* session_storage_namespace) { |
| GURL restore_url = navigations.at(selected_navigation).virtual_url(); |
| TabContentsWrapper* wrapper = TabContentsFactory( |
| profile(), |
| tab_util::GetSiteInstanceForNewTab(NULL, profile_, restore_url), |
| MSG_ROUTING_NONE, |
| GetSelectedTabContents(), |
| session_storage_namespace); |
| TabContents* new_tab = wrapper->tab_contents(); |
| wrapper->extension_tab_helper()->SetExtensionAppById(extension_app_id); |
| std::vector<NavigationEntry*> entries; |
| TabNavigation::CreateNavigationEntriesFromTabNavigations( |
| profile_, navigations, &entries); |
| new_tab->controller().Restore( |
| selected_navigation, from_last_session, &entries); |
| DCHECK_EQ(0u, entries.size()); |
| |
| int add_types = select ? TabStripModel::ADD_ACTIVE : |
| TabStripModel::ADD_NONE; |
| if (pin) { |
| tab_index = std::min(tab_index, tabstrip_model()->IndexOfFirstNonMiniTab()); |
| add_types |= TabStripModel::ADD_PINNED; |
| } |
| tab_handler_->GetTabStripModel()->InsertTabContentsAt(tab_index, wrapper, |
| add_types); |
| if (select) { |
| window_->Activate(); |
| } else { |
| // We set the size of the view here, before WebKit does its initial |
| // layout. If we don't, the initial layout of background tabs will be |
| // performed with a view width of 0, which may cause script outputs and |
| // anchor link location calculations to be incorrect even after a new |
| // layout with proper view dimensions. TabStripModel::AddTabContents() |
| // contains similar logic. |
| new_tab->view()->SizeContents(window_->GetRestoredBounds().size()); |
| new_tab->HideContents(); |
| } |
| SessionService* session_service = |
| SessionServiceFactory::GetForProfileIfExisting(profile_); |
| if (session_service) |
| session_service->TabRestored(wrapper, pin); |
| return new_tab; |
| } |
| |
| void Browser::ReplaceRestoredTab( |
| const std::vector<TabNavigation>& navigations, |
| int selected_navigation, |
| bool from_last_session, |
| const std::string& extension_app_id, |
| SessionStorageNamespace* session_storage_namespace) { |
| GURL restore_url = navigations.at(selected_navigation).virtual_url(); |
| TabContentsWrapper* wrapper = TabContentsFactory( |
| profile(), |
| tab_util::GetSiteInstanceForNewTab(NULL, profile_, restore_url), |
| MSG_ROUTING_NONE, |
| GetSelectedTabContents(), |
| session_storage_namespace); |
| wrapper->extension_tab_helper()->SetExtensionAppById(extension_app_id); |
| TabContents* replacement = wrapper->tab_contents(); |
| std::vector<NavigationEntry*> entries; |
| TabNavigation::CreateNavigationEntriesFromTabNavigations( |
| profile_, navigations, &entries); |
| replacement->controller().Restore( |
| selected_navigation, from_last_session, &entries); |
| DCHECK_EQ(0u, entries.size()); |
| |
| tab_handler_->GetTabStripModel()->ReplaceNavigationControllerAt( |
| tab_handler_->GetTabStripModel()->active_index(), |
| wrapper); |
| } |
| |
| bool Browser::CanRestoreTab() { |
| return command_updater_.IsCommandEnabled(IDC_RESTORE_TAB); |
| } |
| |
| bool Browser::NavigateToIndexWithDisposition(int index, |
| WindowOpenDisposition disp) { |
| NavigationController& controller = |
| GetOrCloneTabForDisposition(disp)->controller(); |
| if (index < 0 || index >= controller.entry_count()) |
| return false; |
| controller.GoToIndex(index); |
| return true; |
| } |
| |
| browser::NavigateParams Browser::GetSingletonTabNavigateParams( |
| const GURL& url) { |
| browser::NavigateParams params( |
| this, url, content::PAGE_TRANSITION_AUTO_BOOKMARK); |
| params.disposition = SINGLETON_TAB; |
| params.window_action = browser::NavigateParams::SHOW_WINDOW; |
| params.user_gesture = true; |
| return params; |
| } |
| |
| void Browser::ShowSingletonTab(const GURL& url) { |
| browser::NavigateParams params(GetSingletonTabNavigateParams(url)); |
| browser::Navigate(¶ms); |
| } |
| |
| void Browser::ShowSingletonTabRespectRef(const GURL& url) { |
| browser::NavigateParams params(GetSingletonTabNavigateParams(url)); |
| params.ref_behavior = browser::NavigateParams::RESPECT_REF; |
| browser::Navigate(¶ms); |
| } |
| |
| void Browser::ShowSingletonTabOverwritingNTP( |
| const browser::NavigateParams& params) { |
| browser::NavigateParams local_params(params); |
| TabContents* contents = GetSelectedTabContents(); |
| if (contents) { |
| const GURL& contents_url = contents->GetURL(); |
| if ((contents_url == GURL(chrome::kChromeUINewTabURL) || |
| contents_url == GURL(chrome::kAboutBlankURL)) && |
| browser::GetIndexOfSingletonTab(&local_params) < 0) { |
| local_params.disposition = CURRENT_TAB; |
| } |
| } |
| |
| browser::Navigate(&local_params); |
| } |
| |
| void Browser::WindowFullscreenStateChanged() { |
| fullscreen_controller_->WindowFullscreenStateChanged(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, Assorted browser commands: |
| |
| TabContents* Browser::GetOrCloneTabForDisposition( |
| WindowOpenDisposition disposition) { |
| TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper(); |
| switch (disposition) { |
| case NEW_FOREGROUND_TAB: |
| case NEW_BACKGROUND_TAB: { |
| current_tab = current_tab->Clone(); |
| tab_handler_->GetTabStripModel()->AddTabContents( |
| current_tab, -1, content::PAGE_TRANSITION_LINK, |
| disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_ACTIVE : |
| TabStripModel::ADD_NONE); |
| break; |
| } |
| case NEW_WINDOW: { |
| current_tab = current_tab->Clone(); |
| Browser* browser = Browser::Create(profile_); |
| browser->tabstrip_model()->AddTabContents( |
| current_tab, -1, content::PAGE_TRANSITION_LINK, |
| TabStripModel::ADD_ACTIVE); |
| browser->window()->Show(); |
| break; |
| } |
| default: |
| break; |
| } |
| return current_tab->tab_contents(); |
| } |
| |
| bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, |
| bool check_fullscreen) const { |
| // On Mac, fullscreen mode has most normal things (in a slide-down panel). On |
| // other platforms, we hide some controls when in fullscreen mode. |
| bool hide_ui_for_fullscreen = false; |
| #if !defined(OS_MACOSX) |
| hide_ui_for_fullscreen = check_fullscreen && window_ && |
| window_->IsFullscreen(); |
| #endif |
| |
| unsigned int features = FEATURE_INFOBAR | FEATURE_SIDEBAR; |
| |
| #if !defined(OS_CHROMEOS) || defined(USE_AURA) |
| // Chrome OS opens a FileBrowse pop up instead of using download shelf. |
| // So FEATURE_DOWNLOADSHELF is only added for non-chromeos platforms. |
| features |= FEATURE_DOWNLOADSHELF; |
| #endif // !defined(OS_CHROMEOS) || defined(USE_AURA) |
| |
| if (is_type_tabbed()) |
| features |= FEATURE_BOOKMARKBAR; |
| |
| if (!hide_ui_for_fullscreen) { |
| if (!is_type_tabbed()) |
| features |= FEATURE_TITLEBAR; |
| |
| if (is_type_tabbed()) |
| features |= FEATURE_TABSTRIP; |
| |
| if (is_type_tabbed()) |
| features |= FEATURE_TOOLBAR; |
| |
| if (!is_app()) |
| features |= FEATURE_LOCATIONBAR; |
| } |
| return !!(features & feature); |
| } |
| |
| bool Browser::IsClosingPermitted() { |
| TabCloseableStateWatcher* watcher = |
| g_browser_process->tab_closeable_state_watcher(); |
| bool can_close = !watcher || watcher->CanCloseBrowser(this); |
| if (!can_close && is_attempting_to_close_browser_) |
| CancelWindowClose(); |
| return can_close; |
| } |
| |
| bool Browser::CanGoBack() const { |
| return GetSelectedTabContentsWrapper()->controller().CanGoBack(); |
| } |
| |
| void Browser::GoBack(WindowOpenDisposition disposition) { |
| UserMetrics::RecordAction(UserMetricsAction("Back")); |
| |
| TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper(); |
| if (CanGoBack()) { |
| TabContents* new_tab = GetOrCloneTabForDisposition(disposition); |
| // If we are on an interstitial page and clone the tab, it won't be copied |
| // to the new tab, so we don't need to go back. |
| if (current_tab->tab_contents()->showing_interstitial_page() && |
| (new_tab != current_tab->tab_contents())) |
| return; |
| new_tab->controller().GoBack(); |
| } |
| } |
| |
| bool Browser::CanGoForward() const { |
| return GetSelectedTabContentsWrapper()->controller().CanGoForward(); |
| } |
| |
| void Browser::GoForward(WindowOpenDisposition disposition) { |
| UserMetrics::RecordAction(UserMetricsAction("Forward")); |
| if (CanGoForward()) |
| GetOrCloneTabForDisposition(disposition)->controller().GoForward(); |
| } |
| |
| void Browser::Reload(WindowOpenDisposition disposition) { |
| UserMetrics::RecordAction(UserMetricsAction("Reload")); |
| ReloadInternal(disposition, false); |
| } |
| |
| void Browser::ReloadIgnoringCache(WindowOpenDisposition disposition) { |
| UserMetrics::RecordAction(UserMetricsAction("ReloadIgnoringCache")); |
| ReloadInternal(disposition, true); |
| } |
| |
| void Browser::ReloadInternal(WindowOpenDisposition disposition, |
| bool ignore_cache) { |
| // If we are showing an interstitial, treat this as an OpenURL. |
| TabContents* current_tab = GetSelectedTabContents(); |
| if (current_tab && current_tab->showing_interstitial_page()) { |
| NavigationEntry* entry = current_tab->controller().GetActiveEntry(); |
| DCHECK(entry); // Should exist if interstitial is showing. |
| OpenURL(entry->url(), GURL(), disposition, content::PAGE_TRANSITION_RELOAD); |
| return; |
| } |
| |
| // As this is caused by a user action, give the focus to the page. |
| TabContents* tab = GetOrCloneTabForDisposition(disposition); |
| if (!tab->FocusLocationBarByDefault()) |
| tab->Focus(); |
| if (ignore_cache) |
| tab->controller().ReloadIgnoringCache(true); |
| else |
| tab->controller().Reload(true); |
| } |
| |
| void Browser::Home(WindowOpenDisposition disposition) { |
| UserMetrics::RecordAction(UserMetricsAction("Home")); |
| OpenURL( |
| profile_->GetHomePage(), GURL(), disposition, |
| content::PageTransitionFromInt( |
| content::PAGE_TRANSITION_AUTO_BOOKMARK | |
| content::PAGE_TRANSITION_HOME_PAGE)); |
| } |
| |
| void Browser::OpenCurrentURL() { |
| UserMetrics::RecordAction(UserMetricsAction("LoadURL")); |
| LocationBar* location_bar = window_->GetLocationBar(); |
| if (!location_bar) |
| return; |
| |
| WindowOpenDisposition open_disposition = |
| location_bar->GetWindowOpenDisposition(); |
| if (OpenInstant(open_disposition)) |
| return; |
| |
| GURL url(location_bar->GetInputString()); |
| |
| if (open_disposition == CURRENT_TAB && TabFinder::IsEnabled()) { |
| Browser* existing_browser = NULL; |
| TabContents* existing_tab = TabFinder::GetInstance()->FindTab( |
| this, url, &existing_browser); |
| if (existing_tab) { |
| existing_browser->ActivateContents(existing_tab); |
| return; |
| } |
| } |
| |
| browser::NavigateParams params(this, url, location_bar->GetPageTransition()); |
| params.disposition = open_disposition; |
| // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least |
| // inherit the opener. In some cases the tabstrip will determine the group |
| // should be inherited, in which case the group is inherited instead of the |
| // opener. |
| params.tabstrip_add_types = |
| TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER; |
| browser::Navigate(¶ms); |
| |
| DCHECK(profile_->GetExtensionService()); |
| if (profile_->GetExtensionService()->IsInstalledApp(url)) { |
| UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, |
| extension_misc::APP_LAUNCH_OMNIBOX_LOCATION, |
| extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
| } |
| } |
| |
| void Browser::Stop() { |
| UserMetrics::RecordAction(UserMetricsAction("Stop")); |
| GetSelectedTabContentsWrapper()->tab_contents()->Stop(); |
| } |
| |
| void Browser::NewWindow() { |
| IncognitoModePrefs::Availability incognito_avail = |
| IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); |
| if (browser_defaults::kAlwaysOpenIncognitoWindow && |
| incognito_avail != IncognitoModePrefs::DISABLED && |
| (CommandLine::ForCurrentProcess()->HasSwitch(switches::kIncognito) || |
| incognito_avail == IncognitoModePrefs::FORCED)) { |
| NewIncognitoWindow(); |
| return; |
| } |
| UserMetrics::RecordAction(UserMetricsAction("NewWindow")); |
| SessionService* session_service = |
| SessionServiceFactory::GetForProfile(profile_->GetOriginalProfile()); |
| if (!session_service || |
| !session_service->RestoreIfNecessary(std::vector<GURL>())) { |
| Browser::OpenEmptyWindow(profile_->GetOriginalProfile()); |
| } |
| } |
| |
| void Browser::NewIncognitoWindow() { |
| if (IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) == |
| IncognitoModePrefs::DISABLED) { |
| NewWindow(); |
| return; |
| } |
| |
| UserMetrics::RecordAction(UserMetricsAction("NewIncognitoWindow")); |
| Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile()); |
| } |
| |
| void Browser::CloseWindow() { |
| UserMetrics::RecordAction(UserMetricsAction("CloseWindow")); |
| window_->Close(); |
| } |
| |
| void Browser::NewTab() { |
| UserMetrics::RecordAction(UserMetricsAction("NewTab")); |
| |
| if (is_type_tabbed()) { |
| AddBlankTab(true); |
| GetSelectedTabContentsWrapper()->view()->RestoreFocus(); |
| } else { |
| Browser* b = GetOrCreateTabbedBrowser(profile_); |
| b->AddBlankTab(true); |
| b->window()->Show(); |
| // The call to AddBlankTab above did not set the focus to the tab as its |
| // window was not active, so we have to do it explicitly. |
| // See http://crbug.com/6380. |
| b->GetSelectedTabContentsWrapper()->view()->RestoreFocus(); |
| } |
| } |
| |
| void Browser::CloseTab() { |
| UserMetrics::RecordAction(UserMetricsAction("CloseTab_Accelerator")); |
| if (CanCloseTab()) |
| tab_handler_->GetTabStripModel()->CloseSelectedTabs(); |
| } |
| |
| void Browser::SelectNextTab() { |
| UserMetrics::RecordAction(UserMetricsAction("SelectNextTab")); |
| tab_handler_->GetTabStripModel()->SelectNextTab(); |
| } |
| |
| void Browser::SelectPreviousTab() { |
| UserMetrics::RecordAction(UserMetricsAction("SelectPrevTab")); |
| tab_handler_->GetTabStripModel()->SelectPreviousTab(); |
| } |
| |
| void Browser::OpenTabpose() { |
| #if defined(OS_MACOSX) |
| if (!CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableExposeForTabs)) { |
| return; |
| } |
| |
| UserMetrics::RecordAction(UserMetricsAction("OpenTabpose")); |
| window()->OpenTabpose(); |
| #else |
| NOTREACHED(); |
| #endif |
| } |
| |
| void Browser::MoveTabNext() { |
| UserMetrics::RecordAction(UserMetricsAction("MoveTabNext")); |
| tab_handler_->GetTabStripModel()->MoveTabNext(); |
| } |
| |
| void Browser::MoveTabPrevious() { |
| UserMetrics::RecordAction(UserMetricsAction("MoveTabPrevious")); |
| tab_handler_->GetTabStripModel()->MoveTabPrevious(); |
| } |
| |
| void Browser::SelectNumberedTab(int index) { |
| if (index < tab_count()) { |
| UserMetrics::RecordAction(UserMetricsAction("SelectNumberedTab")); |
| tab_handler_->GetTabStripModel()->ActivateTabAt(index, true); |
| } |
| } |
| |
| void Browser::SelectLastTab() { |
| UserMetrics::RecordAction(UserMetricsAction("SelectLastTab")); |
| tab_handler_->GetTabStripModel()->SelectLastTab(); |
| } |
| |
| void Browser::DuplicateTab() { |
| UserMetrics::RecordAction(UserMetricsAction("Duplicate")); |
| DuplicateContentsAt(active_index()); |
| } |
| |
| void Browser::RestoreTab() { |
| UserMetrics::RecordAction(UserMetricsAction("RestoreTab")); |
| TabRestoreService* service = |
| TabRestoreServiceFactory::GetForProfile(profile_); |
| if (!service) |
| return; |
| |
| service->RestoreMostRecentEntry(tab_restore_service_delegate()); |
| } |
| |
| void Browser::WriteCurrentURLToClipboard() { |
| // TODO(ericu): There isn't currently a metric for this. Should there be? |
| // We don't appear to track the action when it comes from the |
| // RenderContextViewMenu. |
| |
| TabContents* contents = GetSelectedTabContents(); |
| if (!toolbar_model_.ShouldDisplayURL()) |
| return; |
| |
| chrome_browser_net::WriteURLToClipboard( |
| contents->GetURL(), |
| profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), |
| g_browser_process->clipboard()); |
| } |
| |
| void Browser::ConvertPopupToTabbedBrowser() { |
| UserMetrics::RecordAction(UserMetricsAction("ShowAsTab")); |
| int tab_strip_index = tab_handler_->GetTabStripModel()->active_index(); |
| TabContentsWrapper* contents = |
| tab_handler_->GetTabStripModel()->DetachTabContentsAt(tab_strip_index); |
| Browser* browser = Browser::Create(profile_); |
| browser->tabstrip_model()->AppendTabContents(contents, true); |
| browser->window()->Show(); |
| } |
| |
| // TODO(koz): Change |for_tab| to an enum. |
| void Browser::ToggleFullscreenMode(bool for_tab) { |
| fullscreen_controller_->ToggleFullscreenMode(for_tab); |
| } |
| |
| #if defined(OS_MACOSX) |
| void Browser::TogglePresentationMode(bool for_tab) { |
| fullscreen_controller_->TogglePresentationMode(for_tab); |
| } |
| #endif |
| |
| #if defined(OS_CHROMEOS) |
| void Browser::Search() { |
| // Exit fullscreen to show omnibox. |
| if (window_->IsFullscreen()) { |
| ToggleFullscreenMode(false); |
| // ToggleFullscreenMode is asynchronous, so we don't have omnibox |
| // visible at this point. Wait for next event cycle which toggles |
| // the visibility of omnibox before creating new tab. |
| MessageLoop::current()->PostTask( |
| FROM_HERE, base::Bind(&Browser::Search, weak_factory_.GetWeakPtr())); |
| return; |
| } |
| |
| const GURL& url = GetSelectedTabContents()->GetURL(); |
| if (url.SchemeIs(chrome::kChromeUIScheme) && |
| url.host() == chrome::kChromeUINewTabHost) { |
| // If the NTP is showing, focus the omnibox. |
| window_->SetFocusToLocationBar(true); |
| } else { |
| // Otherwise, open the NTP. |
| NewTab(); |
| } |
| } |
| |
| void Browser::ShowKeyboardOverlay() { |
| window_->ShowKeyboardOverlay(window_->GetNativeHandle()); |
| } |
| #endif |
| |
| void Browser::Exit() { |
| UserMetrics::RecordAction(UserMetricsAction("Exit")); |
| BrowserList::AttemptUserExit(); |
| } |
| |
| void Browser::BookmarkCurrentPage() { |
| UserMetrics::RecordAction(UserMetricsAction("Star")); |
| |
| BookmarkModel* model = profile()->GetBookmarkModel(); |
| if (!model || !model->IsLoaded()) |
| return; // Ignore requests until bookmarks are loaded. |
| |
| GURL url; |
| string16 title; |
| TabContentsWrapper* tab = GetSelectedTabContentsWrapper(); |
| bookmark_utils::GetURLAndTitleToBookmark(tab->tab_contents(), &url, &title); |
| bool was_bookmarked = model->IsBookmarked(url); |
| if (!was_bookmarked && profile_->IsOffTheRecord()) { |
| // If we're incognito the favicon may not have been saved. Save it now |
| // so that bookmarks have an icon for the page. |
| tab->favicon_tab_helper()->SaveFavicon(); |
| } |
| bookmark_utils::AddIfNotBookmarked(model, url, title); |
| // Make sure the model actually added a bookmark before showing the star. A |
| // bookmark isn't created if the url is invalid. |
| if (window_->IsActive() && model->IsBookmarked(url)) { |
| // Only show the bubble if the window is active, otherwise we may get into |
| // weird situations were the bubble is deleted as soon as it is shown. |
| window_->ShowBookmarkBubble(url, was_bookmarked); |
| } |
| } |
| |
| void Browser::SavePage() { |
| UserMetrics::RecordAction(UserMetricsAction("SavePage")); |
| TabContents* current_tab = GetSelectedTabContents(); |
| if (current_tab && current_tab->contents_mime_type() == "application/pdf") |
| UserMetrics::RecordAction(UserMetricsAction("PDF.SavePage")); |
| GetSelectedTabContents()->OnSavePage(); |
| } |
| |
| void Browser::ViewSelectedSource() { |
| ViewSource(GetSelectedTabContentsWrapper()); |
| } |
| |
| void Browser::ShowFindBar() { |
| GetFindBarController()->Show(); |
| } |
| |
| bool Browser::SupportsWindowFeature(WindowFeature feature) const { |
| return SupportsWindowFeatureImpl(feature, true); |
| } |
| |
| bool Browser::CanSupportWindowFeature(WindowFeature feature) const { |
| return SupportsWindowFeatureImpl(feature, false); |
| } |
| |
| void Browser::EmailPageLocation() { |
| UserMetrics::RecordAction(UserMetricsAction("EmailPageLocation")); |
| TabContents* tc = GetSelectedTabContents(); |
| DCHECK(tc); |
| |
| std::string title = net::EscapeQueryParamValue( |
| UTF16ToUTF8(tc->GetTitle()), false); |
| std::string page_url = net::EscapeQueryParamValue(tc->GetURL().spec(), false); |
| std::string mailto = std::string("mailto:?subject=Fwd:%20") + |
| title + "&body=%0A%0A" + page_url; |
| platform_util::OpenExternal(GURL(mailto)); |
| } |
| |
| void Browser::Print() { |
| if (switches::IsPrintPreviewEnabled()) |
| GetSelectedTabContentsWrapper()->print_view_manager()->PrintPreviewNow(); |
| else |
| GetSelectedTabContentsWrapper()->print_view_manager()->PrintNow(); |
| } |
| |
| void Browser::AdvancedPrint() { |
| GetSelectedTabContentsWrapper()->print_view_manager()->AdvancedPrintNow(); |
| } |
| |
| void Browser::ToggleEncodingAutoDetect() { |
| UserMetrics::RecordAction(UserMetricsAction("AutoDetectChange")); |
| encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue()); |
| // If "auto detect" is turned on, then any current override encoding |
| // is cleared. This also implicitly performs a reload. |
| // OTOH, if "auto detect" is turned off, we don't change the currently |
| // active encoding. |
| if (encoding_auto_detect_.GetValue()) { |
| TabContents* contents = GetSelectedTabContents(); |
| if (contents) |
| contents->ResetOverrideEncoding(); |
| } |
| } |
| |
| void Browser::OverrideEncoding(int encoding_id) { |
| UserMetrics::RecordAction(UserMetricsAction("OverrideEncoding")); |
| const std::string selected_encoding = |
| CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id); |
| TabContents* contents = GetSelectedTabContents(); |
| if (!selected_encoding.empty() && contents) |
| contents->SetOverrideEncoding(selected_encoding); |
| // Update the list of recently selected encodings. |
| std::string new_selected_encoding_list; |
| if (CharacterEncoding::UpdateRecentlySelectedEncoding( |
| profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding), |
| encoding_id, |
| &new_selected_encoding_list)) { |
| profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding, |
| new_selected_encoding_list); |
| } |
| } |
| |
| void Browser::Cut() { |
| UserMetrics::RecordAction(UserMetricsAction("Cut")); |
| window()->Cut(); |
| } |
| |
| void Browser::Copy() { |
| UserMetrics::RecordAction(UserMetricsAction("Copy")); |
| window()->Copy(); |
| } |
| |
| void Browser::Paste() { |
| UserMetrics::RecordAction(UserMetricsAction("Paste")); |
| window()->Paste(); |
| } |
| |
| void Browser::Find() { |
| UserMetrics::RecordAction(UserMetricsAction("Find")); |
| FindInPage(false, false); |
| } |
| |
| void Browser::FindNext() { |
| UserMetrics::RecordAction(UserMetricsAction("FindNext")); |
| FindInPage(true, true); |
| } |
| |
| void Browser::FindPrevious() { |
| UserMetrics::RecordAction(UserMetricsAction("FindPrevious")); |
| FindInPage(true, false); |
| } |
| |
| void Browser::Zoom(content::PageZoom zoom) { |
| if (is_devtools()) |
| return; |
| |
| RenderViewHost* host = GetSelectedTabContentsWrapper()->render_view_host(); |
| if (zoom == content::PAGE_ZOOM_RESET) { |
| host->SetZoomLevel(0); |
| UserMetrics::RecordAction(UserMetricsAction("ZoomNormal")); |
| return; |
| } |
| |
| double current_zoom_level = GetSelectedTabContents()->GetZoomLevel(); |
| double default_zoom_level = |
| profile_->GetPrefs()->GetDouble(prefs::kDefaultZoomLevel); |
| |
| // Generate a vector of zoom levels from an array of known presets along with |
| // the default level added if necessary. |
| std::vector<double> zoom_levels = |
| chrome_page_zoom::PresetZoomLevels(default_zoom_level); |
| |
| if (zoom == content::PAGE_ZOOM_OUT) { |
| // Iterate through the zoom levels in reverse order to find the next |
| // lower level based on the current zoom level for this page. |
| for (std::vector<double>::reverse_iterator i = zoom_levels.rbegin(); |
| i != zoom_levels.rend(); ++i) { |
| double zoom_level = *i; |
| if (content::ZoomValuesEqual(zoom_level, current_zoom_level)) |
| continue; |
| if (zoom_level < current_zoom_level) { |
| host->SetZoomLevel(zoom_level); |
| UserMetrics::RecordAction(UserMetricsAction("ZoomMinus")); |
| return; |
| } |
| UserMetrics::RecordAction(UserMetricsAction("ZoomMinus_AtMinimum")); |
| } |
| } else { |
| // Iterate through the zoom levels in normal order to find the next |
| // higher level based on the current zoom level for this page. |
| for (std::vector<double>::const_iterator i = zoom_levels.begin(); |
| i != zoom_levels.end(); ++i) { |
| double zoom_level = *i; |
| if (content::ZoomValuesEqual(zoom_level, current_zoom_level)) |
| continue; |
| if (zoom_level > current_zoom_level) { |
| host->SetZoomLevel(zoom_level); |
| UserMetrics::RecordAction(UserMetricsAction("ZoomPlus")); |
| return; |
| } |
| } |
| UserMetrics::RecordAction(UserMetricsAction("ZoomPlus_AtMaximum")); |
| } |
| } |
| |
| void Browser::FocusToolbar() { |
| UserMetrics::RecordAction(UserMetricsAction("FocusToolbar")); |
| window_->FocusToolbar(); |
| } |
| |
| void Browser::FocusAppMenu() { |
| UserMetrics::RecordAction(UserMetricsAction("FocusAppMenu")); |
| window_->FocusAppMenu(); |
| } |
| |
| void Browser::FocusLocationBar() { |
| UserMetrics::RecordAction(UserMetricsAction("FocusLocation")); |
| window_->SetFocusToLocationBar(true); |
| } |
| |
| void Browser::FocusBookmarksToolbar() { |
| UserMetrics::RecordAction(UserMetricsAction("FocusBookmarksToolbar")); |
| window_->FocusBookmarksToolbar(); |
| } |
| |
| void Browser::FocusChromeOSStatus() { |
| UserMetrics::RecordAction(UserMetricsAction("FocusChromeOSStatus")); |
| window_->FocusChromeOSStatus(); |
| } |
| |
| void Browser::FocusNextPane() { |
| UserMetrics::RecordAction(UserMetricsAction("FocusNextPane")); |
| window_->RotatePaneFocus(true); |
| } |
| |
| void Browser::FocusPreviousPane() { |
| UserMetrics::RecordAction(UserMetricsAction("FocusPreviousPane")); |
| window_->RotatePaneFocus(false); |
| } |
| |
| void Browser::FocusSearch() { |
| // TODO(beng): replace this with FocusLocationBar |
| UserMetrics::RecordAction(UserMetricsAction("FocusSearch")); |
| window_->GetLocationBar()->FocusSearch(); |
| } |
| |
| void Browser::OpenFile() { |
| UserMetrics::RecordAction(UserMetricsAction("OpenFile")); |
| if (!select_file_dialog_.get()) |
| select_file_dialog_ = SelectFileDialog::Create(this); |
| |
| const FilePath directory = profile_->last_selected_directory(); |
| |
| // TODO(beng): figure out how to juggle this. |
| gfx::NativeWindow parent_window = window_->GetNativeHandle(); |
| select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE, |
| string16(), directory, |
| NULL, 0, FILE_PATH_LITERAL(""), |
| GetSelectedTabContents(), |
| parent_window, NULL); |
| } |
| |
| void Browser::OpenCreateShortcutsDialog() { |
| UserMetrics::RecordAction(UserMetricsAction("CreateShortcut")); |
| #if !defined(OS_MACOSX) |
| TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper(); |
| DCHECK(current_tab && |
| web_app::IsValidUrl(current_tab->tab_contents()->GetURL())) << |
| "Menu item should be disabled."; |
| |
| NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry(); |
| if (!entry) |
| return; |
| |
| // RVH's GetApplicationInfo should not be called before it returns. |
| DCHECK(pending_web_app_action_ == NONE); |
| pending_web_app_action_ = CREATE_SHORTCUT; |
| |
| // Start fetching web app info for CreateApplicationShortcut dialog and show |
| // the dialog when the data is available in OnDidGetApplicationInfo. |
| current_tab->extension_tab_helper()->GetApplicationInfo(entry->page_id()); |
| #else |
| NOTIMPLEMENTED(); |
| #endif |
| } |
| |
| void Browser::ToggleDevToolsWindow(DevToolsToggleAction action) { |
| if (action == DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE) |
| UserMetrics::RecordAction(UserMetricsAction("DevTools_ToggleConsole")); |
| else |
| UserMetrics::RecordAction(UserMetricsAction("DevTools_ToggleWindow")); |
| |
| DevToolsWindow::ToggleDevToolsWindow( |
| GetSelectedTabContentsWrapper()->render_view_host(), action); |
| } |
| |
| void Browser::OpenTaskManager(bool highlight_background_resources) { |
| UserMetrics::RecordAction(UserMetricsAction("TaskManager")); |
| if (highlight_background_resources) |
| window_->ShowBackgroundPages(); |
| else |
| window_->ShowTaskManager(); |
| } |
| |
| void Browser::OpenBugReportDialog() { |
| UserMetrics::RecordAction(UserMetricsAction("ReportBug")); |
| browser::ShowHtmlBugReportView(this, std::string(), 0); |
| } |
| |
| void Browser::ToggleBookmarkBar() { |
| UserMetrics::RecordAction(UserMetricsAction("ShowBookmarksBar")); |
| window_->ToggleBookmarkBar(); |
| } |
| |
| void Browser::OpenBookmarkManager() { |
| UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager")); |
| UserMetrics::RecordAction(UserMetricsAction("ShowBookmarks")); |
| ShowSingletonTabOverwritingNTP( |
| GetSingletonTabNavigateParams(GURL(chrome::kChromeUIBookmarksURL))); |
| } |
| |
| void Browser::OpenBookmarkManagerWithHash(const std::string& action, |
| int64 node_id) { |
| UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager")); |
| UserMetrics::RecordAction(UserMetricsAction("ShowBookmarks")); |
| browser::NavigateParams params(GetSingletonTabNavigateParams( |
| GURL(chrome::kChromeUIBookmarksURL).Resolve( |
| StringPrintf("/#%s%s", action.c_str(), |
| base::Int64ToString(node_id).c_str())))); |
| params.path_behavior = browser::NavigateParams::IGNORE_AND_NAVIGATE; |
| ShowSingletonTabOverwritingNTP(params); |
| } |
| |
| void Browser::OpenBookmarkManagerForNode(int64 node_id) { |
| OpenBookmarkManagerWithHash("", node_id); |
| } |
| |
| void Browser::OpenBookmarkManagerEditNode(int64 node_id) { |
| OpenBookmarkManagerWithHash("e=", node_id); |
| } |
| |
| void Browser::ShowAppMenu() { |
| // We record the user metric for this event in WrenchMenu::RunMenu. |
| window_->ShowAppMenu(); |
| } |
| |
| void Browser::ShowAvatarMenu() { |
| window_->ShowAvatarBubbleFromAvatarButton(); |
| } |
| |
| void Browser::ShowHistoryTab() { |
| UserMetrics::RecordAction(UserMetricsAction("ShowHistory")); |
| ShowSingletonTabOverwritingNTP( |
| GetSingletonTabNavigateParams(GURL(chrome::kChromeUIHistoryURL))); |
| } |
| |
| void Browser::ShowDownloadsTab() { |
| UserMetrics::RecordAction(UserMetricsAction("ShowDownloads")); |
| #if !defined(OS_CHROMEOS) |
| // ChromiumOS uses ActiveDownloadsUI instead of of DownloadShelf. |
| if (window()) { |
| DownloadShelf* shelf = window()->GetDownloadShelf(); |
| if (shelf->IsShowing()) |
| shelf->Close(); |
| } |
| #endif |
| ShowSingletonTabOverwritingNTP( |
| GetSingletonTabNavigateParams(GURL(chrome::kChromeUIDownloadsURL))); |
| } |
| |
| void Browser::ShowExtensionsTab() { |
| UserMetrics::RecordAction(UserMetricsAction("ShowExtensions")); |
| ShowOptionsTab(chrome::kExtensionsSubPage); |
| } |
| |
| void Browser::ShowAboutConflictsTab() { |
| UserMetrics::RecordAction(UserMetricsAction("AboutConflicts")); |
| ShowSingletonTab(GURL(chrome::kChromeUIConflictsURL)); |
| } |
| |
| void Browser::ShowBrokenPageTab(TabContents* contents) { |
| UserMetrics::RecordAction(UserMetricsAction("ReportBug")); |
| string16 page_title = contents->GetTitle(); |
| NavigationEntry* entry = contents->controller().GetActiveEntry(); |
| if (!entry) |
| return; |
| std::string page_url = entry->url().spec(); |
| std::vector<std::string> subst; |
| subst.push_back(UTF16ToASCII(page_title)); |
| subst.push_back(page_url); |
| std::string report_page_url = |
| ReplaceStringPlaceholders(kBrokenPageUrl, subst, NULL); |
| ShowSingletonTab(GURL(report_page_url)); |
| } |
| |
| void Browser::ShowOptionsTab(const std::string& sub_page) { |
| browser::NavigateParams params(GetSingletonTabNavigateParams( |
| GURL(chrome::kChromeUISettingsURL + sub_page))); |
| params.path_behavior = browser::NavigateParams::IGNORE_AND_NAVIGATE; |
| |
| ShowSingletonTabOverwritingNTP(params); |
| } |
| |
| void Browser::OpenClearBrowsingDataDialog() { |
| UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_ShowDlg")); |
| ShowOptionsTab(chrome::kClearBrowserDataSubPage); |
| } |
| |
| void Browser::OpenOptionsDialog() { |
| UserMetrics::RecordAction(UserMetricsAction("ShowOptions")); |
| ShowOptionsTab(""); |
| } |
| |
| void Browser::OpenPasswordManager() { |
| UserMetrics::RecordAction(UserMetricsAction("Options_ShowPasswordManager")); |
| ShowOptionsTab(chrome::kPasswordManagerSubPage); |
| } |
| |
| void Browser::OpenImportSettingsDialog() { |
| UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg")); |
| ShowOptionsTab(chrome::kImportDataSubPage); |
| } |
| |
| void Browser::OpenInstantConfirmDialog() { |
| ShowOptionsTab(chrome::kInstantConfirmPage); |
| } |
| |
| void Browser::OpenSyncMyBookmarksDialog() { |
| sync_ui_util::OpenSyncMyBookmarksDialog( |
| profile_, this, ProfileSyncService::START_FROM_WRENCH); |
| } |
| |
| void Browser::OpenAboutChromeDialog() { |
| UserMetrics::RecordAction(UserMetricsAction("AboutChrome")); |
| #if defined(OS_CHROMEOS) |
| std::string chrome_settings(chrome::kChromeUISettingsURL); |
| ShowSingletonTab(GURL(chrome_settings.append(chrome::kAboutOptionsSubPage))); |
| #else |
| window_->ShowAboutChromeDialog(); |
| #endif |
| } |
| |
| void Browser::OpenUpdateChromeDialog() { |
| UserMetrics::RecordAction(UserMetricsAction("UpdateChrome")); |
| window_->ShowUpdateChromeDialog(); |
| } |
| |
| void Browser::ShowHelpTab() { |
| UserMetrics::RecordAction(UserMetricsAction("ShowHelpTab")); |
| GURL help_url(kHelpContentUrl); |
| GURL localized_help_url = google_util::AppendGoogleLocaleParam(help_url); |
| ShowSingletonTab(localized_help_url); |
| } |
| |
| void Browser::OpenPrivacyDashboardTabAndActivate() { |
| OpenURL(GURL(kPrivacyDashboardUrl), GURL(), |
| NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK); |
| window_->Activate(); |
| } |
| |
| void Browser::OpenAutofillHelpTabAndActivate() { |
| GURL help_url = google_util::AppendGoogleLocaleParam(GURL(kAutofillHelpUrl)); |
| AddSelectedTabWithURL(help_url, content::PAGE_TRANSITION_LINK); |
| } |
| |
| void Browser::OpenSearchEngineOptionsDialog() { |
| UserMetrics::RecordAction(UserMetricsAction("EditSearchEngines")); |
| ShowOptionsTab(chrome::kSearchEnginesSubPage); |
| } |
| |
| #if defined(FILE_MANAGER_EXTENSION) |
| void Browser::OpenFileManager() { |
| UserMetrics::RecordAction(UserMetricsAction("OpenFileManager")); |
| ShowSingletonTabRespectRef(GURL(chrome::kChromeUIFileManagerURL)); |
| } |
| #endif |
| |
| #if defined(OS_CHROMEOS) |
| void Browser::LockScreen() { |
| UserMetrics::RecordAction(UserMetricsAction("LockScreen")); |
| chromeos::CrosLibrary::Get()->GetScreenLockLibrary()-> |
| NotifyScreenLockRequested(); |
| } |
| |
| void Browser::OpenSystemOptionsDialog() { |
| UserMetrics::RecordAction(UserMetricsAction("OpenSystemOptionsDialog")); |
| ShowOptionsTab(chrome::kSystemOptionsSubPage); |
| } |
| |
| void Browser::OpenInternetOptionsDialog() { |
| UserMetrics::RecordAction(UserMetricsAction("OpenInternetOptionsDialog")); |
| ShowOptionsTab(chrome::kInternetOptionsSubPage); |
| } |
| |
| void Browser::OpenLanguageOptionsDialog() { |
| UserMetrics::RecordAction(UserMetricsAction("OpenLanguageOptionsDialog")); |
| ShowOptionsTab(chrome::kLanguageOptionsSubPage); |
| } |
| |
| void Browser::OpenSystemTabAndActivate() { |
| OpenURL(GURL(chrome::kChromeUISystemInfoURL), GURL(), |
| NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK); |
| window_->Activate(); |
| } |
| |
| void Browser::OpenMobilePlanTabAndActivate() { |
| if (CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableMobileSetupDialog)) { |
| window_->ShowMobileSetup(); |
| } else { |
| OpenURL(GURL(chrome::kChromeUIMobileSetupURL), GURL(), |
| NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK); |
| window_->Activate(); |
| } |
| } |
| #endif |
| |
| void Browser::OpenPluginsTabAndActivate() { |
| OpenURL(GURL(chrome::kChromeUIPluginsURL), GURL(), |
| NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK); |
| window_->Activate(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| // static |
| void Browser::SetNewHomePagePrefs(PrefService* prefs) { |
| const PrefService::Preference* home_page_pref = |
| prefs->FindPreference(prefs::kHomePage); |
| if (home_page_pref && |
| !home_page_pref->IsManaged() && |
| !prefs->HasPrefPath(prefs::kHomePage)) { |
| prefs->SetString(prefs::kHomePage, |
| GoogleURLTracker::kDefaultGoogleHomepage); |
| } |
| const PrefService::Preference* home_page_is_new_tab_page_pref = |
| prefs->FindPreference(prefs::kHomePageIsNewTabPage); |
| if (home_page_is_new_tab_page_pref && |
| !home_page_is_new_tab_page_pref->IsManaged() && |
| !prefs->HasPrefPath(prefs::kHomePageIsNewTabPage)) |
| prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false); |
| } |
| |
| // static |
| void Browser::RegisterPrefs(PrefService* prefs) { |
| prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0); |
| prefs->RegisterIntegerPref(prefs::kExtensionSidebarWidth, -1); |
| prefs->RegisterBooleanPref(prefs::kAllowFileSelectionDialogs, true); |
| prefs->RegisterBooleanPref(prefs::kShouldShowFirstRunBubble, false); |
| } |
| |
| // static |
| void Browser::RegisterUserPrefs(PrefService* prefs) { |
| prefs->RegisterStringPref(prefs::kHomePage, |
| chrome::kChromeUINewTabURL, |
| PrefService::SYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kHomePageChanged, |
| false, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, |
| true, |
| PrefService::SYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kShowHomeButton, |
| false, |
| PrefService::SYNCABLE_PREF); |
| #if defined(OS_MACOSX) |
| // This really belongs in platform code, but there's no good place to |
| // initialize it between the time when the AppController is created |
| // (where there's no profile) and the time the controller gets another |
| // crack at the start of the main event loop. By that time, BrowserInit |
| // has already created the browser window, and it's too late: we need the |
| // pref to be already initialized. Doing it here also saves us from having |
| // to hard-code pref registration in the several unit tests that use |
| // this preference. |
| prefs->RegisterBooleanPref(prefs::kConfirmToQuitEnabled, |
| false, |
| PrefService::SYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kShowUpdatePromotionInfoBar, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| #endif |
| prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, |
| true, |
| PrefService::SYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, |
| true, |
| PrefService::SYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kDeleteCache, |
| true, |
| PrefService::SYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kDeleteCookies, |
| true, |
| PrefService::SYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kDeletePasswords, |
| false, |
| PrefService::SYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kDeleteFormData, |
| false, |
| PrefService::SYNCABLE_PREF); |
| prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, |
| 0, |
| PrefService::SYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kShowOmniboxSearchHint, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kWebAppCreateOnDesktop, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kWebAppCreateInAppsMenu, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kWebAppCreateInQuickLaunchBar, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kEnableTranslate, |
| true, |
| PrefService::SYNCABLE_PREF); |
| prefs->RegisterStringPref(prefs::kCloudPrintEmail, |
| std::string(), |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kCloudPrintProxyEnabled, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kCloudPrintSubmitEnabled, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kDevToolsDisabled, |
| false, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, |
| -1, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterDictionaryPref(prefs::kPreferencesWindowPlacement, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kImportBookmarks, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kImportHistory, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kImportHomepage, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kImportSearchEngine, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kImportSavedPasswords, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| // The map of timestamps of the last used file browser handlers. |
| prefs->RegisterDictionaryPref(prefs::kLastUsedFileBrowserHandlers, |
| PrefService::UNSYNCABLE_PREF); |
| |
| // We need to register the type of these preferences in order to query |
| // them even though they're only typically controlled via policy. |
| prefs->RegisterBooleanPref(prefs::kDisable3DAPIs, |
| false, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kPluginsAllowOutdated, |
| false, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kPluginsAlwaysAuthorize, |
| false, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kEnableHyperlinkAuditing, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kEnableReferrers, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| |
| // Initialize the disk cache prefs. |
| prefs->RegisterFilePathPref(prefs::kDiskCacheDir, |
| FilePath(), |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterIntegerPref(prefs::kDiskCacheSize, |
| 0, |
| PrefService::UNSYNCABLE_PREF); |
| prefs->RegisterIntegerPref(prefs::kMediaCacheSize, |
| 0, |
| PrefService::UNSYNCABLE_PREF); |
| } |
| |
| // static |
| bool Browser::RunUnloadEventsHelper(TabContents* contents) { |
| // If the TabContents is not connected yet, then there's no unload |
| // handler we can fire even if the TabContents has an unload listener. |
| // One case where we hit this is in a tab that has an infinite loop |
| // before load. |
| if (contents->NeedToFireBeforeUnload()) { |
| // If the page has unload listeners, then we tell the renderer to fire |
| // them. Once they have fired, we'll get a message back saying whether |
| // to proceed closing the page or not, which sends us back to this method |
| // with the NeedToFireBeforeUnload bit cleared. |
| contents->render_view_host()->FirePageBeforeUnload(false); |
| return true; |
| } |
| return false; |
| } |
| |
| // static |
| Browser* Browser::GetBrowserForController( |
| const NavigationController* controller, int* index_result) { |
| BrowserList::const_iterator it; |
| for (it = BrowserList::begin(); it != BrowserList::end(); ++it) { |
| int index = (*it)->tab_handler_->GetTabStripModel()->GetIndexOfController( |
| controller); |
| if (index != TabStripModel::kNoTab) { |
| if (index_result) |
| *index_result = index; |
| return *it; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| // static |
| void Browser::RunFileChooserHelper( |
| TabContents* tab, const content::FileChooserParams& params) { |
| Profile* profile = |
| Profile::FromBrowserContext(tab->browser_context()); |
| // FileSelectHelper adds a reference to itself and only releases it after |
| // sending the result message. It won't be destroyed when this reference |
| // goes out of scope. |
| scoped_refptr<FileSelectHelper> file_select_helper( |
| new FileSelectHelper(profile)); |
| file_select_helper->RunFileChooser(tab->render_view_host(), tab, params); |
| } |
| |
| // static |
| void Browser::EnumerateDirectoryHelper(TabContents* tab, int request_id, |
| const FilePath& path) { |
| ChildProcessSecurityPolicy* policy = |
| ChildProcessSecurityPolicy::GetInstance(); |
| if (!policy->CanReadDirectory(tab->render_view_host()->process()->GetID(), |
| path)) { |
| return; |
| } |
| |
| Profile* profile = |
| Profile::FromBrowserContext(tab->browser_context()); |
| // FileSelectHelper adds a reference to itself and only releases it after |
| // sending the result message. It won't be destroyed when this reference |
| // goes out of scope. |
| scoped_refptr<FileSelectHelper> file_select_helper( |
| new FileSelectHelper(profile)); |
| file_select_helper->EnumerateDirectory(request_id, |
| tab->render_view_host(), |
| path); |
| } |
| |
| // static |
| void Browser::JSOutOfMemoryHelper(TabContents* tab) { |
| TabContentsWrapper* tcw = TabContentsWrapper::GetCurrentWrapperForContents( |
| tab); |
| if (tcw) { |
| InfoBarTabHelper* infobar_helper = tcw->infobar_tab_helper(); |
| infobar_helper->AddInfoBar(new SimpleAlertInfoBarDelegate( |
| infobar_helper, |
| NULL, |
| l10n_util::GetStringUTF16(IDS_JS_OUT_OF_MEMORY_PROMPT), |
| true)); |
| } |
| } |
| |
| // static |
| void Browser::RegisterProtocolHandlerHelper(TabContents* tab, |
| const std::string& protocol, |
| const GURL& url, |
| const string16& title) { |
| TabContentsWrapper* tcw = TabContentsWrapper::GetCurrentWrapperForContents( |
| tab); |
| if (!tcw || tcw->profile()->IsOffTheRecord()) |
| return; |
| |
| ChildProcessSecurityPolicy* policy = |
| ChildProcessSecurityPolicy::GetInstance(); |
| if (policy->IsPseudoScheme(protocol) || policy->IsDisabledScheme(protocol)) |
| return; |
| |
| ProtocolHandler handler = |
| ProtocolHandler::CreateProtocolHandler(protocol, url, title); |
| |
| ProtocolHandlerRegistry* registry = |
| tcw->profile()->GetProtocolHandlerRegistry(); |
| |
| if (!registry->SilentlyHandleRegisterHandlerRequest(handler)) { |
| UserMetrics::RecordAction( |
| UserMetricsAction("RegisterProtocolHandler.InfoBar_Shown")); |
| InfoBarTabHelper* infobar_helper = tcw->infobar_tab_helper(); |
| infobar_helper->AddInfoBar( |
| new RegisterProtocolHandlerInfoBarDelegate(infobar_helper, |
| registry, |
| handler)); |
| } |
| } |
| |
| // static |
| void Browser::RegisterIntentHandlerHelper(TabContents* tab, |
| const string16& action, |
| const string16& type, |
| const string16& href, |
| const string16& title, |
| const string16& disposition) { |
| if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableWebIntents)) |
| return; |
| |
| TabContentsWrapper* tcw = TabContentsWrapper::GetCurrentWrapperForContents( |
| tab); |
| if (!tcw || tcw->profile()->IsOffTheRecord()) |
| return; |
| |
| FaviconService* favicon_service = |
| tcw->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS); |
| |
| // |href| can be relative to originating URL. Resolve if necessary. |
| GURL service_url(href); |
| if (!service_url.is_valid()) { |
| const GURL& url = tab->GetURL(); |
| service_url = url.Resolve(href); |
| } |
| |
| webkit_glue::WebIntentServiceData service; |
| service.service_url = service_url; |
| service.action = action; |
| service.type = type; |
| service.title = title; |
| service.setDisposition(disposition); |
| |
| RegisterIntentHandlerInfoBarDelegate::MaybeShowIntentInfoBar( |
| tcw->infobar_tab_helper(), |
| WebIntentsRegistryFactory::GetForProfile(tcw->profile()), |
| service, |
| favicon_service, |
| tab->GetURL()); |
| } |
| |
| // static |
| void Browser::FindReplyHelper(TabContents* tab, |
| int request_id, |
| int number_of_matches, |
| const gfx::Rect& selection_rect, |
| int active_match_ordinal, |
| bool final_update) { |
| TabContentsWrapper* tcw = TabContentsWrapper::GetCurrentWrapperForContents( |
| tab); |
| if (!tcw || !tcw->find_tab_helper()) |
| return; |
| |
| tcw->find_tab_helper()->HandleFindReply(request_id, number_of_matches, |
| selection_rect, active_match_ordinal, |
| final_update); |
| } |
| |
| // static |
| void Browser::CrashedPluginHelper(TabContents* tab, |
| const FilePath& plugin_path) { |
| TabContentsWrapper* tcw = TabContentsWrapper::GetCurrentWrapperForContents( |
| tab); |
| if (!tcw) |
| return; |
| |
| DCHECK(!plugin_path.value().empty()); |
| |
| string16 plugin_name = plugin_path.LossyDisplayName(); |
| webkit::WebPluginInfo plugin_info; |
| if (PluginService::GetInstance()->GetPluginInfoByPath( |
| plugin_path, &plugin_info) && |
| !plugin_info.name.empty()) { |
| plugin_name = plugin_info.name; |
| #if defined(OS_MACOSX) |
| // Many plugins on the Mac have .plugin in the actual name, which looks |
| // terrible, so look for that and strip it off if present. |
| const std::string kPluginExtension = ".plugin"; |
| if (EndsWith(plugin_name, ASCIIToUTF16(kPluginExtension), true)) |
| plugin_name.erase(plugin_name.length() - kPluginExtension.length()); |
| #endif // OS_MACOSX |
| } |
| gfx::Image* icon = &ResourceBundle::GetSharedInstance().GetNativeImageNamed( |
| IDR_INFOBAR_PLUGIN_CRASHED); |
| InfoBarTabHelper* infobar_helper = tcw->infobar_tab_helper(); |
| infobar_helper->AddInfoBar( |
| new SimpleAlertInfoBarDelegate( |
| infobar_helper, |
| icon, |
| l10n_util::GetStringFUTF16(IDS_PLUGIN_CRASHED_PROMPT, plugin_name), |
| true)); |
| } |
| |
| // static |
| void Browser::UpdateTargetURLHelper(TabContents* tab, int32 page_id, |
| const GURL& url) { |
| TabContentsWrapper* tcw = TabContentsWrapper::GetCurrentWrapperForContents( |
| tab); |
| if (!tcw || !tcw->prerender_tab_helper()) |
| return; |
| tcw->prerender_tab_helper()->UpdateTargetURL(page_id, url); |
| } |
| |
| void Browser::ExecuteCommandWithDisposition( |
| int id, WindowOpenDisposition disposition) { |
| // No commands are enabled if there is not yet any selected tab. |
| // TODO(pkasting): It seems like we should not need this, because either |
| // most/all commands should not have been enabled yet anyway or the ones that |
| // are enabled should be global, or safe themselves against having no selected |
| // tab. However, Ben says he tried removing this before and got lots of |
| // crashes, e.g. from Windows sending WM_COMMANDs at random times during |
| // window construction. This probably could use closer examination someday. |
| if (!GetSelectedTabContentsWrapper()) |
| return; |
| |
| DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command " |
| << id; |
| |
| // If command execution is blocked then just record the command and return. |
| if (block_command_execution_) { |
| // We actually only allow no more than one blocked command, otherwise some |
| // commands maybe lost. |
| DCHECK_EQ(last_blocked_command_id_, -1); |
| last_blocked_command_id_ = id; |
| last_blocked_command_disposition_ = disposition; |
| return; |
| } |
| |
| // The order of commands in this switch statement must match the function |
| // declaration order in browser.h! |
| switch (id) { |
| // Navigation commands |
| case IDC_BACK: GoBack(disposition); break; |
| case IDC_FORWARD: GoForward(disposition); break; |
| case IDC_RELOAD: Reload(disposition); break; |
| case IDC_RELOAD_IGNORING_CACHE: ReloadIgnoringCache(disposition); break; |
| case IDC_HOME: Home(disposition); break; |
| case IDC_OPEN_CURRENT_URL: OpenCurrentURL(); break; |
| case IDC_STOP: Stop(); break; |
| |
| // Window management commands |
| case IDC_NEW_WINDOW: NewWindow(); break; |
| case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(); break; |
| case IDC_CLOSE_WINDOW: CloseWindow(); break; |
| case IDC_NEW_TAB: NewTab(); break; |
| case IDC_CLOSE_TAB: CloseTab(); break; |
| case IDC_SELECT_NEXT_TAB: SelectNextTab(); break; |
| case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break; |
| case IDC_TABPOSE: OpenTabpose(); break; |
| case IDC_MOVE_TAB_NEXT: MoveTabNext(); break; |
| case IDC_MOVE_TAB_PREVIOUS: MoveTabPrevious(); break; |
| case IDC_SELECT_TAB_0: |
| case IDC_SELECT_TAB_1: |
| case IDC_SELECT_TAB_2: |
| case IDC_SELECT_TAB_3: |
| case IDC_SELECT_TAB_4: |
| case IDC_SELECT_TAB_5: |
| case IDC_SELECT_TAB_6: |
| case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0); |
| break; |
| case IDC_SELECT_LAST_TAB: SelectLastTab(); break; |
| case IDC_DUPLICATE_TAB: DuplicateTab(); break; |
| case IDC_RESTORE_TAB: RestoreTab(); break; |
| case IDC_COPY_URL: WriteCurrentURLToClipboard(); break; |
| case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break; |
| case IDC_FULLSCREEN: ToggleFullscreenMode(false); break; |
| #if defined(OS_MACOSX) |
| case IDC_PRESENTATION_MODE: TogglePresentationMode(false); break; |
| #endif |
| case IDC_EXIT: Exit(); break; |
| #if defined(OS_CHROMEOS) |
| case IDC_SEARCH: Search(); break; |
| case IDC_SHOW_KEYBOARD_OVERLAY: ShowKeyboardOverlay(); break; |
| #endif |
| |
| // Page-related commands |
| case IDC_SAVE_PAGE: SavePage(); break; |
| case IDC_BOOKMARK_PAGE: BookmarkCurrentPage(); break; |
| case IDC_BOOKMARK_ALL_TABS: BookmarkAllTabs(); break; |
| case IDC_VIEW_SOURCE: ViewSelectedSource(); break; |
| case IDC_EMAIL_PAGE_LOCATION: EmailPageLocation(); break; |
| case IDC_PRINT: Print(); break; |
| case IDC_ADVANCED_PRINT: AdvancedPrint(); break; |
| case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break; |
| case IDC_ENCODING_UTF8: |
| case IDC_ENCODING_UTF16LE: |
| case IDC_ENCODING_ISO88591: |
| case IDC_ENCODING_WINDOWS1252: |
| case IDC_ENCODING_GBK: |
| case IDC_ENCODING_GB18030: |
| case IDC_ENCODING_BIG5HKSCS: |
| case IDC_ENCODING_BIG5: |
| case IDC_ENCODING_KOREAN: |
| case IDC_ENCODING_SHIFTJIS: |
| case IDC_ENCODING_ISO2022JP: |
| case IDC_ENCODING_EUCJP: |
| case IDC_ENCODING_THAI: |
| case IDC_ENCODING_ISO885915: |
| case IDC_ENCODING_MACINTOSH: |
| case IDC_ENCODING_ISO88592: |
| case IDC_ENCODING_WINDOWS1250: |
| case IDC_ENCODING_ISO88595: |
| case IDC_ENCODING_WINDOWS1251: |
| case IDC_ENCODING_KOI8R: |
| case IDC_ENCODING_KOI8U: |
| case IDC_ENCODING_ISO88597: |
| case IDC_ENCODING_WINDOWS1253: |
| case IDC_ENCODING_ISO88594: |
| case IDC_ENCODING_ISO885913: |
| case IDC_ENCODING_WINDOWS1257: |
| case IDC_ENCODING_ISO88593: |
| case IDC_ENCODING_ISO885910: |
| case IDC_ENCODING_ISO885914: |
| case IDC_ENCODING_ISO885916: |
| case IDC_ENCODING_WINDOWS1254: |
| case IDC_ENCODING_ISO88596: |
| case IDC_ENCODING_WINDOWS1256: |
| case IDC_ENCODING_ISO88598: |
| case IDC_ENCODING_ISO88598I: |
| case IDC_ENCODING_WINDOWS1255: |
| case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break; |
| |
| // Clipboard commands |
| case IDC_CUT: Cut(); break; |
| case IDC_COPY: Copy(); break; |
| case IDC_PASTE: Paste(); break; |
| |
| // Find-in-page |
| case IDC_FIND: Find(); break; |
| case IDC_FIND_NEXT: FindNext(); break; |
| case IDC_FIND_PREVIOUS: FindPrevious(); break; |
| |
| // Zoom |
| case IDC_ZOOM_PLUS: Zoom(content::PAGE_ZOOM_IN); break; |
| case IDC_ZOOM_NORMAL: Zoom(content::PAGE_ZOOM_RESET); break; |
| case IDC_ZOOM_MINUS: Zoom(content::PAGE_ZOOM_OUT); break; |
| |
| // Focus various bits of UI |
| case IDC_FOCUS_TOOLBAR: FocusToolbar(); break; |
| case IDC_FOCUS_LOCATION: FocusLocationBar(); break; |
| case IDC_FOCUS_SEARCH: FocusSearch(); break; |
| case IDC_FOCUS_MENU_BAR: FocusAppMenu(); break; |
| case IDC_FOCUS_BOOKMARKS: FocusBookmarksToolbar(); break; |
| case IDC_FOCUS_CHROMEOS_STATUS: FocusChromeOSStatus(); break; |
| case IDC_FOCUS_NEXT_PANE: FocusNextPane(); break; |
| case IDC_FOCUS_PREVIOUS_PANE: FocusPreviousPane(); break; |
| |
| // Show various bits of UI |
| case IDC_OPEN_FILE: OpenFile(); break; |
| case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break; |
| case IDC_DEV_TOOLS: ToggleDevToolsWindow( |
| DEVTOOLS_TOGGLE_ACTION_NONE); |
| break; |
| case IDC_DEV_TOOLS_CONSOLE: ToggleDevToolsWindow( |
| DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE); |
| break; |
| case IDC_DEV_TOOLS_INSPECT: ToggleDevToolsWindow( |
| DEVTOOLS_TOGGLE_ACTION_INSPECT); |
| break; |
| case IDC_TASK_MANAGER: OpenTaskManager(false); break; |
| case IDC_VIEW_BACKGROUND_PAGES: OpenTaskManager(true); break; |
| case IDC_FEEDBACK: OpenBugReportDialog(); break; |
| |
| case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break; |
| case IDC_PROFILING_ENABLED: Profiling::Toggle(); break; |
| |
| case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break; |
| case IDC_SHOW_APP_MENU: ShowAppMenu(); break; |
| case IDC_SHOW_AVATAR_MENU: ShowAvatarMenu(); break; |
| case IDC_SHOW_HISTORY: ShowHistoryTab(); break; |
| case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break; |
| case IDC_MANAGE_EXTENSIONS: ShowExtensionsTab(); break; |
| case IDC_SYNC_BOOKMARKS: OpenSyncMyBookmarksDialog(); break; |
| case IDC_OPTIONS: OpenOptionsDialog(); break; |
| case IDC_EDIT_SEARCH_ENGINES: OpenSearchEngineOptionsDialog(); break; |
| case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break; |
| case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break; |
| case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break; |
| case IDC_ABOUT: OpenAboutChromeDialog(); break; |
| case IDC_UPGRADE_DIALOG: OpenUpdateChromeDialog(); break; |
| case IDC_VIEW_INCOMPATIBILITIES: ShowAboutConflictsTab(); break; |
| case IDC_HELP_PAGE: ShowHelpTab(); break; |
| #if defined(OS_CHROMEOS) |
| case IDC_LOCK_SCREEN: LockScreen(); break; |
| case IDC_FILE_MANAGER: OpenFileManager(); break; |
| case IDC_SYSTEM_OPTIONS: OpenSystemOptionsDialog(); break; |
| case IDC_INTERNET_OPTIONS: OpenInternetOptionsDialog(); break; |
| case IDC_LANGUAGE_OPTIONS: OpenLanguageOptionsDialog(); break; |
| #endif |
| case IDC_SHOW_SYNC_SETUP: ShowSyncSetup(); break; |
| case IDC_TOGGLE_SPEECH_INPUT: ToggleSpeechInput(); break; |
| |
| default: |
| LOG(WARNING) << "Received Unimplemented Command: " << id; |
| break; |
| } |
| } |
| |
| void Browser::ExecuteCommand(int id, int event_flags) { |
| ExecuteCommandWithDisposition( |
| id, browser::DispositionFromEventFlags(event_flags)); |
| } |
| |
| bool Browser::ExecuteCommandIfEnabled(int id) { |
| if (command_updater_.SupportsCommand(id) && |
| command_updater_.IsCommandEnabled(id)) { |
| ExecuteCommand(id); |
| return true; |
| } |
| return false; |
| } |
| |
| bool Browser::IsReservedCommandOrKey(int command_id, |
| const NativeWebKeyboardEvent& event) { |
| #if defined(OS_CHROMEOS) |
| // Chrome OS's top row of keys produces F1-10. Make sure that web pages |
| // aren't able to block Chrome from performing the standard actions for F1-F4 |
| // (F5-7 are grabbed by other X clients and hence don't need this protection, |
| // and F8-10 are handled separately in Chrome via a GDK event filter, but |
| // let's future-proof this). |
| ui::KeyboardCode key_code = |
| static_cast<ui::KeyboardCode>(event.windowsKeyCode); |
| if (key_code == ui::VKEY_F1 || |
| key_code == ui::VKEY_F2 || |
| key_code == ui::VKEY_F3 || |
| key_code == ui::VKEY_F4 || |
| key_code == ui::VKEY_F5 || |
| key_code == ui::VKEY_F6 || |
| key_code == ui::VKEY_F7 || |
| key_code == ui::VKEY_F8 || |
| key_code == ui::VKEY_F9 || |
| key_code == ui::VKEY_F10) { |
| return true; |
| } |
| #endif |
| |
| if (window_->IsFullscreen() && command_id == IDC_FULLSCREEN) |
| return true; |
| return command_id == IDC_CLOSE_TAB || |
| command_id == IDC_CLOSE_WINDOW || |
| command_id == IDC_NEW_INCOGNITO_WINDOW || |
| command_id == IDC_NEW_TAB || |
| command_id == IDC_NEW_WINDOW || |
| command_id == IDC_RESTORE_TAB || |
| command_id == IDC_SELECT_NEXT_TAB || |
| command_id == IDC_SELECT_PREVIOUS_TAB || |
| command_id == IDC_TABPOSE || |
| command_id == IDC_EXIT || |
| command_id == IDC_SEARCH; |
| } |
| |
| void Browser::SetBlockCommandExecution(bool block) { |
| block_command_execution_ = block; |
| if (block) { |
| last_blocked_command_id_ = -1; |
| last_blocked_command_disposition_ = CURRENT_TAB; |
| } |
| } |
| |
| int Browser::GetLastBlockedCommand(WindowOpenDisposition* disposition) { |
| if (disposition) |
| *disposition = last_blocked_command_disposition_; |
| return last_blocked_command_id_; |
| } |
| |
| void Browser::UpdateUIForNavigationInTab(TabContentsWrapper* contents, |
| content::PageTransition transition, |
| bool user_initiated) { |
| tabstrip_model()->TabNavigating(contents, transition); |
| |
| bool contents_is_selected = contents == GetSelectedTabContentsWrapper(); |
| if (user_initiated && contents_is_selected && window()->GetLocationBar()) { |
| // Forcibly reset the location bar if the url is going to change in the |
| // current tab, since otherwise it won't discard any ongoing user edits, |
| // since it doesn't realize this is a user-initiated action. |
| window()->GetLocationBar()->Revert(); |
| } |
| |
| if (GetStatusBubble()) |
| GetStatusBubble()->Hide(); |
| |
| // Update the location bar. This is synchronous. We specifically don't |
| // update the load state since the load hasn't started yet and updating it |
| // will put it out of sync with the actual state like whether we're |
| // displaying a favicon, which controls the throbber. If we updated it here, |
| // the throbber will show the default favicon for a split second when |
| // navigating away from the new tab page. |
| ScheduleUIUpdate(contents->tab_contents(), TabContents::INVALIDATE_URL); |
| |
| if (contents_is_selected) |
| contents->tab_contents()->Focus(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, PageNavigator implementation: |
| |
| // TODO(adriansc): Remove this method once refactoring changed all call sites. |
| TabContents* Browser::OpenURL(const GURL& url, |
| const GURL& referrer, |
| WindowOpenDisposition disposition, |
| content::PageTransition transition) { |
| // For specifying a referrer, use the version of OpenURL taking OpenURLParams. |
| DCHECK(referrer.is_empty()); |
| return OpenURLFromTab(NULL, |
| OpenURLParams(url, referrer, disposition, transition, |
| false)); |
| } |
| |
| TabContents* Browser::OpenURL(const OpenURLParams& params) { |
| return OpenURLFromTab(NULL, params); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, CommandUpdater::CommandUpdaterDelegate implementation: |
| |
| void Browser::ExecuteCommand(int id) { |
| ExecuteCommandWithDisposition(id, CURRENT_TAB); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, TabHandlerDelegate implementation: |
| |
| Profile* Browser::GetProfile() const { |
| return profile(); |
| } |
| |
| Browser* Browser::AsBrowser() { |
| return this; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, TabStripModelDelegate implementation: |
| |
| TabContentsWrapper* Browser::AddBlankTab(bool foreground) { |
| return AddBlankTabAt(-1, foreground); |
| } |
| |
| TabContentsWrapper* Browser::AddBlankTabAt(int index, bool foreground) { |
| // Time new tab page creation time. We keep track of the timing data in |
| // TabContents, but we want to include the time it takes to create the |
| // TabContents object too. |
| base::TimeTicks new_tab_start_time = base::TimeTicks::Now(); |
| browser::NavigateParams params(this, GURL(chrome::kChromeUINewTabURL), |
| content::PAGE_TRANSITION_TYPED); |
| params.disposition = foreground ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB; |
| params.tabstrip_index = index; |
| browser::Navigate(¶ms); |
| params.target_contents->tab_contents()->set_new_tab_start_time( |
| new_tab_start_time); |
| return params.target_contents; |
| } |
| |
| Browser* Browser::CreateNewStripWithContents( |
| TabContentsWrapper* detached_contents, |
| const gfx::Rect& window_bounds, |
| const DockInfo& dock_info, |
| bool maximize) { |
| DCHECK(CanSupportWindowFeature(FEATURE_TABSTRIP)); |
| |
| gfx::Rect new_window_bounds = window_bounds; |
| if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize)) |
| dock_info.AdjustOtherWindowBounds(); |
| |
| // Create an empty new browser window the same size as the old one. |
| Browser* browser = new Browser(TYPE_TABBED, profile_); |
| browser->set_override_bounds(new_window_bounds); |
| browser->set_show_state( |
| maximize ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL); |
| browser->InitBrowserWindow(); |
| browser->tabstrip_model()->AppendTabContents(detached_contents, true); |
| // Make sure the loading state is updated correctly, otherwise the throbber |
| // won't start if the page is loading. |
| browser->LoadingStateChanged(detached_contents->tab_contents()); |
| return browser; |
| } |
| |
| int Browser::GetDragActions() const { |
| return TabStripModelDelegate::TAB_TEAROFF_ACTION | (tab_count() > 1 ? |
| TabStripModelDelegate::TAB_MOVE_ACTION : 0); |
| } |
| |
| TabContentsWrapper* Browser::CreateTabContentsForURL( |
| const GURL& url, const GURL& referrer, Profile* profile, |
| content::PageTransition transition, bool defer_load, |
| SiteInstance* instance) const { |
| TabContentsWrapper* contents = TabContentsFactory(profile, instance, |
| MSG_ROUTING_NONE, |
| GetSelectedTabContents(), NULL); |
| if (!defer_load) { |
| // Load the initial URL before adding the new tab contents to the tab strip |
| // so that the tab contents has navigation state. |
| contents->controller().LoadURL(url, referrer, transition, std::string()); |
| } |
| |
| return contents; |
| } |
| |
| bool Browser::CanDuplicateContentsAt(int index) { |
| NavigationController& nc = GetTabContentsAt(index)->controller(); |
| return nc.tab_contents() && nc.GetLastCommittedEntry(); |
| } |
| |
| void Browser::DuplicateContentsAt(int index) { |
| TabContentsWrapper* contents = GetTabContentsWrapperAt(index); |
| CHECK(contents); |
| TabContentsWrapper* contents_dupe = contents->Clone(); |
| |
| bool pinned = false; |
| if (CanSupportWindowFeature(FEATURE_TABSTRIP)) { |
| // If this is a tabbed browser, just create a duplicate tab inside the same |
| // window next to the tab being duplicated. |
| int index = tab_handler_->GetTabStripModel()-> |
| GetIndexOfTabContents(contents); |
| pinned = tab_handler_->GetTabStripModel()->IsTabPinned(index); |
| int add_types = TabStripModel::ADD_ACTIVE | |
| TabStripModel::ADD_INHERIT_GROUP | |
| (pinned ? TabStripModel::ADD_PINNED : 0); |
| tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1, |
| contents_dupe, |
| add_types); |
| } else { |
| Browser* browser = NULL; |
| if (is_app()) { |
| CHECK(!is_type_popup()); |
| CHECK(!is_type_panel()); |
| browser = Browser::CreateForApp(TYPE_POPUP, app_name_, gfx::Rect(), |
| profile_); |
| } else if (is_type_popup()) { |
| browser = Browser::CreateForType(TYPE_POPUP, profile_); |
| } |
| |
| // Preserve the size of the original window. The new window has already |
| // been given an offset by the OS, so we shouldn't copy the old bounds. |
| BrowserWindow* new_window = browser->window(); |
| new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(), |
| window()->GetRestoredBounds().size())); |
| |
| // We need to show the browser now. Otherwise ContainerWin assumes the |
| // TabContents is invisible and won't size it. |
| browser->window()->Show(); |
| |
| // The page transition below is only for the purpose of inserting the tab. |
| browser->AddTab(contents_dupe, content::PAGE_TRANSITION_LINK); |
| } |
| |
| SessionService* session_service = |
| SessionServiceFactory::GetForProfileIfExisting(profile_); |
| if (session_service) |
| session_service->TabRestored(contents_dupe, pinned); |
| } |
| |
| void Browser::CloseFrameAfterDragSession() { |
| #if !defined(OS_MACOSX) |
| // This is scheduled to run after we return to the message loop because |
| // otherwise the frame will think the drag session is still active and ignore |
| // the request. |
| // TODO(port): figure out what is required here in a cross-platform world |
| MessageLoop::current()->PostTask( |
| FROM_HERE, base::Bind(&Browser::CloseFrame, weak_factory_.GetWeakPtr())); |
| #endif |
| } |
| |
| void Browser::CreateHistoricalTab(TabContentsWrapper* contents) { |
| // We don't create historical tabs for incognito windows or windows without |
| // profiles. |
| if (!profile() || profile()->IsOffTheRecord()) |
| return; |
| |
| // We don't create historical tabs for print preview tabs. |
| if (contents->tab_contents()->GetURL() == GURL(chrome::kChromeUIPrintURL)) |
| return; |
| |
| TabRestoreService* service = |
| TabRestoreServiceFactory::GetForProfile(profile()); |
| |
| // We only create historical tab entries for tabbed browser windows. |
| if (service && CanSupportWindowFeature(FEATURE_TABSTRIP)) { |
| service->CreateHistoricalTab(&contents->controller(), |
| tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents)); |
| } |
| } |
| |
| bool Browser::RunUnloadListenerBeforeClosing(TabContentsWrapper* contents) { |
| return Browser::RunUnloadEventsHelper(contents->tab_contents()); |
| } |
| |
| bool Browser::CanReloadContents(TabContents* source) const { |
| return !is_devtools(); |
| } |
| |
| bool Browser::CanCloseContents(std::vector<int>* indices) { |
| DCHECK(!indices->empty()); |
| TabCloseableStateWatcher* watcher = |
| g_browser_process->tab_closeable_state_watcher(); |
| bool can_close_all = !watcher || watcher->CanCloseTabs(this, indices); |
| if (indices->empty()) // Cannot close any tab. |
| return false; |
| // Now, handle cases where at least one tab can be closed. |
| // If we are closing all the tabs for this browser, make sure to check for |
| // in-progress downloads. |
| // Note that the next call when it returns false will ask the user for |
| // confirmation before closing the browser if the user decides so. |
| if (tab_handler_->GetTabStripModel()->count() == |
| static_cast<int>(indices->size()) && |
| !CanCloseWithInProgressDownloads()) { |
| indices->clear(); |
| can_close_all = false; |
| } |
| return can_close_all; |
| } |
| |
| bool Browser::CanBookmarkAllTabs() const { |
| BookmarkModel* model = profile()->GetBookmarkModel(); |
| return (model && model->IsLoaded()) && |
| tab_count() > 1 && |
| profile()->GetPrefs()->GetBoolean(prefs::kEditBookmarksEnabled); |
| } |
| |
| void Browser::BookmarkAllTabs() { |
| BookmarkEditor::ShowBookmarkAllTabsDialog(this); |
| } |
| |
| bool Browser::CanCloseTab() const { |
| TabCloseableStateWatcher* watcher = |
| g_browser_process->tab_closeable_state_watcher(); |
| return !watcher || watcher->CanCloseTab(this); |
| } |
| |
| bool Browser::LargeIconsPermitted() const { |
| // We don't show the big icons in tabs for TYPE_EXTENSION_APP windows because |
| // for those windows, we already have a big icon in the top-left outside any |
| // tab. Having big tab icons too looks kinda redonk. |
| return true; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, TabStripModelObserver implementation: |
| |
| void Browser::TabInsertedAt(TabContentsWrapper* contents, |
| int index, |
| bool foreground) { |
| SetAsDelegate(contents, this); |
| contents->restore_tab_helper()->SetWindowID(session_id()); |
| |
| SyncHistoryWithTabs(index); |
| |
| // Make sure the loading state is updated correctly, otherwise the throbber |
| // won't start if the page is loading. |
| LoadingStateChanged(contents->tab_contents()); |
| |
| // If the tab crashes in the beforeunload or unload handler, it won't be |
| // able to ack. But we know we can close it. |
| registrar_.Add(this, content::NOTIFICATION_TAB_CONTENTS_DISCONNECTED, |
| content::Source<TabContents>(contents->tab_contents())); |
| |
| registrar_.Add(this, content::NOTIFICATION_INTERSTITIAL_ATTACHED, |
| content::Source<TabContents>(contents->tab_contents())); |
| } |
| |
| void Browser::TabClosingAt(TabStripModel* tab_strip_model, |
| TabContentsWrapper* contents, |
| int index) { |
| fullscreen_controller_->OnTabClosing(contents->tab_contents()); |
| content::NotificationService::current()->Notify( |
| content::NOTIFICATION_TAB_CLOSING, |
| content::Source<NavigationController>(&contents->controller()), |
| content::NotificationService::NoDetails()); |
| |
| // Sever the TabContents' connection back to us. |
| SetAsDelegate(contents, NULL); |
| } |
| |
| void Browser::TabDetachedAt(TabContentsWrapper* contents, int index) { |
| TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH); |
| } |
| |
| void Browser::TabDeactivated(TabContentsWrapper* contents) { |
| fullscreen_controller_->OnTabDeactivated(contents); |
| if (instant()) |
| instant()->Hide(); |
| |
| // Save what the user's currently typing, so it can be restored when we |
| // switch back to this tab. |
| window_->GetLocationBar()->SaveStateToContents(contents->tab_contents()); |
| } |
| |
| void Browser::ActiveTabChanged(TabContentsWrapper* old_contents, |
| TabContentsWrapper* new_contents, |
| int index, |
| bool user_gesture) { |
| // On some platforms we want to automatically reload tabs that are |
| // killed when the user selects them. |
| if (user_gesture && new_contents->tab_contents()->crashed_status() == |
| base::TERMINATION_STATUS_PROCESS_WAS_KILLED) { |
| const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| if (parsed_command_line.HasSwitch(switches::kReloadKilledTabs)) { |
| Reload(CURRENT_TAB); |
| return; |
| } |
| } |
| |
| // Discarded tabs always get reloaded. |
| if (IsTabDiscarded(index)) { |
| Reload(CURRENT_TAB); |
| return; |
| } |
| |
| // If we have any update pending, do it now. |
| if (chrome_updater_factory_.HasWeakPtrs() && old_contents) |
| ProcessPendingUIUpdates(); |
| |
| // Propagate the profile to the location bar. |
| UpdateToolbar(true); |
| |
| // Update reload/stop state. |
| UpdateReloadStopState(new_contents->tab_contents()->IsLoading(), true); |
| |
| // Update commands to reflect current state. |
| UpdateCommandsForTabState(); |
| |
| // Reset the status bubble. |
| StatusBubble* status_bubble = GetStatusBubble(); |
| if (status_bubble) { |
| status_bubble->Hide(); |
| |
| // Show the loading state (if any). |
| status_bubble->SetStatus(GetSelectedTabContentsWrapper()->GetStatusText()); |
| } |
| |
| if (HasFindBarController()) { |
| find_bar_controller_->ChangeTabContents(new_contents); |
| find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true); |
| } |
| |
| // Update sessions. Don't force creation of sessions. If sessions doesn't |
| // exist, the change will be picked up by sessions when created. |
| SessionService* session_service = |
| SessionServiceFactory::GetForProfileIfExisting(profile_); |
| if (session_service && !tab_handler_->GetTabStripModel()->closing_all()) { |
| session_service->SetSelectedTabInWindow( |
| session_id(), tab_handler_->GetTabStripModel()->active_index()); |
| } |
| |
| UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_SWITCH); |
| } |
| |
| void Browser::TabMoved(TabContentsWrapper* contents, |
| int from_index, |
| int to_index) { |
| DCHECK(from_index >= 0 && to_index >= 0); |
| // Notify the history service. |
| SyncHistoryWithTabs(std::min(from_index, to_index)); |
| } |
| |
| void Browser::TabReplacedAt(TabStripModel* tab_strip_model, |
| TabContentsWrapper* old_contents, |
| TabContentsWrapper* new_contents, |
| int index) { |
| TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE); |
| TabInsertedAt(new_contents, index, |
| (index == tab_handler_->GetTabStripModel()->active_index())); |
| |
| int entry_count = new_contents->controller().entry_count(); |
| if (entry_count > 0) { |
| // Send out notification so that observers are updated appropriately. |
| new_contents->controller().NotifyEntryChanged( |
| new_contents->controller().GetEntryAtIndex(entry_count - 1), |
| entry_count - 1); |
| } |
| |
| SessionService* session_service = |
| SessionServiceFactory::GetForProfile(profile()); |
| if (session_service) { |
| // The new_contents may end up with a different navigation stack. Force |
| // the session service to update itself. |
| session_service->TabRestored( |
| new_contents, tab_handler_->GetTabStripModel()->IsTabPinned(index)); |
| } |
| |
| content::DevToolsManager::GetInstance()->TabReplaced( |
| old_contents->tab_contents(), new_contents->tab_contents()); |
| } |
| |
| void Browser::TabPinnedStateChanged(TabContentsWrapper* contents, int index) { |
| SessionService* session_service = |
| SessionServiceFactory::GetForProfileIfExisting(profile()); |
| if (session_service) { |
| session_service->SetPinnedState( |
| session_id(), |
| GetTabContentsWrapperAt(index)->restore_tab_helper()->session_id(), |
| tab_handler_->GetTabStripModel()->IsTabPinned(index)); |
| } |
| } |
| |
| void Browser::TabStripEmpty() { |
| // Close the frame after we return to the message loop (not immediately, |
| // otherwise it will destroy this object before the stack has a chance to |
| // cleanly unwind.) |
| // Note: This will be called several times if TabStripEmpty is called several |
| // times. This is because it does not close the window if tabs are |
| // still present. |
| // NOTE: If you change to be immediate (no invokeLater) then you'll need to |
| // update BrowserList::CloseAllBrowsers. |
| MessageLoop::current()->PostTask( |
| FROM_HERE, base::Bind(&Browser::CloseFrame, weak_factory_.GetWeakPtr())); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, TabContentsDelegate implementation: |
| |
| // TODO(adriansc): Remove this method once refactoring changed all call sites. |
| TabContents* Browser::OpenURLFromTab(TabContents* source, |
| const GURL& url, |
| const GURL& referrer, |
| WindowOpenDisposition disposition, |
| content::PageTransition transition) { |
| return OpenURLFromTab(source, OpenURLParams(url, referrer, disposition, |
| transition, false)); |
| } |
| |
| TabContents* Browser::OpenURLFromTab(TabContents* source, |
| const OpenURLParams& params) { |
| browser::NavigateParams nav_params(this, params.url, params.transition); |
| nav_params.source_contents = |
| tabstrip_model()->GetTabContentsAt( |
| tabstrip_model()->GetWrapperIndex(source)); |
| nav_params.referrer = params.referrer; |
| nav_params.disposition = params.disposition; |
| nav_params.tabstrip_add_types = TabStripModel::ADD_NONE; |
| nav_params.window_action = browser::NavigateParams::SHOW_WINDOW; |
| nav_params.user_gesture = true; |
| nav_params.override_encoding = params.override_encoding; |
| nav_params.is_renderer_initiated = params.is_renderer_initiated; |
| browser::Navigate(&nav_params); |
| |
| return nav_params.target_contents ? |
| nav_params.target_contents->tab_contents() : NULL; |
| } |
| |
| void Browser::NavigationStateChanged(const TabContents* source, |
| unsigned changed_flags) { |
| // Only update the UI when something visible has changed. |
| if (changed_flags) |
| ScheduleUIUpdate(source, changed_flags); |
| |
| // We can synchronously update commands since they will only change once per |
| // navigation, so we don't have to worry about flickering. We do, however, |
| // need to update the command state early on load to always present usable |
| // actions in the face of slow-to-commit pages. |
| if (changed_flags & (TabContents::INVALIDATE_URL | |
| TabContents::INVALIDATE_LOAD)) |
| UpdateCommandsForTabState(); |
| } |
| |
| void Browser::AddNewContents(TabContents* source, |
| TabContents* new_contents, |
| WindowOpenDisposition disposition, |
| const gfx::Rect& initial_pos, |
| bool user_gesture) { |
| // No code for this yet. |
| DCHECK(disposition != SAVE_TO_DISK); |
| // Can't create a new contents for the current tab - invalid case. |
| DCHECK(disposition != CURRENT_TAB); |
| |
| TabContentsWrapper* source_wrapper = NULL; |
| BlockedContentTabHelper* source_blocked_content = NULL; |
| TabContentsWrapper* new_wrapper = |
| TabContentsWrapper::GetCurrentWrapperForContents(new_contents); |
| if (!new_wrapper) |
| new_wrapper = new TabContentsWrapper(new_contents); |
| if (source) { |
| source_wrapper = TabContentsWrapper::GetCurrentWrapperForContents(source); |
| source_blocked_content = source_wrapper->blocked_content_tab_helper(); |
| } |
| |
| if (source_wrapper) { |
| // Handle blocking of all contents. |
| if (source_blocked_content->all_contents_blocked()) { |
| source_blocked_content->AddTabContents(new_wrapper, |
| disposition, |
| initial_pos, |
| user_gesture); |
| return; |
| } |
| |
| // Handle blocking of popups. |
| if ((disposition == NEW_POPUP) && !user_gesture && |
| !CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kDisablePopupBlocking)) { |
| // Unrequested popups from normal pages are constrained unless they're in |
| // the whitelist. The popup owner will handle checking this. |
| GetConstrainingContentsWrapper(source_wrapper)-> |
| blocked_content_tab_helper()-> |
| AddPopup(new_wrapper, initial_pos, user_gesture); |
| return; |
| } |
| |
| new_contents->render_view_host()->DisassociateFromPopupCount(); |
| } |
| |
| browser::NavigateParams params(this, new_wrapper); |
| params.source_contents = |
| source ? tabstrip_model()->GetTabContentsAt( |
| tabstrip_model()->GetWrapperIndex(source)) |
| : NULL; |
| params.disposition = disposition; |
| params.window_bounds = initial_pos; |
| params.window_action = browser::NavigateParams::SHOW_WINDOW; |
| params.user_gesture = user_gesture; |
| browser::Navigate(¶ms); |
| } |
| |
| void Browser::ActivateContents(TabContents* contents) { |
| tab_handler_->GetTabStripModel()->ActivateTabAt( |
| tab_handler_->GetTabStripModel()->GetWrapperIndex(contents), false); |
| window_->Activate(); |
| } |
| |
| void Browser::DeactivateContents(TabContents* contents) { |
| window_->Deactivate(); |
| } |
| |
| void Browser::LoadingStateChanged(TabContents* source) { |
| window_->UpdateLoadingAnimations( |
| tab_handler_->GetTabStripModel()->TabsAreLoading()); |
| window_->UpdateTitleBar(); |
| |
| TabContents* selected_contents = GetSelectedTabContents(); |
| if (source == selected_contents) { |
| bool is_loading = source->IsLoading(); |
| UpdateReloadStopState(is_loading, false); |
| if (GetStatusBubble()) { |
| GetStatusBubble()->SetStatus( |
| GetSelectedTabContentsWrapper()->GetStatusText()); |
| } |
| |
| if (!is_loading && pending_web_app_action_ == UPDATE_SHORTCUT) { |
| // Schedule a shortcut update when web application info is available if |
| // last committed entry is not NULL. Last committed entry could be NULL |
| // when an interstitial page is injected (e.g. bad https certificate, |
| // malware site etc). When this happens, we abort the shortcut update. |
| NavigationEntry* entry = source->controller().GetLastCommittedEntry(); |
| if (entry) { |
| TabContentsWrapper::GetCurrentWrapperForContents(source)-> |
| extension_tab_helper()->GetApplicationInfo(entry->page_id()); |
| } else { |
| pending_web_app_action_ = NONE; |
| } |
| } |
| } |
| } |
| |
| void Browser::CloseContents(TabContents* source) { |
| if (is_attempting_to_close_browser_) { |
| // If we're trying to close the browser, just clear the state related to |
| // waiting for unload to fire. Don't actually try to close the tab as it |
| // will go down the slow shutdown path instead of the fast path of killing |
| // all the renderer processes. |
| ClearUnloadState(source, true); |
| return; |
| } |
| |
| int index = tab_handler_->GetTabStripModel()->GetWrapperIndex(source); |
| if (index == TabStripModel::kNoTab) { |
| NOTREACHED() << "CloseContents called for tab not in our strip"; |
| return; |
| } |
| tab_handler_->GetTabStripModel()->CloseTabContentsAt( |
| index, |
| TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); |
| } |
| |
| void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) { |
| if (!IsPopupOrPanel(source)) { |
| NOTREACHED() << "moving invalid browser type"; |
| return; |
| } |
| window_->SetBounds(pos); |
| } |
| |
| void Browser::DetachContents(TabContents* source) { |
| int index = tab_handler_->GetTabStripModel()->GetWrapperIndex(source); |
| if (index >= 0) |
| tab_handler_->GetTabStripModel()->DetachTabContentsAt(index); |
| } |
| |
| bool Browser::IsPopupOrPanel(const TabContents* source) const { |
| // A non-tabbed BROWSER is an unconstrained popup. |
| return is_type_popup() || is_type_panel(); |
| } |
| |
| void Browser::ContentsMouseEvent( |
| TabContents* source, const gfx::Point& location, bool motion) { |
| if (!GetStatusBubble()) |
| return; |
| |
| if (source == GetSelectedTabContents()) { |
| GetStatusBubble()->MouseMoved(location, !motion); |
| if (!motion) |
| GetStatusBubble()->SetURL(GURL(), std::string()); |
| } |
| } |
| |
| void Browser::UpdateTargetURL(TabContents* source, int32 page_id, |
| const GURL& url) { |
| Browser::UpdateTargetURLHelper(source, page_id, url); |
| |
| if (!GetStatusBubble()) |
| return; |
| |
| if (source == GetSelectedTabContents()) { |
| PrefService* prefs = profile_->GetPrefs(); |
| GetStatusBubble()->SetURL(url, prefs->GetString(prefs::kAcceptLanguages)); |
| } |
| } |
| |
| void Browser::UpdateDownloadShelfVisibility(bool visible) { |
| if (GetStatusBubble()) |
| GetStatusBubble()->UpdateDownloadShelfVisibility(visible); |
| } |
| |
| void Browser::ContentsZoomChange(bool zoom_in) { |
| ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS); |
| } |
| |
| void Browser::TabContentsFocused(TabContents* tab_content) { |
| window_->TabContentsFocused(tab_content); |
| } |
| |
| bool Browser::TakeFocus(bool reverse) { |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_FOCUS_RETURNED_TO_BROWSER, |
| content::Source<Browser>(this), |
| content::NotificationService::NoDetails()); |
| return false; |
| } |
| |
| bool Browser::IsApplication() const { |
| return is_app(); |
| } |
| |
| void Browser::ConvertContentsToApplication(TabContents* contents) { |
| const GURL& url = contents->controller().GetActiveEntry()->url(); |
| std::string app_name = web_app::GenerateApplicationNameFromURL(url); |
| |
| DetachContents(contents); |
| Browser* app_browser = Browser::CreateForApp( |
| TYPE_POPUP, app_name, gfx::Rect(), profile_); |
| TabContentsWrapper* wrapper = |
| TabContentsWrapper::GetCurrentWrapperForContents(contents); |
| if (!wrapper) |
| wrapper = new TabContentsWrapper(contents); |
| app_browser->tabstrip_model()->AppendTabContents(wrapper, true); |
| |
| contents->GetMutableRendererPrefs()->can_accept_load_drops = false; |
| contents->render_view_host()->SyncRendererPrefs(); |
| app_browser->window()->Show(); |
| } |
| |
| void Browser::BeforeUnloadFired(TabContents* tab, |
| bool proceed, |
| bool* proceed_to_fire_unload) { |
| if (!is_attempting_to_close_browser_) { |
| *proceed_to_fire_unload = proceed; |
| if (!proceed) |
| tab->set_closed_by_user_gesture(false); |
| return; |
| } |
| |
| if (!proceed) { |
| CancelWindowClose(); |
| *proceed_to_fire_unload = false; |
| tab->set_closed_by_user_gesture(false); |
| return; |
| } |
| |
| if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) { |
| // Now that beforeunload has fired, put the tab on the queue to fire |
| // unload. |
| tabs_needing_unload_fired_.insert(tab); |
| ProcessPendingTabs(); |
| // We want to handle firing the unload event ourselves since we want to |
| // fire all the beforeunload events before attempting to fire the unload |
| // events should the user cancel closing the browser. |
| *proceed_to_fire_unload = false; |
| return; |
| } |
| |
| *proceed_to_fire_unload = true; |
| } |
| |
| void Browser::SetFocusToLocationBar(bool select_all) { |
| // Two differences between this and FocusLocationBar(): |
| // (1) This doesn't get recorded in user metrics, since it's called |
| // internally. |
| // (2) This checks whether the location bar can be focused, and if not, clears |
| // the focus. FocusLocationBar() is only reached when the location bar is |
| // focusable, but this may be reached at other times, e.g. while in |
| // fullscreen mode, where we need to leave focus in a consistent state. |
| window_->SetFocusToLocationBar(select_all); |
| } |
| |
| void Browser::RenderWidgetShowing() { |
| window_->DisableInactiveFrame(); |
| } |
| |
| int Browser::GetExtraRenderViewHeight() const { |
| return window_->GetExtraRenderViewHeight(); |
| } |
| |
| namespace { |
| |
| bool DisplayOldDownloadsUI() { |
| return !CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kDownloadsNewUI); |
| } |
| |
| } // anonymous namespace |
| |
| void Browser::OnStartDownload(TabContents* source, DownloadItem* download) { |
| TabContentsWrapper* wrapper = |
| TabContentsWrapper::GetCurrentWrapperForContents(source); |
| TabContentsWrapper* constrained = GetConstrainingContentsWrapper(wrapper); |
| if (constrained != wrapper) { |
| // Download in a constrained popup is shown in the tab that opened it. |
| TabContents* constrained_tab = constrained->tab_contents(); |
| constrained_tab->delegate()->OnStartDownload(constrained_tab, download); |
| return; |
| } |
| |
| if (!window()) |
| return; |
| |
| if (DisplayOldDownloadsUI()) { |
| #if defined(OS_CHROMEOS) && !defined(USE_AURA) |
| // Don't show content browser for extension/theme downloads from gallery. |
| ExtensionService* service = profile_->GetExtensionService(); |
| if (!ChromeDownloadManagerDelegate::IsExtensionDownload(download) || |
| service == NULL || |
| !service->IsDownloadFromGallery(download->GetURL(), |
| download->GetReferrerUrl())) { |
| // Open the Active Downloads ui for chromeos. |
| ActiveDownloadsUI::OpenPopup(profile_); |
| } |
| #else |
| // GetDownloadShelf creates the download shelf if it was not yet created. |
| DownloadShelf* shelf = window()->GetDownloadShelf(); |
| shelf->AddDownload(new DownloadItemModel(download)); |
| // Don't show the animation for "Save file" downloads. |
| // For non-theme extensions, we don't show the download animation. |
| // Show animation in same window as the download shelf. Download shelf |
| // may not be in the same window that initiated the download, e.g. |
| // Panels. |
| // Don't show the animation if the selected tab is not visible (i.e. the |
| // window is minimized, we're in a unit test, etc.). |
| TabContents* shelf_tab = shelf->browser()->GetSelectedTabContents(); |
| if ((download->GetTotalBytes() > 0) && |
| !ChromeDownloadManagerDelegate::IsExtensionDownload(download) && |
| platform_util::IsVisible(shelf_tab->GetNativeView()) && |
| ui::Animation::ShouldRenderRichAnimation()) { |
| DownloadStartedAnimation::Show(shelf_tab); |
| } |
| #endif |
| } |
| |
| // If the download occurs in a new tab, close it. |
| if (source->controller().IsInitialNavigation() && tab_count() > 1) |
| CloseContents(source); |
| } |
| |
| void Browser::ShowPageInfo(content::BrowserContext* browser_context, |
| const GURL& url, |
| const NavigationEntry::SSLStatus& ssl, |
| bool show_history) { |
| Profile* profile = Profile::FromBrowserContext(browser_context); |
| window()->ShowPageInfo(profile, url, ssl, show_history); |
| } |
| |
| void Browser::ViewSourceForTab(TabContents* source, const GURL& page_url) { |
| DCHECK(source); |
| int index = tabstrip_model()->GetWrapperIndex(source); |
| TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index); |
| ViewSource(wrapper); |
| } |
| |
| void Browser::ViewSourceForFrame(TabContents* source, |
| const GURL& frame_url, |
| const std::string& frame_content_state) { |
| DCHECK(source); |
| int index = tabstrip_model()->GetWrapperIndex(source); |
| TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index); |
| ViewSource(wrapper, frame_url, frame_content_state); |
| } |
| |
| bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, |
| bool* is_keyboard_shortcut) { |
| // Escape exits tabbed fullscreen mode. |
| // TODO(koz): Write a test for this http://crbug.com/100441. |
| if (event.windowsKeyCode == 27 && |
| fullscreen_controller_->HandleUserPressedEscape()) { |
| return true; |
| } |
| return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut); |
| } |
| |
| void Browser::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { |
| window()->HandleKeyboardEvent(event); |
| } |
| |
| void Browser::ShowRepostFormWarningDialog(TabContents *tab_contents) { |
| window()->ShowRepostFormWarningDialog(tab_contents); |
| } |
| |
| void Browser::ShowContentSettingsPage(ContentSettingsType content_type) { |
| ShowOptionsTab( |
| chrome::kContentSettingsExceptionsSubPage + std::string(kHashMark) + |
| ContentSettingsHandler::ContentSettingsTypeToGroupName(content_type)); |
| } |
| |
| void Browser::ShowCollectedCookiesDialog(TabContentsWrapper* wrapper) { |
| window()->ShowCollectedCookiesDialog(wrapper); |
| } |
| |
| bool Browser::ShouldAddNavigationToHistory( |
| const history::HistoryAddPageArgs& add_page_args, |
| content::NavigationType navigation_type) { |
| // Don't update history if running as app. |
| return !IsApplication(); |
| } |
| |
| void Browser::TabContentsCreated(TabContents* new_contents) { |
| // Create a TabContentsWrapper now, so all observers are in place, as the |
| // network requests for its initial navigation will start immediately. The |
| // TabContents will later be inserted into this browser using |
| // Browser::Navigate via AddNewContents. The latter will retrieve the newly |
| // created TabContentsWrapper from TabContents object. |
| new TabContentsWrapper(new_contents); |
| } |
| |
| void Browser::ContentRestrictionsChanged(TabContents* source) { |
| UpdateCommandsForContentRestrictionState(); |
| } |
| |
| void Browser::RendererUnresponsive(TabContents* source) { |
| // Ignore hangs if print preview is open. |
| TabContentsWrapper* source_wrapper = |
| TabContentsWrapper::GetCurrentWrapperForContents(source); |
| if (source_wrapper) { |
| printing::PrintPreviewTabController* controller = |
| printing::PrintPreviewTabController::GetInstance(); |
| if (controller) { |
| TabContentsWrapper* preview_tab = |
| controller->GetPrintPreviewForTab(source_wrapper); |
| if (preview_tab && preview_tab != source_wrapper) { |
| return; |
| } |
| } |
| } |
| |
| browser::ShowHungRendererDialog(source); |
| } |
| |
| void Browser::RendererResponsive(TabContents* source) { |
| browser::HideHungRendererDialog(source); |
| } |
| |
| void Browser::WorkerCrashed(TabContents* source) { |
| TabContentsWrapper* wrapper = |
| TabContentsWrapper::GetCurrentWrapperForContents(source); |
| InfoBarTabHelper* infobar_helper = wrapper->infobar_tab_helper(); |
| infobar_helper->AddInfoBar(new SimpleAlertInfoBarDelegate( |
| infobar_helper, |
| NULL, |
| l10n_util::GetStringUTF16(IDS_WEBWORKER_CRASHED_PROMPT), |
| true)); |
| } |
| |
| void Browser::DidNavigateMainFramePostCommit(TabContents* tab) { |
| if (tab == GetSelectedTabContents()) |
| UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE); |
| } |
| |
| void Browser::DidNavigateToPendingEntry(TabContents* tab) { |
| if (tab == GetSelectedTabContents()) |
| UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE); |
| } |
| |
| content::JavaScriptDialogCreator* Browser::GetJavaScriptDialogCreator() { |
| return GetJavaScriptDialogCreatorInstance(); |
| } |
| |
| void Browser::RunFileChooser(TabContents* tab, |
| const content::FileChooserParams& params) { |
| RunFileChooserHelper(tab, params); |
| } |
| |
| void Browser::EnumerateDirectory(TabContents* tab, int request_id, |
| const FilePath& path) { |
| EnumerateDirectoryHelper(tab, request_id, path); |
| } |
| |
| void Browser::ToggleFullscreenModeForTab(TabContents* tab, |
| bool enter_fullscreen) { |
| fullscreen_controller_->ToggleFullscreenModeForTab(tab, enter_fullscreen); |
| } |
| |
| bool Browser::IsFullscreenForTab(const TabContents* tab) const { |
| return fullscreen_controller_->IsFullscreenForTab(tab); |
| } |
| |
| void Browser::JSOutOfMemory(TabContents* tab) { |
| JSOutOfMemoryHelper(tab); |
| } |
| |
| void Browser::RegisterProtocolHandler(TabContents* tab, |
| const std::string& protocol, |
| const GURL& url, |
| const string16& title) { |
| RegisterProtocolHandlerHelper(tab, protocol, url, title); |
| } |
| |
| void Browser::RegisterIntentHandler(TabContents* tab, |
| const string16& action, |
| const string16& type, |
| const string16& href, |
| const string16& title, |
| const string16& disposition) { |
| RegisterIntentHandlerHelper(tab, action, type, href, title, disposition); |
| } |
| |
| void Browser::WebIntentDispatch(TabContents* tab, |
| content::IntentsHost* intents_host) { |
| if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableWebIntents)) |
| return; |
| |
| TabContentsWrapper* tcw = |
| TabContentsWrapper::GetCurrentWrapperForContents(tab); |
| tcw->web_intent_picker_controller()->SetIntentsHost(intents_host); |
| tcw->web_intent_picker_controller()->ShowDialog( |
| this, intents_host->GetIntent().action, intents_host->GetIntent().type); |
| } |
| |
| void Browser::FindReply(TabContents* tab, |
| int request_id, |
| int number_of_matches, |
| const gfx::Rect& selection_rect, |
| int active_match_ordinal, |
| bool final_update) { |
| FindReplyHelper(tab, request_id, number_of_matches, selection_rect, |
| active_match_ordinal, final_update); |
| } |
| |
| void Browser::CrashedPlugin(TabContents* tab, const FilePath& plugin_path) { |
| CrashedPluginHelper(tab, plugin_path); |
| } |
| |
| void Browser::UpdatePreferredSize(TabContents* source, |
| const gfx::Size& pref_size) { |
| window_->UpdatePreferredSize(source, pref_size); |
| } |
| |
| void Browser::RequestToLockMouse(TabContents* tab) { |
| fullscreen_controller_->RequestToLockMouse(tab); |
| } |
| |
| void Browser::LostMouseLock() { |
| fullscreen_controller_->LostMouseLock(); |
| } |
| |
| void Browser::OnAcceptFullscreenPermission( |
| const GURL& url, |
| FullscreenExitBubbleType bubble_type) { |
| fullscreen_controller_->OnAcceptFullscreenPermission(url, bubble_type); |
| } |
| |
| void Browser::OnDenyFullscreenPermission(FullscreenExitBubbleType bubble_type) { |
| fullscreen_controller_->OnDenyFullscreenPermission(bubble_type); |
| } |
| |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, TabContentsWrapperDelegate implementation: |
| |
| void Browser::OnDidGetApplicationInfo(TabContentsWrapper* source, |
| int32 page_id) { |
| if (GetSelectedTabContentsWrapper() != source) |
| return; |
| |
| NavigationEntry* entry = source->controller().GetLastCommittedEntry(); |
| if (!entry || (entry->page_id() != page_id)) |
| return; |
| |
| switch (pending_web_app_action_) { |
| case CREATE_SHORTCUT: { |
| window()->ShowCreateWebAppShortcutsDialog(source); |
| break; |
| } |
| case UPDATE_SHORTCUT: { |
| web_app::UpdateShortcutForTabContents(source); |
| break; |
| } |
| default: |
| NOTREACHED(); |
| break; |
| } |
| |
| pending_web_app_action_ = NONE; |
| } |
| |
| void Browser::OnInstallApplication(TabContentsWrapper* source, |
| const WebApplicationInfo& web_app) { |
| ExtensionService* extension_service = profile()->GetExtensionService(); |
| if (!extension_service) |
| return; |
| |
| scoped_refptr<CrxInstaller> installer(CrxInstaller::Create( |
| extension_service, |
| extension_service->show_extensions_prompts() ? |
| new ExtensionInstallUI(profile()) : NULL)); |
| installer->InstallWebApp(web_app); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, SearchEngineTabHelperDelegate implementation: |
| |
| void Browser::ConfirmSetDefaultSearchProvider(TabContents* tab_contents, |
| TemplateURL* template_url, |
| Profile* profile) { |
| window()->ConfirmSetDefaultSearchProvider(tab_contents, template_url, |
| profile); |
| } |
| |
| void Browser::ConfirmAddSearchProvider(const TemplateURL* template_url, |
| Profile* profile) { |
| #if defined(OS_CHROMEOS) || defined(USE_AURA) |
| // Use a WebUI implementation of the dialog. |
| browser::ConfirmAddSearchProvider(template_url, profile); |
| #else |
| // TODO(rbyers): Remove the IsMoreWebUI check and (ideally) all #ifdefs once |
| // we can select exactly one version of this dialog to use for each platform |
| // at build time. |
| if (ChromeWebUI::IsMoreWebUI()) |
| browser::ConfirmAddSearchProvider(template_url, profile); |
| else |
| // Platform-specific implementation of the dialog. |
| window()->ConfirmAddSearchProvider(template_url, profile); |
| #endif |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, BlockedContentTabHelperDelegate implementation: |
| |
| TabContentsWrapper* Browser::GetConstrainingContentsWrapper( |
| TabContentsWrapper* source) { |
| return source; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, BookmarkTabHelperDelegate implementation: |
| |
| void Browser::URLStarredChanged(TabContentsWrapper* source, bool starred) { |
| if (source == GetSelectedTabContentsWrapper()) |
| window_->SetStarredState(starred); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, SelectFileDialog::Listener implementation: |
| |
| void Browser::FileSelected(const FilePath& path, int index, void* params) { |
| profile_->set_last_selected_directory(path.DirName()); |
| GURL file_url = net::FilePathToFileURL(path); |
| if (!file_url.is_empty()) |
| OpenURL(file_url, GURL(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, content::NotificationObserver implementation: |
| |
| void Browser::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| switch (type) { |
| case content::NOTIFICATION_TAB_CONTENTS_DISCONNECTED: |
| if (is_attempting_to_close_browser_) { |
| // Pass in false so that we delay processing. We need to delay the |
| // processing as it may close the tab, which is currently on the call |
| // stack above us. |
| ClearUnloadState(content::Source<TabContents>(source).ptr(), false); |
| } |
| break; |
| |
| case content::NOTIFICATION_SSL_VISIBLE_STATE_CHANGED: |
| // When the current tab's SSL state changes, we need to update the URL |
| // bar to reflect the new state. Note that it's possible for the selected |
| // tab contents to be NULL. This is because we listen for all sources |
| // (NavigationControllers) for convenience, so the notification could |
| // actually be for a different window while we're doing asynchronous |
| // closing of this one. |
| if (GetSelectedTabContents() && |
| &GetSelectedTabContents()->controller() == |
| content::Source<NavigationController>(source).ptr()) |
| UpdateToolbar(false); |
| break; |
| |
| case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED: { |
| // Show the UI if the extension was disabled for escalated permissions. |
| Profile* profile = content::Source<Profile>(source).ptr(); |
| if (profile_->IsSameProfile(profile)) { |
| ExtensionService* service = profile->GetExtensionService(); |
| DCHECK(service); |
| const Extension* extension = |
| content::Details<const Extension>(details).ptr(); |
| if (service->extension_prefs()->DidExtensionEscalatePermissions( |
| extension->id())) |
| ShowExtensionDisabledUI(service, profile_, extension); |
| } |
| break; |
| } |
| |
| case chrome::NOTIFICATION_EXTENSION_UNLOADED: { |
| if (window()->GetLocationBar()) |
| window()->GetLocationBar()->UpdatePageActions(); |
| |
| // Close any tabs from the unloaded extension, unless it's terminated, |
| // in which case let the sad tabs remain. |
| if (content::Details<UnloadedExtensionInfo>(details)->reason != |
| extension_misc::UNLOAD_REASON_TERMINATE) { |
| const Extension* extension = |
| content::Details<UnloadedExtensionInfo>(details)->extension; |
| TabStripModel* model = tab_handler_->GetTabStripModel(); |
| for (int i = model->count() - 1; i >= 0; --i) { |
| TabContents* tc = model->GetTabContentsAt(i)->tab_contents(); |
| bool close_tab_contents = |
| tc->GetURL().SchemeIs(chrome::kExtensionScheme) && |
| tc->GetURL().host() == extension->id(); |
| // We want to close all panels originated by the unloaded extension. |
| close_tab_contents = close_tab_contents || |
| (type_ == TYPE_PANEL && |
| (web_app::GetExtensionIdFromApplicationName(app_name_) == |
| extension->id())); |
| if (close_tab_contents) { |
| CloseTabContents(tc); |
| } |
| } |
| } |
| break; |
| } |
| |
| case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: { |
| Profile* profile = content::Source<Profile>(source).ptr(); |
| if (profile_->IsSameProfile(profile) && window()->GetLocationBar()) |
| window()->GetLocationBar()->InvalidatePageActions(); |
| break; |
| } |
| |
| case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: |
| case chrome::NOTIFICATION_EXTENSION_LOADED: |
| // During window creation on Windows we may end up calling into |
| // SHAppBarMessage, which internally spawns a nested message loop. This |
| // makes it possible for us to end up here before window creation has |
| // completed,at which point window_ is NULL. See 94752 for details. |
| if (window() && window()->GetLocationBar()) |
| window()->GetLocationBar()->UpdatePageActions(); |
| break; |
| |
| case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: |
| window()->UserChangedTheme(); |
| break; |
| |
| case chrome::NOTIFICATION_PREF_CHANGED: { |
| const std::string& pref_name = |
| *content::Details<std::string>(details).ptr(); |
| if (pref_name == prefs::kPrintingEnabled) { |
| UpdatePrintingState(GetContentRestrictionsForSelectedTab()); |
| } else if (pref_name == prefs::kInstantEnabled || |
| pref_name == prefs::kMetricsReportingEnabled || |
| pref_name == prefs::kSearchSuggestEnabled) { |
| if (!InstantController::IsEnabled(profile())) { |
| if (instant()) { |
| instant()->DestroyPreviewContents(); |
| instant_.reset(); |
| instant_unload_handler_.reset(); |
| } |
| } else { |
| CreateInstantIfNecessary(); |
| } |
| } else if (pref_name == prefs::kIncognitoModeAvailability) { |
| UpdateCommandsForIncognitoAvailability(); |
| } else if (pref_name == prefs::kDevToolsDisabled) { |
| UpdateCommandsForDevTools(); |
| if (profile_->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled)) |
| content::DevToolsManager::GetInstance()->CloseAllClientHosts(); |
| } else if (pref_name == prefs::kEditBookmarksEnabled) { |
| UpdateCommandsForBookmarkEditing(); |
| } else if (pref_name == prefs::kShowBookmarkBar) { |
| UpdateCommandsForBookmarkBar(); |
| UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_PREF_CHANGE); |
| } else if (pref_name == prefs::kHomePage) { |
| PrefService* pref_service = content::Source<PrefService>(source).ptr(); |
| MarkHomePageAsChanged(pref_service); |
| } else if (pref_name == prefs::kAllowFileSelectionDialogs) { |
| UpdateSaveAsState(GetContentRestrictionsForSelectedTab()); |
| UpdateOpenFileState(); |
| } else { |
| NOTREACHED(); |
| } |
| break; |
| } |
| |
| case chrome::NOTIFICATION_TAB_CONTENT_SETTINGS_CHANGED: { |
| TabContents* tab_contents = content::Source<TabContents>(source).ptr(); |
| if (tab_contents == GetSelectedTabContents()) { |
| LocationBar* location_bar = window()->GetLocationBar(); |
| if (location_bar) |
| location_bar->UpdateContentSettingsIcons(); |
| } |
| break; |
| } |
| |
| case content::NOTIFICATION_INTERSTITIAL_ATTACHED: |
| UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE); |
| break; |
| |
| case chrome::NOTIFICATION_FULLSCREEN_CHANGED: |
| UpdateCommandsForFullscreenMode(window_->IsFullscreen()); |
| UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TOGGLE_FULLSCREEN); |
| break; |
| |
| default: |
| NOTREACHED() << "Got a notification we didn't register for."; |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, ProfileSyncServiceObserver implementation: |
| |
| void Browser::OnStateChanged() { |
| DCHECK(profile_->GetProfileSyncService()); |
| |
| const bool show_main_ui = IsShowingMainUI(window_->IsFullscreen()); |
| command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, |
| show_main_ui && profile_->GetOriginalProfile()->IsSyncAccessible()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, InstantDelegate implementation: |
| |
| void Browser::ShowInstant(TabContentsWrapper* preview_contents) { |
| DCHECK(instant_->tab_contents() == GetSelectedTabContentsWrapper()); |
| window_->ShowInstant(preview_contents); |
| |
| GetSelectedTabContents()->HideContents(); |
| preview_contents->tab_contents()->ShowContents(); |
| } |
| |
| void Browser::HideInstant() { |
| window_->HideInstant(); |
| if (GetSelectedTabContents()) |
| GetSelectedTabContents()->ShowContents(); |
| if (instant_->GetPreviewContents()) |
| instant_->GetPreviewContents()->tab_contents()->HideContents(); |
| } |
| |
| void Browser::CommitInstant(TabContentsWrapper* preview_contents) { |
| TabContentsWrapper* tab_contents = instant_->tab_contents(); |
| int index = |
| tab_handler_->GetTabStripModel()->GetIndexOfTabContents(tab_contents); |
| DCHECK_NE(TabStripModel::kNoTab, index); |
| // TabStripModel takes ownership of preview_contents. |
| tab_handler_->GetTabStripModel()->ReplaceTabContentsAt( |
| index, preview_contents); |
| // InstantUnloadHandler takes ownership of tab_contents. |
| instant_unload_handler_->RunUnloadListenersOrDestroy(tab_contents, index); |
| |
| GURL url = preview_contents->tab_contents()->GetURL(); |
| DCHECK(profile_->GetExtensionService()); |
| if (profile_->GetExtensionService()->IsInstalledApp(url)) { |
| UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, |
| extension_misc::APP_LAUNCH_OMNIBOX_INSTANT, |
| extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
| } |
| } |
| |
| void Browser::SwapTabContents(TabContentsWrapper* old_tab_contents, |
| TabContentsWrapper* new_tab_contents) { |
| int index = |
| tab_handler_->GetTabStripModel()->GetIndexOfTabContents(old_tab_contents); |
| DCHECK_NE(TabStripModel::kNoTab, index); |
| tab_handler_->GetTabStripModel()->ReplaceTabContentsAt(index, |
| new_tab_contents); |
| } |
| |
| void Browser::SetTabContentBlocked(TabContentsWrapper* wrapper, bool blocked) { |
| int index = tabstrip_model()->GetIndexOfTabContents(wrapper); |
| if (index == TabStripModel::kNoTab) { |
| NOTREACHED(); |
| return; |
| } |
| tabstrip_model()->SetTabBlocked(index, blocked); |
| UpdatePrintingState(wrapper->tab_contents()->content_restrictions()); |
| } |
| |
| void Browser::SetSuggestedText(const string16& text, |
| InstantCompleteBehavior behavior) { |
| if (window()->GetLocationBar()) |
| window()->GetLocationBar()->SetSuggestedText(text, behavior); |
| } |
| |
| gfx::Rect Browser::GetInstantBounds() { |
| return window()->GetInstantBounds(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, protected: |
| |
| BrowserWindow* Browser::CreateBrowserWindow() { |
| #if !defined(OS_CHROMEOS) || defined(USE_AURA) |
| if (type_ == TYPE_PANEL) { |
| DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kDisablePanels)); |
| return PanelManager::GetInstance()->CreatePanel(this); |
| } |
| #endif |
| |
| return BrowserWindow::CreateBrowserWindow(this); |
| } |
| |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, Command and state updating (private): |
| |
| void Browser::InitCommandState() { |
| // All browser commands whose state isn't set automagically some other way |
| // (like Back & Forward with initial page load) must have their state |
| // initialized here, otherwise they will be forever disabled. |
| |
| // Navigation commands |
| command_updater_.UpdateCommandEnabled(IDC_RELOAD, true); |
| command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, true); |
| |
| // Window management commands |
| command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true); |
| command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true); |
| command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true); |
| command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true); |
| command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, false); |
| command_updater_.UpdateCommandEnabled(IDC_EXIT, true); |
| command_updater_.UpdateCommandEnabled(IDC_DEBUG_FRAME_TOGGLE, true); |
| |
| // Page-related commands |
| command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598I, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true); |
| |
| // Zoom |
| command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true); |
| command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true); |
| command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true); |
| command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true); |
| |
| // Show various bits of UI |
| UpdateOpenFileState(); |
| command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false); |
| UpdateCommandsForDevTools(); |
| command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true); |
| command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true); |
| command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true); |
| command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true); |
| command_updater_.UpdateCommandEnabled(IDC_BOOKMARKS_MENU, true); |
| |
| #if defined(OS_CHROMEOS) |
| command_updater_.UpdateCommandEnabled(IDC_LOCK_SCREEN, true); |
| command_updater_.UpdateCommandEnabled(IDC_FILE_MANAGER, true); |
| command_updater_.UpdateCommandEnabled(IDC_SEARCH, true); |
| command_updater_.UpdateCommandEnabled(IDC_SHOW_KEYBOARD_OVERLAY, true); |
| command_updater_.UpdateCommandEnabled(IDC_SYSTEM_OPTIONS, true); |
| command_updater_.UpdateCommandEnabled(IDC_INTERNET_OPTIONS, true); |
| #endif |
| command_updater_.UpdateCommandEnabled( |
| IDC_SHOW_SYNC_SETUP, profile_->GetOriginalProfile()->IsSyncAccessible()); |
| |
| // Initialize other commands based on the window type. |
| bool normal_window = is_type_tabbed(); |
| |
| // Navigation commands |
| command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window); |
| |
| // Window management commands |
| // TODO(rohitrao): Disable fullscreen on non-Lion? |
| command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, |
| !(is_type_panel() && is_app())); |
| command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, |
| normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_NEXT, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_PREVIOUS, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window); |
| #if defined(OS_MACOSX) |
| command_updater_.UpdateCommandEnabled(IDC_TABPOSE, normal_window); |
| command_updater_.UpdateCommandEnabled(IDC_PRESENTATION_MODE, |
| !(is_type_panel() && is_app())); |
| #endif |
| |
| // Clipboard commands |
| command_updater_.UpdateCommandEnabled(IDC_COPY_URL, !is_devtools()); |
| |
| // Find-in-page |
| command_updater_.UpdateCommandEnabled(IDC_FIND, !is_devtools()); |
| command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, !is_devtools()); |
| command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, !is_devtools()); |
| |
| // Show various bits of UI |
| command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window); |
| |
| // The upgrade entry and the view incompatibility entry should always be |
| // enabled. Whether they are visible is a separate matter determined on menu |
| // show. |
| command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true); |
| command_updater_.UpdateCommandEnabled(IDC_VIEW_INCOMPATIBILITIES, true); |
| |
| // View Background Pages entry is always enabled, but is hidden if there are |
| // no background pages. |
| command_updater_.UpdateCommandEnabled(IDC_VIEW_BACKGROUND_PAGES, true); |
| |
| // Toggle speech input |
| command_updater_.UpdateCommandEnabled(IDC_TOGGLE_SPEECH_INPUT, true); |
| |
| // Initialize other commands whose state changes based on fullscreen mode. |
| UpdateCommandsForFullscreenMode(false); |
| |
| UpdateCommandsForContentRestrictionState(); |
| |
| UpdateCommandsForBookmarkEditing(); |
| |
| UpdateCommandsForIncognitoAvailability(); |
| } |
| |
| bool Browser::IsShowingMainUI(bool is_fullscreen) { |
| #if !defined(OS_MACOSX) |
| return is_type_tabbed() && !is_fullscreen; |
| #else |
| return is_type_tabbed(); |
| #endif |
| } |
| |
| void Browser::UpdateCommandsForIncognitoAvailability() { |
| IncognitoModePrefs::Availability incognito_availability = |
| IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); |
| command_updater_.UpdateCommandEnabled( |
| IDC_NEW_WINDOW, |
| incognito_availability != IncognitoModePrefs::FORCED); |
| command_updater_.UpdateCommandEnabled( |
| IDC_NEW_INCOGNITO_WINDOW, |
| incognito_availability != IncognitoModePrefs::DISABLED); |
| |
| // Bookmark manager and settings page/subpages are forced to open in normal |
| // mode. For this reason we disable these commands when incognito is forced. |
| const bool command_enabled = |
| incognito_availability != IncognitoModePrefs::FORCED; |
| command_updater_.UpdateCommandEnabled( |
| IDC_SHOW_BOOKMARK_MANAGER, |
| browser_defaults::bookmarks_enabled && command_enabled); |
| ExtensionService* extension_service = profile()->GetExtensionService(); |
| bool enable_extensions = |
| extension_service && extension_service->extensions_enabled(); |
| command_updater_.UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS, |
| enable_extensions && command_enabled); |
| |
| const bool show_main_ui = IsShowingMainUI(window_ && window_->IsFullscreen()); |
| command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, |
| show_main_ui && command_enabled); |
| command_updater_.UpdateCommandEnabled(IDC_OPTIONS, |
| show_main_ui && command_enabled); |
| } |
| |
| void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) { |
| const bool show_main_ui = IsShowingMainUI(is_fullscreen); |
| bool main_not_fullscreen = show_main_ui && !is_fullscreen; |
| |
| // Navigation commands |
| command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui); |
| |
| // Window management commands |
| command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB, |
| type_ != TYPE_TABBED && !is_fullscreen); |
| |
| // Focus various bits of UI |
| command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui); |
| command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui); |
| command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui); |
| command_updater_.UpdateCommandEnabled( |
| IDC_FOCUS_MENU_BAR, main_not_fullscreen); |
| command_updater_.UpdateCommandEnabled( |
| IDC_FOCUS_NEXT_PANE, main_not_fullscreen); |
| command_updater_.UpdateCommandEnabled( |
| IDC_FOCUS_PREVIOUS_PANE, main_not_fullscreen); |
| command_updater_.UpdateCommandEnabled( |
| IDC_FOCUS_BOOKMARKS, main_not_fullscreen); |
| command_updater_.UpdateCommandEnabled( |
| IDC_FOCUS_CHROMEOS_STATUS, main_not_fullscreen); |
| |
| // Show various bits of UI |
| command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui); |
| command_updater_.UpdateCommandEnabled(IDC_FEEDBACK, show_main_ui); |
| command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, |
| show_main_ui && profile_->GetOriginalProfile()->IsSyncAccessible()); |
| |
| // Settings page/subpages are forced to open in normal mode. We disable these |
| // commands when incognito is forced. |
| const bool options_enabled = show_main_ui && |
| IncognitoModePrefs::GetAvailability( |
| profile_->GetPrefs()) != IncognitoModePrefs::FORCED; |
| command_updater_.UpdateCommandEnabled(IDC_OPTIONS, options_enabled); |
| command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, options_enabled); |
| |
| command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui); |
| command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui); |
| command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui); |
| command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui); |
| command_updater_.UpdateCommandEnabled(IDC_SHOW_AVATAR_MENU, |
| show_main_ui && !profile()->IsOffTheRecord()); |
| #if defined (ENABLE_PROFILING) && !defined(NO_TCMALLOC) |
| command_updater_.UpdateCommandEnabled(IDC_PROFILING_ENABLED, show_main_ui); |
| #endif |
| |
| UpdateCommandsForBookmarkBar(); |
| } |
| |
| void Browser::UpdateCommandsForTabState() { |
| TabContents* current_tab = GetSelectedTabContents(); |
| TabContentsWrapper* current_tab_wrapper = GetSelectedTabContentsWrapper(); |
| if (!current_tab || !current_tab_wrapper) // May be NULL during tab restore. |
| return; |
| |
| // Navigation commands |
| NavigationController& nc = current_tab->controller(); |
| command_updater_.UpdateCommandEnabled(IDC_BACK, nc.CanGoBack()); |
| command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc.CanGoForward()); |
| command_updater_.UpdateCommandEnabled(IDC_RELOAD, |
| CanReloadContents(current_tab)); |
| command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, |
| CanReloadContents(current_tab)); |
| |
| // Window management commands |
| command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, |
| !is_app() && CanDuplicateContentsAt(active_index())); |
| |
| // Page-related commands |
| window_->SetStarredState( |
| current_tab_wrapper->bookmark_tab_helper()->is_starred()); |
| command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE, |
| current_tab->controller().CanViewSource()); |
| command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, |
| toolbar_model_.ShouldDisplayURL() && current_tab->GetURL().is_valid()); |
| if (is_devtools()) |
| command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, false); |
| |
| // Changing the encoding is not possible on Chrome-internal webpages. |
| bool is_chrome_internal = HasInternalURL(nc.GetActiveEntry()); |
| command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU, |
| !is_chrome_internal && SavePackage::IsSavableContents( |
| current_tab->contents_mime_type())); |
| |
| // Show various bits of UI |
| // TODO(pinkerton): Disable app-mode in the model until we implement it |
| // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148 |
| #if !defined(OS_MACOSX) |
| command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, |
| web_app::IsValidUrl(current_tab->GetURL())); |
| #endif |
| |
| UpdateCommandsForContentRestrictionState(); |
| UpdateCommandsForBookmarkEditing(); |
| } |
| |
| void Browser::UpdateCommandsForContentRestrictionState() { |
| int restrictions = GetContentRestrictionsForSelectedTab(); |
| |
| command_updater_.UpdateCommandEnabled( |
| IDC_COPY, !(restrictions & content::CONTENT_RESTRICTION_COPY)); |
| command_updater_.UpdateCommandEnabled( |
| IDC_CUT, !(restrictions & content::CONTENT_RESTRICTION_CUT)); |
| command_updater_.UpdateCommandEnabled( |
| IDC_PASTE, !(restrictions & content::CONTENT_RESTRICTION_PASTE)); |
| UpdateSaveAsState(restrictions); |
| UpdatePrintingState(restrictions); |
| } |
| |
| void Browser::UpdatePrintingState(int content_restrictions) { |
| bool print_enabled = true; |
| bool advanced_print_enabled = true; |
| if (g_browser_process->local_state()) { |
| print_enabled = |
| g_browser_process->local_state()->GetBoolean(prefs::kPrintingEnabled); |
| advanced_print_enabled = print_enabled; |
| } |
| if (print_enabled) { |
| // Do not print when a constrained window is showing. It's confusing. |
| TabContentsWrapper* wrapper = GetSelectedTabContentsWrapper(); |
| bool has_constrained_window = (wrapper && |
| wrapper->constrained_window_tab_helper()->constrained_window_count()); |
| if (has_constrained_window || |
| content_restrictions & content::CONTENT_RESTRICTION_PRINT) { |
| print_enabled = false; |
| advanced_print_enabled = false; |
| } |
| |
| // The exception is print preview, |
| // where advanced printing is always enabled. |
| printing::PrintPreviewTabController* controller = |
| printing::PrintPreviewTabController::GetInstance(); |
| if (controller && (controller->GetPrintPreviewForTab(wrapper) || |
| controller->is_creating_print_preview_tab())) { |
| advanced_print_enabled = true; |
| } |
| } |
| command_updater_.UpdateCommandEnabled(IDC_PRINT, print_enabled); |
| command_updater_.UpdateCommandEnabled(IDC_ADVANCED_PRINT, |
| advanced_print_enabled); |
| } |
| |
| void Browser::UpdateReloadStopState(bool is_loading, bool force) { |
| window_->UpdateReloadStopState(is_loading, force); |
| command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading); |
| } |
| |
| void Browser::UpdateCommandsForDevTools() { |
| bool dev_tools_enabled = |
| !profile_->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled); |
| command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS, |
| dev_tools_enabled); |
| command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE, |
| dev_tools_enabled); |
| command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT, |
| dev_tools_enabled); |
| } |
| |
| void Browser::UpdateCommandsForBookmarkEditing() { |
| bool enabled = |
| profile_->GetPrefs()->GetBoolean(prefs::kEditBookmarksEnabled) && |
| browser_defaults::bookmarks_enabled; |
| |
| command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_PAGE, |
| enabled && is_type_tabbed()); |
| command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS, |
| enabled && CanBookmarkAllTabs()); |
| } |
| |
| void Browser::UpdateCommandsForBookmarkBar() { |
| const bool show_main_ui = IsShowingMainUI(window_ && window_->IsFullscreen()); |
| command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, |
| browser_defaults::bookmarks_enabled && |
| !profile_->GetPrefs()->IsManagedPreference(prefs::kShowBookmarkBar) && |
| show_main_ui); |
| } |
| |
| void Browser::MarkHomePageAsChanged(PrefService* pref_service) { |
| pref_service->SetBoolean(prefs::kHomePageChanged, true); |
| pref_service->ScheduleSavePersistentPrefs(); |
| } |
| |
| void Browser::UpdateSaveAsState(int content_restrictions) { |
| bool enabled = !(content_restrictions & content::CONTENT_RESTRICTION_SAVE); |
| PrefService* state = g_browser_process->local_state(); |
| if (state) |
| enabled = enabled && state->GetBoolean(prefs::kAllowFileSelectionDialogs); |
| |
| command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE, enabled); |
| } |
| |
| void Browser::UpdateOpenFileState() { |
| bool enabled = true; |
| PrefService* local_state = g_browser_process->local_state(); |
| if (local_state) |
| enabled = local_state->GetBoolean(prefs::kAllowFileSelectionDialogs); |
| |
| command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, enabled); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, UI update coalescing and handling (private): |
| |
| void Browser::UpdateToolbar(bool should_restore_state) { |
| window_->UpdateToolbar(GetSelectedTabContentsWrapper(), should_restore_state); |
| } |
| |
| void Browser::ScheduleUIUpdate(const TabContents* source, |
| unsigned changed_flags) { |
| if (!source) |
| return; |
| |
| // Do some synchronous updates. |
| if (changed_flags & TabContents::INVALIDATE_URL && |
| source == GetSelectedTabContents()) { |
| // Only update the URL for the current tab. Note that we do not update |
| // the navigation commands since those would have already been updated |
| // synchronously by NavigationStateChanged. |
| UpdateToolbar(false); |
| changed_flags &= ~TabContents::INVALIDATE_URL; |
| } |
| if (changed_flags & TabContents::INVALIDATE_LOAD) { |
| // Update the loading state synchronously. This is so the throbber will |
| // immediately start/stop, which gives a more snappy feel. We want to do |
| // this for any tab so they start & stop quickly. |
| tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( |
| tab_handler_->GetTabStripModel()->GetIndexOfController( |
| &source->controller()), |
| TabStripModelObserver::LOADING_ONLY); |
| // The status bubble needs to be updated during INVALIDATE_LOAD too, but |
| // we do that asynchronously by not stripping INVALIDATE_LOAD from |
| // changed_flags. |
| } |
| |
| if (changed_flags & TabContents::INVALIDATE_TITLE && !source->IsLoading()) { |
| // To correctly calculate whether the title changed while not loading |
| // we need to process the update synchronously. This state only matters for |
| // the TabStripModel, so we notify the TabStripModel now and notify others |
| // asynchronously. |
| tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( |
| tab_handler_->GetTabStripModel()->GetIndexOfController( |
| &source->controller()), |
| TabStripModelObserver::TITLE_NOT_LOADING); |
| } |
| |
| // If the only updates were synchronously handled above, we're done. |
| if (changed_flags == 0) |
| return; |
| |
| // Save the dirty bits. |
| scheduled_updates_[source] |= changed_flags; |
| |
| if (!chrome_updater_factory_.HasWeakPtrs()) { |
| // No task currently scheduled, start another. |
| MessageLoop::current()->PostDelayedTask( |
| FROM_HERE, |
| base::Bind(&Browser::ProcessPendingUIUpdates, |
| chrome_updater_factory_.GetWeakPtr()), |
| kUIUpdateCoalescingTimeMS); |
| } |
| } |
| |
| void Browser::ProcessPendingUIUpdates() { |
| #ifndef NDEBUG |
| // Validate that all tabs we have pending updates for exist. This is scary |
| // because the pending list must be kept in sync with any detached or |
| // deleted tabs. |
| for (UpdateMap::const_iterator i = scheduled_updates_.begin(); |
| i != scheduled_updates_.end(); ++i) { |
| bool found = false; |
| for (int tab = 0; tab < tab_count(); tab++) { |
| if (GetTabContentsAt(tab) == i->first) { |
| found = true; |
| break; |
| } |
| } |
| DCHECK(found); |
| } |
| #endif |
| |
| chrome_updater_factory_.InvalidateWeakPtrs(); |
| |
| for (UpdateMap::const_iterator i = scheduled_updates_.begin(); |
| i != scheduled_updates_.end(); ++i) { |
| // Do not dereference |contents|, it may be out-of-date! |
| const TabContents* contents = i->first; |
| unsigned flags = i->second; |
| |
| if (contents == GetSelectedTabContents()) { |
| // Updates that only matter when the tab is selected go here. |
| |
| if (flags & TabContents::INVALIDATE_PAGE_ACTIONS) { |
| LocationBar* location_bar = window()->GetLocationBar(); |
| if (location_bar) |
| location_bar->UpdatePageActions(); |
| } |
| // Updating the URL happens synchronously in ScheduleUIUpdate. |
| if (flags & TabContents::INVALIDATE_LOAD && GetStatusBubble()) { |
| GetStatusBubble()->SetStatus( |
| GetSelectedTabContentsWrapper()->GetStatusText()); |
| } |
| |
| if (flags & (TabContents::INVALIDATE_TAB | |
| TabContents::INVALIDATE_TITLE)) { |
| // TODO(pinkerton): Disable app-mode in the model until we implement it |
| // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148 |
| #if !defined(OS_MACOSX) |
| command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, |
| web_app::IsValidUrl(contents->GetURL())); |
| #endif |
| window_->UpdateTitleBar(); |
| } |
| } |
| |
| // Updates that don't depend upon the selected state go here. |
| if (flags & (TabContents::INVALIDATE_TAB | TabContents::INVALIDATE_TITLE)) { |
| tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( |
| tab_handler_->GetTabStripModel()->GetWrapperIndex(contents), |
| TabStripModelObserver::ALL); |
| } |
| |
| // We don't need to process INVALIDATE_STATE, since that's not visible. |
| } |
| |
| scheduled_updates_.clear(); |
| } |
| |
| void Browser::RemoveScheduledUpdatesFor(TabContents* contents) { |
| if (!contents) |
| return; |
| |
| UpdateMap::iterator i = scheduled_updates_.find(contents); |
| if (i != scheduled_updates_.end()) |
| scheduled_updates_.erase(i); |
| } |
| |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, Getters for UI (private): |
| |
| StatusBubble* Browser::GetStatusBubble() { |
| #if !defined(OS_MACOSX) |
| // In kiosk mode, we want to always hide the status bubble. |
| if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) |
| return NULL; |
| #endif |
| return window_ ? window_->GetStatusBubble() : NULL; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, Session restore functions (private): |
| |
| void Browser::SyncHistoryWithTabs(int index) { |
| SessionService* session_service = |
| SessionServiceFactory::GetForProfileIfExisting(profile()); |
| if (session_service) { |
| for (int i = index; i < tab_count(); ++i) { |
| TabContentsWrapper* tab = GetTabContentsWrapperAt(i); |
| if (tab) { |
| session_service->SetTabIndexInWindow( |
| session_id(), tab->restore_tab_helper()->session_id(), i); |
| session_service->SetPinnedState( |
| session_id(), |
| tab->restore_tab_helper()->session_id(), |
| tab_handler_->GetTabStripModel()->IsTabPinned(i)); |
| } |
| } |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, OnBeforeUnload handling (private): |
| |
| void Browser::ProcessPendingTabs() { |
| if (!is_attempting_to_close_browser_) { |
| // Because we might invoke this after a delay it's possible for the value of |
| // is_attempting_to_close_browser_ to have changed since we scheduled the |
| // task. |
| return; |
| } |
| |
| if (HasCompletedUnloadProcessing()) { |
| // We've finished all the unload events and can proceed to close the |
| // browser. |
| OnWindowClosing(); |
| return; |
| } |
| |
| // Process beforeunload tabs first. When that queue is empty, process |
| // unload tabs. |
| if (!tabs_needing_before_unload_fired_.empty()) { |
| TabContents* tab = *(tabs_needing_before_unload_fired_.begin()); |
| // Null check render_view_host here as this gets called on a PostTask and |
| // the tab's render_view_host may have been nulled out. |
| if (tab->render_view_host()) { |
| tab->render_view_host()->FirePageBeforeUnload(false); |
| } else { |
| ClearUnloadState(tab, true); |
| } |
| } else if (!tabs_needing_unload_fired_.empty()) { |
| // We've finished firing all beforeunload events and can proceed with unload |
| // events. |
| // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting |
| // somewhere around here so that we have accurate measurements of shutdown |
| // time. |
| // TODO(ojan): We can probably fire all the unload events in parallel and |
| // get a perf benefit from that in the cases where the tab hangs in it's |
| // unload handler or takes a long time to page in. |
| TabContents* tab = *(tabs_needing_unload_fired_.begin()); |
| // Null check render_view_host here as this gets called on a PostTask and |
| // the tab's render_view_host may have been nulled out. |
| if (tab->render_view_host()) { |
| tab->render_view_host()->ClosePage(); |
| } else { |
| ClearUnloadState(tab, true); |
| } |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| bool Browser::HasCompletedUnloadProcessing() const { |
| return is_attempting_to_close_browser_ && |
| tabs_needing_before_unload_fired_.empty() && |
| tabs_needing_unload_fired_.empty(); |
| } |
| |
| void Browser::CancelWindowClose() { |
| // Closing of window can be canceled from: |
| // - canceling beforeunload |
| // - disallowing closing from IsClosingPermitted. |
| DCHECK(is_attempting_to_close_browser_); |
| tabs_needing_before_unload_fired_.clear(); |
| tabs_needing_unload_fired_.clear(); |
| is_attempting_to_close_browser_ = false; |
| |
| // Inform TabCloseableStateWatcher that closing of window has been canceled. |
| TabCloseableStateWatcher* watcher = |
| g_browser_process->tab_closeable_state_watcher(); |
| if (watcher) |
| watcher->OnWindowCloseCanceled(this); |
| } |
| |
| bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) { |
| DCHECK(is_attempting_to_close_browser_); |
| |
| UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab); |
| if (iter != set->end()) { |
| set->erase(iter); |
| return true; |
| } |
| return false; |
| } |
| |
| void Browser::ClearUnloadState(TabContents* tab, bool process_now) { |
| // Closing of browser could be canceled (via IsClosingPermitted) between the |
| // time when request was initiated and when this method is called, so check |
| // for is_attempting_to_close_browser_ flag before proceeding. |
| if (is_attempting_to_close_browser_) { |
| RemoveFromSet(&tabs_needing_before_unload_fired_, tab); |
| RemoveFromSet(&tabs_needing_unload_fired_, tab); |
| if (process_now) { |
| ProcessPendingTabs(); |
| } else { |
| MessageLoop::current()->PostTask( |
| FROM_HERE, |
| base::Bind(&Browser::ProcessPendingTabs, weak_factory_.GetWeakPtr())); |
| } |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, In-progress download termination handling (private): |
| |
| bool Browser::CanCloseWithInProgressDownloads() { |
| // If we've prompted, we need to hear from the user before we |
| // can close. |
| if (cancel_download_confirmation_state_ != NOT_PROMPTED) |
| return cancel_download_confirmation_state_ != WAITING_FOR_RESPONSE; |
| |
| int num_downloads_blocking; |
| if (DOWNLOAD_CLOSE_OK == |
| OkToCloseWithInProgressDownloads(&num_downloads_blocking)) |
| return true; |
| |
| // Closing this window will kill some downloads; prompt to make sure |
| // that's ok. |
| cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE; |
| window_->ConfirmBrowserCloseWithPendingDownloads(); |
| |
| // Return false so the browser does not close. We'll close if the user |
| // confirms in the dialog. |
| return false; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Browser, Assorted utility functions (private): |
| |
| // static |
| Browser* Browser::GetTabbedBrowser(Profile* profile, bool match_incognito) { |
| return BrowserList::FindTabbedBrowser(profile, match_incognito); |
| } |
| |
| // static |
| Browser* Browser::GetOrCreateTabbedBrowser(Profile* profile) { |
| Browser* browser = GetTabbedBrowser(profile, false); |
| if (!browser) |
| browser = Browser::Create(profile); |
| return browser; |
| } |
| |
| void Browser::SetAsDelegate(TabContentsWrapper* tab, Browser* delegate) { |
| // TabContents... |
| tab->tab_contents()->set_delegate(delegate); |
| tab->set_delegate(delegate); |
| |
| // ...and all the helpers. |
| tab->blocked_content_tab_helper()->set_delegate(delegate); |
| tab->bookmark_tab_helper()->set_delegate(delegate); |
| tab->constrained_window_tab_helper()->set_delegate(delegate); |
| tab->extension_tab_helper()->set_delegate(delegate); |
| tab->search_engine_tab_helper()->set_delegate(delegate); |
| } |
| |
| void Browser::FindInPage(bool find_next, bool forward_direction) { |
| ShowFindBar(); |
| if (find_next) { |
| string16 find_text; |
| #if defined(OS_MACOSX) |
| // We always want to search for the contents of the find pasteboard on OS X. |
| find_text = GetFindPboardText(); |
| #endif |
| GetSelectedTabContentsWrapper()-> |
| find_tab_helper()->StartFinding(find_text, |
| forward_direction, |
| false); // Not case sensitive. |
| } |
| } |
| |
| void Browser::CloseFrame() { |
| window_->Close(); |
| } |
| |
| void Browser::TabDetachedAtImpl(TabContentsWrapper* contents, int index, |
| DetachType type) { |
| if (type == DETACH_TYPE_DETACH) { |
| // Save the current location bar state, but only if the tab being detached |
| // is the selected tab. Because saving state can conditionally revert the |
| // location bar, saving the current tab's location bar state to a |
| // non-selected tab can corrupt both tabs. |
| if (contents == GetSelectedTabContentsWrapper()) { |
| LocationBar* location_bar = window()->GetLocationBar(); |
| if (location_bar) |
| location_bar->SaveStateToContents(contents->tab_contents()); |
| } |
| |
| if (!tab_handler_->GetTabStripModel()->closing_all()) |
| SyncHistoryWithTabs(0); |
| } |
| |
| SetAsDelegate(contents, NULL); |
| RemoveScheduledUpdatesFor(contents->tab_contents()); |
| |
| if (find_bar_controller_.get() && |
| index == tab_handler_->GetTabStripModel()->active_index()) { |
| find_bar_controller_->ChangeTabContents(NULL); |
| } |
| |
| if (is_attempting_to_close_browser_) { |
| // If this is the last tab with unload handlers, then ProcessPendingTabs |
| // would call back into the TabStripModel (which is invoking this method on |
| // us). Avoid that by passing in false so that the call to |
| // ProcessPendingTabs is delayed. |
| ClearUnloadState(contents->tab_contents(), false); |
| } |
| |
| registrar_.Remove(this, content::NOTIFICATION_INTERSTITIAL_ATTACHED, |
| content::Source<TabContents>(contents->tab_contents())); |
| registrar_.Remove(this, content::NOTIFICATION_TAB_CONTENTS_DISCONNECTED, |
| content::Source<TabContents>(contents->tab_contents())); |
| } |
| |
| // static |
| void Browser::RegisterAppPrefs(const std::string& app_name, Profile* profile) { |
| // We need to register the window position pref. |
| std::string window_pref(prefs::kBrowserWindowPlacement); |
| window_pref.append("_"); |
| window_pref.append(app_name); |
| PrefService* prefs = profile->GetPrefs(); |
| if (!prefs->FindPreference(window_pref.c_str())) { |
| prefs->RegisterDictionaryPref(window_pref.c_str(), |
| PrefService::UNSYNCABLE_PREF); |
| } |
| } |
| |
| void Browser::TabRestoreServiceChanged(TabRestoreService* service) { |
| command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, |
| !service->entries().empty()); |
| } |
| |
| void Browser::TabRestoreServiceDestroyed(TabRestoreService* service) { |
| if (!tab_restore_service_) |
| return; |
| |
| DCHECK_EQ(tab_restore_service_, service); |
| tab_restore_service_->RemoveObserver(this); |
| tab_restore_service_ = NULL; |
| } |
| |
| // Centralized method for creating a TabContents, configuring and installing |
| // all its supporting objects and observers. |
| TabContentsWrapper* Browser::TabContentsFactory( |
| Profile* profile, |
| SiteInstance* site_instance, |
| int routing_id, |
| const TabContents* base_tab_contents, |
| SessionStorageNamespace* session_storage_namespace) { |
| TabContents* new_contents = new TabContents(profile, site_instance, |
| routing_id, base_tab_contents, |
| session_storage_namespace); |
| TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents); |
| return wrapper; |
| } |
| |
| bool Browser::OpenInstant(WindowOpenDisposition disposition) { |
| if (!instant() || !instant()->PrepareForCommit() || |
| disposition == NEW_BACKGROUND_TAB) { |
| // NEW_BACKGROUND_TAB results in leaving the omnibox open, so we don't |
| // attempt to use the instant preview. |
| return false; |
| } |
| |
| if (disposition == CURRENT_TAB) { |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_INSTANT_COMMITTED, |
| content::Source<TabContentsWrapper>(instant()->CommitCurrentPreview( |
| INSTANT_COMMIT_PRESSED_ENTER)), |
| content::NotificationService::NoDetails()); |
| return true; |
| } |
| if (disposition == NEW_FOREGROUND_TAB) { |
| TabContentsWrapper* preview_contents = instant()->ReleasePreviewContents( |
| INSTANT_COMMIT_PRESSED_ENTER); |
| // HideInstant is invoked after release so that InstantController is not |
| // active when HideInstant asks it for its state. |
| HideInstant(); |
| preview_contents->controller().PruneAllButActive(); |
| tab_handler_->GetTabStripModel()->AddTabContents( |
| preview_contents, |
| -1, |
| instant()->last_transition_type(), |
| TabStripModel::ADD_ACTIVE); |
| instant()->CompleteRelease(preview_contents); |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_INSTANT_COMMITTED, |
| content::Source<TabContentsWrapper>(preview_contents), |
| content::NotificationService::NoDetails()); |
| return true; |
| } |
| // The omnibox currently doesn't use other dispositions, so we don't attempt |
| // to handle them. If you hit this NOTREACHED file a bug and I'll (sky) add |
| // support for the new disposition. |
| NOTREACHED(); |
| return false; |
| } |
| |
| void Browser::CreateInstantIfNecessary() { |
| if (is_type_tabbed() && InstantController::IsEnabled(profile()) && |
| !profile()->IsOffTheRecord()) { |
| instant_.reset(new InstantController(profile_, this)); |
| instant_unload_handler_.reset(new InstantUnloadHandler(this)); |
| } |
| } |
| |
| void Browser::ViewSource(TabContentsWrapper* contents) { |
| DCHECK(contents); |
| |
| NavigationEntry* active_entry = contents->controller().GetActiveEntry(); |
| if (!active_entry) |
| return; |
| |
| ViewSource(contents, active_entry->url(), active_entry->content_state()); |
| } |
| |
| void Browser::ViewSource(TabContentsWrapper* contents, |
| const GURL& url, |
| const std::string& content_state) { |
| UserMetrics::RecordAction(UserMetricsAction("ViewSource")); |
| DCHECK(contents); |
| |
| TabContentsWrapper* view_source_contents = contents->Clone(); |
| view_source_contents->controller().PruneAllButActive(); |
| NavigationEntry* active_entry = |
| view_source_contents->controller().GetActiveEntry(); |
| if (!active_entry) |
| return; |
| |
| GURL view_source_url = GURL(chrome::kViewSourceScheme + std::string(":") + |
| url.spec()); |
| active_entry->set_virtual_url(view_source_url); |
| |
| // Do not restore scroller position. |
| active_entry->set_content_state( |
| webkit_glue::RemoveScrollOffsetFromHistoryState(content_state)); |
| |
| // Do not restore title, derive it from the url. |
| active_entry->set_title(string16()); |
| |
| // Now show view-source entry. |
| if (CanSupportWindowFeature(FEATURE_TABSTRIP)) { |
| // If this is a tabbed browser, just create a duplicate tab inside the same |
| // window next to the tab being duplicated. |
| int index = tab_handler_->GetTabStripModel()-> |
| GetIndexOfTabContents(contents); |
| int add_types = TabStripModel::ADD_ACTIVE | |
| TabStripModel::ADD_INHERIT_GROUP; |
| tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1, |
| view_source_contents, |
| add_types); |
| } else { |
| Browser* browser = Browser::CreateForType(TYPE_TABBED, profile_); |
| |
| // Preserve the size of the original window. The new window has already |
| // been given an offset by the OS, so we shouldn't copy the old bounds. |
| BrowserWindow* new_window = browser->window(); |
| new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(), |
| window()->GetRestoredBounds().size())); |
| |
| // We need to show the browser now. Otherwise ContainerWin assumes the |
| // TabContents is invisible and won't size it. |
| browser->window()->Show(); |
| |
| // The page transition below is only for the purpose of inserting the tab. |
| browser->AddTab(view_source_contents, content::PAGE_TRANSITION_LINK); |
| } |
| |
| SessionService* session_service = |
| SessionServiceFactory::GetForProfileIfExisting(profile_); |
| if (session_service) |
| session_service->TabRestored(view_source_contents, false); |
| } |
| |
| int Browser::GetContentRestrictionsForSelectedTab() { |
| int content_restrictions = 0; |
| TabContents* current_tab = GetSelectedTabContents(); |
| if (current_tab) { |
| content_restrictions = current_tab->content_restrictions(); |
| NavigationEntry* active_entry = current_tab->controller().GetActiveEntry(); |
| // See comment in UpdateCommandsForTabState about why we call url(). |
| if (!SavePackage::IsSavableURL(active_entry ? active_entry->url() : GURL())) |
| content_restrictions |= content::CONTENT_RESTRICTION_SAVE; |
| } |
| return content_restrictions; |
| } |
| |
| void Browser::UpdateBookmarkBarState(BookmarkBarStateChangeReason reason) { |
| BookmarkBar::State state; |
| // The bookmark bar is hidden in fullscreen mode, unless on the new tab page. |
| if (browser_defaults::bookmarks_enabled && |
| profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) && |
| (!window_ || !window_->IsFullscreen())) { |
| state = BookmarkBar::SHOW; |
| } else { |
| TabContentsWrapper* tab = GetSelectedTabContentsWrapper(); |
| if (tab && tab->bookmark_tab_helper()->ShouldShowBookmarkBar()) |
| state = BookmarkBar::DETACHED; |
| else |
| state = BookmarkBar::HIDDEN; |
| } |
| if (state == bookmark_bar_state_) |
| return; |
| |
| bookmark_bar_state_ = state; |
| |
| if (!window_) |
| return; // This is called from the constructor when window_ is NULL. |
| |
| if (reason == BOOKMARK_BAR_STATE_CHANGE_TAB_SWITCH) { |
| // Don't notify BrowserWindow on a tab switch as at the time this is invoked |
| // BrowserWindow hasn't yet switched tabs. The BrowserWindow implementations |
| // end up querying state once they process the tab switch. |
| return; |
| } |
| |
| BookmarkBar::AnimateChangeType animate_type = |
| (reason == BOOKMARK_BAR_STATE_CHANGE_PREF_CHANGE) ? |
| BookmarkBar::ANIMATE_STATE_CHANGE : |
| BookmarkBar::DONT_ANIMATE_STATE_CHANGE; |
| window_->BookmarkBarStateChanged(animate_type); |
| } |
| |
| void Browser::ShowSyncSetup() { |
| ProfileSyncService* service = |
| profile()->GetOriginalProfile()->GetProfileSyncService(); |
| if (service->HasSyncSetupCompleted()) |
| ShowOptionsTab(chrome::kPersonalOptionsSubPage); |
| else |
| service->ShowLoginDialog(); |
| } |
| |
| void Browser::ToggleSpeechInput() { |
| GetSelectedTabContentsWrapper()->render_view_host()->ToggleSpeechInput(); |
| } |
| |
| void Browser::OnWindowDidShow() { |
| if (window_has_shown_) |
| return; |
| window_has_shown_ = true; |
| |
| // Nothing to do for non-tabbed windows. |
| if (!is_type_tabbed()) |
| return; |
| |
| // Suppress the first run bubble if we're showing the sync promo. |
| TabContents* contents = GetSelectedTabContents(); |
| bool is_showing_promo = contents && |
| contents->GetURL().SchemeIs(chrome::kChromeUIScheme) && |
| contents->GetURL().host() == chrome::kChromeUISyncPromoHost; |
| |
| // Show the First Run information bubble if we've been told to. |
| PrefService* local_state = g_browser_process->local_state(); |
| if (!is_showing_promo && local_state && |
| local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) { |
| FirstRun::BubbleType bubble_type = FirstRun::MINIMAL_BUBBLE; |
| if (local_state-> |
| FindPreference(prefs::kShouldUseOEMFirstRunBubble) && |
| local_state->GetBoolean(prefs::kShouldUseOEMFirstRunBubble)) { |
| bubble_type = FirstRun::OEM_BUBBLE; |
| } else if (local_state-> |
| FindPreference(prefs::kShouldUseMinimalFirstRunBubble) && |
| local_state->GetBoolean(prefs::kShouldUseMinimalFirstRunBubble)) { |
| bubble_type = FirstRun::MINIMAL_BUBBLE; |
| } |
| // Reset the preference so we don't show the bubble for subsequent |
| // windows. |
| local_state->SetBoolean(prefs::kShouldShowFirstRunBubble, false); |
| window_->GetLocationBar()->ShowFirstRunBubble(bubble_type); |
| } else { |
| GlobalErrorService* service = |
| GlobalErrorServiceFactory::GetForProfile(profile()); |
| GlobalError* error = service->GetFirstGlobalErrorWithBubbleView(); |
| if (error) { |
| error->ShowBubbleView(this); |
| } |
| } |
| } |