blob: 49e694b494fc7e3e4ee987b1d85c43b22e4f6f82 [file] [log] [blame]
// 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 <shellapi.h>
#include <windows.h>
#endif // OS_WIN
#include <algorithm>
#include <string>
#include "app/l10n_util.h"
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "gfx/point.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/browser_url_handler.h"
#include "chrome/browser/character_encoding.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_toggle_action.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/dom_ui/bug_report_ui.h"
#include "chrome/browser/dom_ui/filebrowse_ui.h"
#include "chrome/browser/dom_ui/options/content_settings_handler.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_shelf.h"
#include "chrome/browser/download/download_started_animation.h"
#include "chrome/browser/extensions/crashed_extension_infobar.h"
#include "chrome/browser/extensions/crx_installer.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_tabs_module.h"
#include "chrome/browser/extensions/extension_service.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/host_zoom_map.h"
#include "chrome/browser/instant/instant_controller.h"
#include "chrome/browser/instant/instant_unload_handler.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/browser_url_util.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/sessions/tab_restore_service.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/interstitial_page.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/find_bar/find_bar.h"
#include "chrome/browser/ui/find_bar/find_bar_controller.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/options/options_window.h"
#include "chrome/browser/ui/status_bubble.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/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_switches.h"
#include "chrome/common/content_restriction.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/web_apps.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "net/base/cookie_monster.h"
#include "net/base/net_util.h"
#include "net/base/registry_controlled_domain.h"
#include "net/base/static_cookie_policy.h"
#include "net/url_request/url_request_context.h"
#include "ui/base/animation/animation.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/window_open_disposition.h"
#if defined(OS_WIN)
#include "app/win/shell.h"
#include "chrome/browser/autofill/autofill_ie_toolbar_import_win.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/download/save_package.h"
#include "chrome/browser/ssl/ssl_error_info.h"
#include "chrome/browser/shell_integration.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"
#endif // OS_WIN
#if defined(OS_MACOSX)
#include "chrome/browser/ui/cocoa/find_pasteboard.h"
#endif
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/boot_times_loader.h"
#include "chrome/browser/chromeos/options/language_config_view.h"
#endif
using base::TimeDelta;
///////////////////////////////////////////////////////////////////////////////
namespace {
// The URL to be loaded to display Help.
#if defined(OS_CHROMEOS)
const char kHelpContentUrl[] =
"chrome-extension://oonnajkebngbfpmcpekfdeofeannbapp/main.html";
const char kHelpContentOnlineUrl[] =
"http://www.google.com/support/chromeos/";
#else
const char kHelpContentUrl[] =
"http://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)
"http://www.google.com/support/chromeos/bin/answer.py?answer=142893";
#else
"http://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[] =
"http://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[] = "#";
#if defined(OS_CHROMEOS)
// If a popup window is bigger than this fraction of the screen on chrome os,
// turn it into a tab
const float kPopupMaxWidthFactor = 0.5;
const float kPopupMaxHeightFactor = 0.6;
#endif
} // namespace
extern bool g_log_bug53991;
///////////////////////////////////////////////////////////////////////////////
// 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),
maximized_state_(MAXIMIZED_STATE_DEFAULT),
method_factory_(this),
block_command_execution_(false),
last_blocked_command_id_(-1),
last_blocked_command_disposition_(CURRENT_TAB),
pending_web_app_action_(NONE) {
registrar_.Add(this, NotificationType::SSL_VISIBLE_STATE_CHANGED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_LOADED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::PROFILE_ERROR,
NotificationService::AllSources());
// Need to know when to alert the user of theme install delay.
registrar_.Add(this, NotificationType::EXTENSION_READY_FOR_INSTALL,
NotificationService::AllSources());
PrefService* local_state = g_browser_process->local_state();
if (local_state)
printing_enabled_.Init(prefs::kPrintingEnabled, local_state, this);
dev_tools_disabled_.Init(prefs::kDevToolsDisabled,
profile_->GetPrefs(), this);
InitCommandState();
BrowserList::AddBrowser(this);
encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector,
profile_->GetPrefs(), NULL);
use_vertical_tabs_.Init(prefs::kUseVerticalTabs, profile_->GetPrefs(), this);
instant_enabled_.Init(prefs::kInstantEnabled, profile_->GetPrefs(), this);
if (!TabMenuModel::AreVerticalTabsEnabled()) {
// If vertical tabs aren't enabled, explicitly turn them off. Otherwise we
// might show vertical tabs but not show an option to turn them off.
use_vertical_tabs_.SetValue(false);
}
UpdateTabStripModelInsertionPolicy();
tab_restore_service_ = profile->GetTabRestoreService();
if (tab_restore_service_) {
tab_restore_service_->AddObserver(this);
TabRestoreServiceChanged(tab_restore_service_);
}
if (profile_->GetProfileSyncService())
profile_->GetProfileSyncService()->AddObserver(this);
CreateInstantIfNecessary();
}
Browser::~Browser() {
VLOG_IF(1, g_log_bug53991) << "~Browser: " << profile_->IsOffTheRecord()
<< "; stillActive="
<< BrowserList::IsOffTheRecordSessionActive();
if (profile_->GetProfileSyncService())
profile_->GetProfileSyncService()->RemoveObserver(this);
BrowserList::RemoveBrowser(this);
#if defined(OS_WIN) || defined(OS_LINUX)
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.
profile_->ResetTabRestoreService();
}
#endif
SessionService* session_service = profile_->GetSessionService();
if (session_service)
session_service->WindowClosed(session_id_);
TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
if (tab_restore_service)
tab_restore_service->BrowserClosed(this);
if (profile_->IsOffTheRecord() &&
!BrowserList::IsOffTheRecordSessionActive()) {
// An off-the-record 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_);
}
// static
Browser* Browser::Create(Profile* profile) {
Browser* browser = new Browser(TYPE_NORMAL, profile);
browser->CreateBrowserWindow();
return browser;
}
// static
Browser* Browser::CreateForPopup(Type type,
Profile* profile,
TabContents* new_contents,
const gfx::Rect& initial_bounds) {
DCHECK(type & TYPE_POPUP);
Browser* browser = new Browser(type, profile);
browser->set_override_bounds(initial_bounds);
browser->CreateBrowserWindow();
TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents);
browser->tabstrip_model()->AppendTabContents(wrapper, true);
return browser;
}
// static
Browser* Browser::CreateForType(Type type, Profile* profile) {
Browser* browser = new Browser(type, profile);
browser->CreateBrowserWindow();
return browser;
}
// static
Browser* Browser::CreateForApp(const std::string& app_name,
const gfx::Size& window_size,
Profile* profile,
bool is_panel) {
Browser::Type type = TYPE_APP;
if (is_panel) {
// TYPE_APP_PANEL is the logical choice. However, the panel UI
// is not fully implemented. See crbug/55943.
type = TYPE_APP_POPUP;
}
Browser* browser = new Browser(type, profile);
browser->app_name_ = app_name;
if (!window_size.IsEmpty()) {
gfx::Rect initial_pos(window_size);
browser->set_override_bounds(initial_pos);
}
browser->CreateBrowserWindow();
return browser;
}
// static
Browser* Browser::CreateForDevTools(Profile* profile) {
Browser* browser = new Browser(TYPE_DEVTOOLS, profile);
browser->app_name_ = DevToolsWindow::kDevToolsApp;
browser->CreateBrowserWindow();
return browser;
}
void Browser::CreateBrowserWindow() {
DCHECK(!window_);
window_ = BrowserWindow::CreateBrowserWindow(this);
#if defined(OS_WIN)
{
// 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.
app::win::SetAppIdForWindow(
type_ & TYPE_APP ?
ShellIntegration::GetAppId(UTF8ToWide(app_name_), profile_->GetPath()) :
ShellIntegration::GetChromiumAppId(profile_->GetPath()),
window()->GetNativeHandle());
}
#endif
NotificationService::current()->Notify(
NotificationType::BROWSER_WINDOW_READY,
Source<Browser>(this),
NotificationService::NoDetails());
// Show the First Run information bubble if we've been told to.
PrefService* local_state = g_browser_process->local_state();
if (!local_state)
return;
if (local_state->FindPreference(prefs::kShouldShowFirstRunBubble) &&
local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) {
FirstRun::BubbleType bubble_type = FirstRun::LARGE_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->ClearPref(prefs::kShouldShowFirstRunBubble);
window_->GetLocationBar()->ShowFirstRunBubble(bubble_type);
}
if (local_state->FindPreference(
prefs::kAutoFillPersonalDataManagerFirstRun) &&
local_state->GetBoolean(prefs::kAutoFillPersonalDataManagerFirstRun)) {
// Notify PDM that this is a first run.
#if defined(OS_WIN)
ImportAutofillDataWin(profile_->GetPersonalDataManager());
#endif // defined(OS_WIN)
// Reset the preference so we don't call it again for subsequent windows.
local_state->ClearPref(prefs::kAutoFillPersonalDataManagerFirstRun);
}
}
///////////////////////////////////////////////////////////////////////////////
// Getters & Setters
const std::vector<std::wstring>& Browser::user_data_dir_profiles() const {
return g_browser_process->user_data_dir_profiles();
}
void Browser::set_user_data_dir_profiles(
const std::vector<std::wstring>& profiles) {
g_browser_process->user_data_dir_profiles() = profiles;
}
FindBarController* Browser::GetFindBarController() {
if (!find_bar_controller_.get()) {
FindBar* find_bar = BrowserWindow::CreateFindBar(this);
find_bar_controller_.reset(new FindBarController(find_bar));
find_bar->SetFindBarController(find_bar_controller_.get());
find_bar_controller_->ChangeTabContents(GetSelectedTabContents());
find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true);
}
return find_bar_controller_.get();
}
bool Browser::HasFindBarController() const {
return find_bar_controller_.get() != NULL;
}
///////////////////////////////////////////////////////////////////////////////
// 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 = profile->GetTabRestoreService();
if (service)
service->RestoreMostRecentEntry(NULL);
}
// static
void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
Browser* browser = GetOrCreateTabbedBrowser(
profile->GetOffTheRecordProfile());
browser->AddSelectedTabWithURL(url, PageTransition::LINK);
browser->window()->Show();
}
// static
// TODO(erikkay): There are multiple reasons why this could fail. Should
// this function return an error reason as well so that callers can show
// reasonable errors?
TabContents* Browser::OpenApplication(Profile* profile,
const std::string& app_id,
TabContents* existing_tab) {
ExtensionService* extensions_service = profile->GetExtensionService();
// If the extension with |app_id| could't be found, most likely because it
// was uninstalled.
const Extension* extension =
extensions_service->GetExtensionById(app_id, false);
if (!extension)
return NULL;
return OpenApplication(profile, extension, extension->launch_container(),
existing_tab);
}
// static
TabContents* Browser::OpenApplication(
Profile* profile,
const Extension* extension,
extension_misc::LaunchContainer container,
TabContents* existing_tab) {
TabContents* tab = NULL;
UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchContainer", container, 100);
switch (container) {
case extension_misc::LAUNCH_WINDOW:
case extension_misc::LAUNCH_PANEL:
tab = Browser::OpenApplicationWindow(profile, extension, container,
GURL(), NULL);
break;
case extension_misc::LAUNCH_TAB: {
tab = Browser::OpenApplicationTab(profile, extension, existing_tab);
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) {
GURL url;
if (!url_input.is_empty()) {
if (extension)
DCHECK(extension->web_extent().ContainsURL(url_input));
url = url_input;
} else {
DCHECK(extension);
url = extension->GetFullLaunchURL();
}
// TODO(erikkay) this can't be correct for extensions
std::string app_name = web_app::GenerateApplicationNameFromURL(url);
RegisterAppPrefs(app_name);
bool as_panel = extension && (container == extension_misc::LAUNCH_PANEL);
gfx::Size window_size;
if (extension)
window_size.SetSize(extension->launch_width(),
extension->launch_height());
Browser* browser = Browser::CreateForApp(app_name, window_size, profile,
as_panel);
if (app_browser)
*app_browser = browser;
TabContentsWrapper* wrapper =
browser->AddSelectedTabWithURL(url, PageTransition::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,
TabContents* existing_tab) {
Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
TabContents* contents = NULL;
if (!browser || browser->type() != Browser::TYPE_NORMAL)
return contents;
// Check the prefs for overridden mode.
ExtensionService* extensions_service = profile->GetExtensionService();
DCHECK(extensions_service);
ExtensionPrefs::LaunchType launch_type =
extensions_service->extension_prefs()->GetLaunchType(
extension->id(), ExtensionPrefs::LAUNCH_REGULAR);
UMA_HISTOGRAM_ENUMERATION("Extensions.AppTabLaunchType", launch_type, 100);
int add_type = TabStripModel::ADD_SELECTED;
if (launch_type == ExtensionPrefs::LAUNCH_PINNED)
add_type |= TabStripModel::ADD_PINNED;
// TODO(erikkay): START_PAGE doesn't seem like the right transition in all
// cases.
browser::NavigateParams params(browser, extension->GetFullLaunchURL(),
PageTransition::START_PAGE);
params.tabstrip_add_types = add_type;
// Launch the application in the existing TabContents, if it was supplied.
if (existing_tab) {
TabStripModel* model = browser->tabstrip_model();
int tab_index = model->GetWrapperIndex(existing_tab);
existing_tab->OpenURL(extension->GetFullLaunchURL(), existing_tab->GetURL(),
CURRENT_TAB, PageTransition::LINK);
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_SELECTED)
model->SelectTabContentsAt(tab_index, true);
contents = existing_tab;
} else {
params.disposition = NEW_FOREGROUND_TAB;
browser::Navigate(&params);
contents = params.target_contents->tab_contents();
}
if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN)
browser->window()->SetFullscreen(true);
return contents;
}
// static
void Browser::OpenBookmarkManagerWindow(Profile* profile) {
Browser* browser = Browser::Create(profile);
browser->ShowBookmarkManagerTab();
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->OpenHelpTab();
browser->window()->Show();
}
// static
void Browser::OpenOptionsWindow(Profile* profile) {
Browser* browser = Browser::Create(profile);
browser->ShowOptionsTab(chrome::kDefaultOptionsSubPage);
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 {
// Only save the window placement of popups if they are restored.
return (type() & TYPE_POPUP) == 0 || browser_defaults::kRestorePopups;
}
void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) {
// 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.
if (profile()->HasSessionService()) {
SessionService* session_service = profile()->GetSessionService();
if (session_service)
session_service->SetWindowBounds(session_id_, bounds, maximized);
}
}
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_;
bool maximized;
WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL,
&restored_bounds, &maximized);
return restored_bounds;
}
// TODO(beng): obtain maximized state some other way so we don't need to go
// through all this hassle.
bool Browser::GetSavedMaximizedState() const {
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStartMaximized))
return true;
if (maximized_state_ == MAXIMIZED_STATE_MAXIMIZED)
return true;
if (maximized_state_ == MAXIMIZED_STATE_UNMAXIMIZED)
return false;
// An explicit maximized state was not set. Query the window sizer.
gfx::Rect restored_bounds;
bool maximized = false;
WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL,
&restored_bounds, &maximized);
return maximized;
}
SkBitmap Browser::GetCurrentPageIcon() const {
TabContents* contents = GetSelectedTabContents();
// |contents| can be NULL since GetCurrentPageIcon() is called by the window
// during the window's creation (before tabs have been added).
return contents ? contents->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 = TabContents::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;
#elif defined(OS_WIN) || defined(OS_LINUX)
int string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT;
// Don't append the app name to window titles on app frames and app popups
if (type_ & TYPE_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 HasSessionService here, we want to force creation of the
// session service so that user can restore what was open.
SessionService* session_service = profile()->GetSessionService();
if (session_service)
session_service->WindowClosing(session_id());
TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
if (tab_restore_service)
tab_restore_service->BrowserClosing(this);
// TODO(sky): convert session/tab restore to use notification.
NotificationService::current()->Notify(
NotificationType::BROWSER_CLOSING,
Source<Browser>(this),
Details<bool>(&exiting));
CloseAllTabs();
}
////////////////////////////////////////////////////////////////////////////////
// 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, TabStripModel pass-thrus:
int Browser::tab_count() const {
return tab_handler_->GetTabStripModel()->count();
}
int Browser::selected_index() const {
return tab_handler_->GetTabStripModel()->selected_index();
}
int Browser::GetIndexOfController(
const NavigationController* controller) const {
return tab_handler_->GetTabStripModel()->GetIndexOfController(controller);
}
TabContentsWrapper* Browser::GetSelectedTabContentsWrapper() const {
return tabstrip_model()->GetSelectedTabContents();
}
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::SelectTabContentsAt(int index, bool user_gesture) {
tab_handler_->GetTabStripModel()->SelectTabContentsAt(index, user_gesture);
}
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,
PageTransition::Type transition) {
browser::NavigateParams params(this, url, transition);
params.disposition = NEW_FOREGROUND_TAB;
browser::Navigate(&params);
return params.target_contents;
}
TabContents* Browser::AddTab(TabContentsWrapper* tab_contents,
PageTransition::Type type) {
tab_handler_->GetTabStripModel()->AddTabContents(
tab_contents, -1, type, TabStripModel::ADD_SELECTED);
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);
}
void Browser::BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate,
gfx::NativeWindow parent_window) {
ShowHtmlDialog(delegate, parent_window);
}
void Browser::BrowserRenderWidgetShowing() {
RenderWidgetShowing();
}
void Browser::ToolbarSizeChanged(bool is_animating) {
ToolbarSizeChanged(NULL, 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) {
TabContentsWrapper* wrapper = TabContentsFactory(profile(), NULL,
MSG_ROUTING_NONE,
GetSelectedTabContents(),
session_storage_namespace);
TabContents* new_tab = wrapper->tab_contents();
new_tab->SetExtensionAppById(extension_app_id);
new_tab->controller().RestoreFromState(navigations, selected_navigation,
from_last_session);
bool really_pin =
(pin && tab_index == tabstrip_model()->IndexOfFirstNonMiniTab());
tab_handler_->GetTabStripModel()->InsertTabContentsAt(
tab_index, wrapper,
select ? TabStripModel::ADD_SELECTED : TabStripModel::ADD_NONE);
if (really_pin)
tab_handler_->GetTabStripModel()->SetTabPinned(tab_index, true);
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();
}
if (profile_->HasSessionService()) {
SessionService* session_service = profile_->GetSessionService();
if (session_service)
session_service->TabRestored(&new_tab->controller(), really_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) {
TabContentsWrapper* wrapper = TabContentsFactory(profile(), NULL,
MSG_ROUTING_NONE,
GetSelectedTabContents(),
session_storage_namespace);
TabContents* replacement = wrapper->tab_contents();
replacement->SetExtensionAppById(extension_app_id);
replacement->controller().RestoreFromState(navigations, selected_navigation,
from_last_session);
tab_handler_->GetTabStripModel()->ReplaceNavigationControllerAt(
tab_handler_->GetTabStripModel()->selected_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;
}
void Browser::ShowSingletonTab(const GURL& url, bool ignore_path) {
browser::NavigateParams params(this, url, PageTransition::AUTO_BOOKMARK);
params.disposition = SINGLETON_TAB;
params.show_window = true;
params.ignore_path = ignore_path;
browser::Navigate(&params);
}
void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) {
#if !defined(OS_MACOSX)
const bool show_main_ui = (type() == TYPE_NORMAL) && !is_fullscreen;
#else
const bool show_main_ui = (type() == TYPE_NORMAL);
#endif
bool main_not_fullscreen_or_popup =
show_main_ui && !is_fullscreen && (type() & TYPE_POPUP) == 0;
// Navigation commands
command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui);
// Window management commands
command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB,
(type() & TYPE_POPUP) && !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_or_popup);
command_updater_.UpdateCommandEnabled(
IDC_FOCUS_NEXT_PANE, main_not_fullscreen_or_popup);
command_updater_.UpdateCommandEnabled(
IDC_FOCUS_PREVIOUS_PANE, main_not_fullscreen_or_popup);
command_updater_.UpdateCommandEnabled(
IDC_FOCUS_BOOKMARKS, main_not_fullscreen_or_popup);
command_updater_.UpdateCommandEnabled(
IDC_FOCUS_CHROMEOS_STATUS, main_not_fullscreen_or_popup);
// 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_SHOW_BOOKMARK_BAR,
browser_defaults::bookmarks_enabled && show_main_ui);
command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui);
command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS,
show_main_ui && profile_->IsSyncAccessible());
command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui);
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_TOGGLE_VERTICAL_TABS, show_main_ui);
}
///////////////////////////////////////////////////////////////////////////////
// Browser, Assorted browser commands:
bool Browser::ShouldOpenNewTabForWindowDisposition(
WindowOpenDisposition disposition) {
return (disposition == NEW_FOREGROUND_TAB ||
disposition == NEW_BACKGROUND_TAB);
}
TabContents* Browser::GetOrCloneTabForDisposition(
WindowOpenDisposition disposition) {
TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper();
if (ShouldOpenNewTabForWindowDisposition(disposition)) {
current_tab = current_tab->Clone();
tab_handler_->GetTabStripModel()->AddTabContents(
current_tab, -1, PageTransition::LINK,
disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_SELECTED :
TabStripModel::ADD_NONE);
}
return current_tab->tab_contents();
}
void Browser::UpdateTabStripModelInsertionPolicy() {
tab_handler_->GetTabStripModel()->SetInsertionPolicy(UseVerticalTabs() ?
TabStripModel::INSERT_BEFORE : TabStripModel::INSERT_AFTER);
}
void Browser::UseVerticalTabsChanged() {
UpdateTabStripModelInsertionPolicy();
window()->ToggleTabStripMode();
}
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)
// 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)
if (type() == TYPE_NORMAL) {
features |= FEATURE_BOOKMARKBAR;
}
if (!hide_ui_for_fullscreen) {
if (type() != TYPE_NORMAL)
features |= FEATURE_TITLEBAR;
if (type() == TYPE_NORMAL)
features |= FEATURE_TABSTRIP;
if (type() == TYPE_NORMAL)
features |= FEATURE_TOOLBAR;
if ((type() & Browser::TYPE_APP) == 0)
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;
}
void Browser::GoBack(WindowOpenDisposition disposition) {
UserMetrics::RecordAction(UserMetricsAction("Back"), profile_);
TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper();
if (current_tab->controller().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();
}
}
void Browser::GoForward(WindowOpenDisposition disposition) {
UserMetrics::RecordAction(UserMetricsAction("Forward"), profile_);
if (GetSelectedTabContentsWrapper()->controller().CanGoForward())
GetOrCloneTabForDisposition(disposition)->controller().GoForward();
}
void Browser::Reload(WindowOpenDisposition disposition) {
UserMetrics::RecordAction(UserMetricsAction("Reload"), profile_);
ReloadInternal(disposition, false);
}
void Browser::ReloadIgnoringCache(WindowOpenDisposition disposition) {
UserMetrics::RecordAction(UserMetricsAction("ReloadIgnoringCache"), profile_);
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, PageTransition::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"), profile_);
OpenURL(GetHomePage(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
}
void Browser::OpenCurrentURL() {
UserMetrics::RecordAction(UserMetricsAction("LoadURL"), profile_);
LocationBar* location_bar = window_->GetLocationBar();
WindowOpenDisposition open_disposition =
location_bar->GetWindowOpenDisposition();
if (OpenInstant(open_disposition))
return;
GURL url(WideToUTF8(location_bar->GetInputString()));
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(&params);
}
void Browser::Stop() {
UserMetrics::RecordAction(UserMetricsAction("Stop"), profile_);
GetSelectedTabContentsWrapper()->tab_contents()->Stop();
}
void Browser::NewWindow() {
if (browser_defaults::kAlwaysOpenIncognitoWindow &&
CommandLine::ForCurrentProcess()->HasSwitch(switches::kIncognito)) {
NewIncognitoWindow();
return;
}
UserMetrics::RecordAction(UserMetricsAction("NewWindow"), profile_);
SessionService* session_service =
profile_->GetOriginalProfile()->GetSessionService();
if (!session_service ||
!session_service->RestoreIfNecessary(std::vector<GURL>())) {
Browser::OpenEmptyWindow(profile_->GetOriginalProfile());
}
}
void Browser::NewIncognitoWindow() {
UserMetrics::RecordAction(UserMetricsAction("NewIncognitoWindow"), profile_);
Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile());
}
void Browser::CloseWindow() {
UserMetrics::RecordAction(UserMetricsAction("CloseWindow"), profile_);
window_->Close();
}
void Browser::NewTab() {
UserMetrics::RecordAction(UserMetricsAction("NewTab"), profile_);
if (type() == TYPE_NORMAL) {
AddBlankTab(true);
} 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"),
profile_);
if (CanCloseTab()) {
tab_handler_->GetTabStripModel()->CloseTabContentsAt(
tab_handler_->GetTabStripModel()->selected_index(),
TabStripModel::CLOSE_USER_GESTURE |
TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
}
}
void Browser::SelectNextTab() {
UserMetrics::RecordAction(UserMetricsAction("SelectNextTab"), profile_);
tab_handler_->GetTabStripModel()->SelectNextTab();
}
void Browser::SelectPreviousTab() {
UserMetrics::RecordAction(UserMetricsAction("SelectPrevTab"), profile_);
tab_handler_->GetTabStripModel()->SelectPreviousTab();
}
void Browser::OpenTabpose() {
#if defined(OS_MACOSX)
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExposeForTabs)) {
return;
}
UserMetrics::RecordAction(UserMetricsAction("OpenTabpose"), profile_);
window()->OpenTabpose();
#else
NOTREACHED();
#endif
}
void Browser::MoveTabNext() {
UserMetrics::RecordAction(UserMetricsAction("MoveTabNext"), profile_);
tab_handler_->GetTabStripModel()->MoveTabNext();
}
void Browser::MoveTabPrevious() {
UserMetrics::RecordAction(UserMetricsAction("MoveTabPrevious"), profile_);
tab_handler_->GetTabStripModel()->MoveTabPrevious();
}
void Browser::SelectNumberedTab(int index) {
if (index < tab_count()) {
UserMetrics::RecordAction(UserMetricsAction("SelectNumberedTab"),
profile_);
tab_handler_->GetTabStripModel()->SelectTabContentsAt(index, true);
}
}
void Browser::SelectLastTab() {
UserMetrics::RecordAction(UserMetricsAction("SelectLastTab"), profile_);
tab_handler_->GetTabStripModel()->SelectLastTab();
}
void Browser::DuplicateTab() {
UserMetrics::RecordAction(UserMetricsAction("Duplicate"), profile_);
DuplicateContentsAt(selected_index());
}
void Browser::RestoreTab() {
UserMetrics::RecordAction(UserMetricsAction("RestoreTab"), profile_);
TabRestoreService* service = profile_->GetTabRestoreService();
if (!service)
return;
service->RestoreMostRecentEntry(this);
}
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 (!contents->ShouldDisplayURL())
return;
chrome_browser_net::WriteURLToClipboard(
contents->GetURL(),
profile_->GetPrefs()->GetString(prefs::kAcceptLanguages),
g_browser_process->clipboard());
}
void Browser::ConvertPopupToTabbedBrowser() {
UserMetrics::RecordAction(UserMetricsAction("ShowAsTab"), profile_);
int tab_strip_index = tab_handler_->GetTabStripModel()->selected_index();
TabContentsWrapper* contents =
tab_handler_->GetTabStripModel()->DetachTabContentsAt(tab_strip_index);
Browser* browser = Browser::Create(profile_);
browser->tabstrip_model()->AppendTabContents(contents, true);
browser->window()->Show();
}
void Browser::ToggleFullscreenMode() {
#if !defined(OS_MACOSX)
// In kiosk mode, we always want to be fullscreen. When the browser first
// starts we're not yet fullscreen, so let the initial toggle go through.
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode) &&
window_->IsFullscreen())
return;
#endif
UserMetrics::RecordAction(UserMetricsAction("ToggleFullscreen"), profile_);
window_->SetFullscreen(!window_->IsFullscreen());
// On Linux, setting fullscreen mode is an async call to the X server, which
// may or may not support fullscreen mode.
#if !defined(OS_LINUX)
UpdateCommandsForFullscreenMode(window_->IsFullscreen());
#endif
}
#if defined(OS_CHROMEOS)
void Browser::Search() {
// If the NTP is showing, close it.
if (StartsWithASCII(GetSelectedTabContents()->GetURL().spec(),
chrome::kChromeUINewTabURL, true)) {
CloseTab();
return;
}
// Exit fullscreen to show omnibox.
if (window_->IsFullscreen()) {
ToggleFullscreenMode();
// 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, method_factory_.NewRunnableMethod(&Browser::Search));
return;
}
// Otherwise just open it.
NewTab();
}
void Browser::ShowKeyboardOverlay() {
window_->ShowKeyboardOverlay(window_->GetNativeHandle());
}
#endif
void Browser::Exit() {
UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_);
#if defined(OS_CHROMEOS)
chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutStarted", false);
// Write /tmp/uptime-logout-started as well.
const char kLogoutStarted[] = "logout-started";
chromeos::BootTimesLoader::Get()->RecordCurrentStats(kLogoutStarted);
#endif
BrowserList::Exit();
}
void Browser::BookmarkCurrentPage() {
UserMetrics::RecordAction(UserMetricsAction("Star"), profile_);
BookmarkModel* model = profile()->GetBookmarkModel();
if (!model || !model->IsLoaded())
return; // Ignore requests until bookmarks are loaded.
GURL url;
string16 title;
TabContents* tab = GetSelectedTabContents();
bookmark_utils::GetURLAndTitleToBookmark(tab, &url, &title);
bool was_bookmarked = model->IsBookmarked(url);
if (!was_bookmarked && profile_->IsOffTheRecord()) {
// If we're off the record the favicon may not have been saved. Save it now
// so that bookmarks have an icon for the page.
tab->SaveFavicon();
}
model->SetURLStarred(url, title, true);
// 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"), profile_);
TabContents* current_tab = GetSelectedTabContents();
if (current_tab && current_tab->contents_mime_type() == "application/pdf")
UserMetrics::RecordAction(UserMetricsAction("PDF.SavePage"), profile_);
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"), profile_);
GetSelectedTabContents()->EmailPageLocation();
}
void Browser::Print() {
UserMetrics::RecordAction(UserMetricsAction("PrintPreview"), profile_);
GetSelectedTabContents()->PrintPreview();
}
void Browser::ToggleEncodingAutoDetect() {
UserMetrics::RecordAction(UserMetricsAction("AutoDetectChange"), profile_);
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"), profile_);
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"), profile_);
window()->Cut();
}
void Browser::Copy() {
UserMetrics::RecordAction(UserMetricsAction("Copy"), profile_);
window()->Copy();
}
void Browser::Paste() {
UserMetrics::RecordAction(UserMetricsAction("Paste"), profile_);
window()->Paste();
}
void Browser::Find() {
UserMetrics::RecordAction(UserMetricsAction("Find"), profile_);
FindInPage(false, false);
}
void Browser::FindNext() {
UserMetrics::RecordAction(UserMetricsAction("FindNext"), profile_);
FindInPage(true, true);
}
void Browser::FindPrevious() {
UserMetrics::RecordAction(UserMetricsAction("FindPrevious"), profile_);
FindInPage(true, false);
}
void Browser::Zoom(PageZoom::Function zoom_function) {
static const UserMetricsAction kActions[] = {
UserMetricsAction("ZoomMinus"),
UserMetricsAction("ZoomNormal"),
UserMetricsAction("ZoomPlus")
};
UserMetrics::RecordAction(kActions[zoom_function - PageZoom::ZOOM_OUT],
profile_);
TabContentsWrapper* tab_contents = GetSelectedTabContentsWrapper();
tab_contents->render_view_host()->Zoom(zoom_function);
}
void Browser::FocusToolbar() {
UserMetrics::RecordAction(UserMetricsAction("FocusToolbar"), profile_);
window_->FocusToolbar();
}
void Browser::FocusAppMenu() {
UserMetrics::RecordAction(UserMetricsAction("FocusAppMenu"), profile_);
window_->FocusAppMenu();
}
void Browser::FocusLocationBar() {
UserMetrics::RecordAction(UserMetricsAction("FocusLocation"), profile_);
window_->SetFocusToLocationBar(true);
}
void Browser::FocusBookmarksToolbar() {
UserMetrics::RecordAction(UserMetricsAction("FocusBookmarksToolbar"),
profile_);
window_->FocusBookmarksToolbar();
}
void Browser::FocusChromeOSStatus() {
UserMetrics::RecordAction(UserMetricsAction("FocusChromeOSStatus"), profile_);
window_->FocusChromeOSStatus();
}
void Browser::FocusNextPane() {
UserMetrics::RecordAction(UserMetricsAction("FocusNextPane"), profile_);
window_->RotatePaneFocus(true);
}
void Browser::FocusPreviousPane() {
UserMetrics::RecordAction(UserMetricsAction("FocusPreviousPane"), profile_);
window_->RotatePaneFocus(false);
}
void Browser::FocusSearch() {
// TODO(beng): replace this with FocusLocationBar
UserMetrics::RecordAction(UserMetricsAction("FocusSearch"), profile_);
window_->GetLocationBar()->FocusSearch();
}
void Browser::OpenFile() {
UserMetrics::RecordAction(UserMetricsAction("OpenFile"), profile_);
#if defined(OS_CHROMEOS)
FileBrowseUI::OpenPopup(profile_,
"",
FileBrowseUI::kPopupWidth,
FileBrowseUI::kPopupHeight);
#else
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(""),
parent_window, NULL);
#endif
}
void Browser::OpenCreateShortcutsDialog() {
UserMetrics::RecordAction(UserMetricsAction("CreateShortcut"), profile_);
#if defined(OS_WIN) || defined(OS_LINUX)
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->render_view_host()->GetApplicationInfo(entry->page_id());
#else
NOTIMPLEMENTED();
#endif
}
void Browser::ToggleDevToolsWindow(DevToolsToggleAction action) {
std::string uma_string;
switch (action) {
case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE:
uma_string = "DevTools_ToggleConsole";
break;
case DEVTOOLS_TOGGLE_ACTION_NONE:
case DEVTOOLS_TOGGLE_ACTION_INSPECT:
default:
uma_string = "DevTools_ToggleWindow";
break;
}
UserMetrics::RecordAction(UserMetricsAction(uma_string.c_str()), profile_);
DevToolsManager::GetInstance()->ToggleDevToolsWindow(
GetSelectedTabContentsWrapper()->render_view_host(), action);
}
void Browser::OpenTaskManager() {
UserMetrics::RecordAction(UserMetricsAction("TaskManager"), profile_);
window_->ShowTaskManager();
}
void Browser::OpenBugReportDialog() {
UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_);
browser::ShowHtmlBugReportView(this);
}
void Browser::ToggleBookmarkBar() {
UserMetrics::RecordAction(UserMetricsAction("ShowBookmarksBar"), profile_);
window_->ToggleBookmarkBar();
}
void Browser::OpenBookmarkManager() {
UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"), profile_);
ShowBookmarkManagerTab();
}
void Browser::ShowAppMenu() {
// We record the user metric for this event in WrenchMenu::RunMenu.
window_->ShowAppMenu();
}
void Browser::ShowBookmarkManagerTab() {
UserMetrics::RecordAction(UserMetricsAction("ShowBookmarks"), profile_);
ShowSingletonTab(GURL(chrome::kChromeUIBookmarksURL), false);
}
void Browser::ShowHistoryTab() {
UserMetrics::RecordAction(UserMetricsAction("ShowHistory"), profile_);
ShowSingletonTab(GURL(chrome::kChromeUIHistoryURL), false);
}
void Browser::ShowDownloadsTab() {
UserMetrics::RecordAction(UserMetricsAction("ShowDownloads"), profile_);
ShowSingletonTab(GURL(chrome::kChromeUIDownloadsURL), false);
}
void Browser::ShowExtensionsTab() {
UserMetrics::RecordAction(UserMetricsAction("ShowExtensions"), profile_);
ShowSingletonTab(GURL(chrome::kChromeUIExtensionsURL), false);
}
void Browser::ShowAboutConflictsTab() {
UserMetrics::RecordAction(UserMetricsAction("AboutConflicts"), profile_);
ShowSingletonTab(GURL(chrome::kChromeUIConflictsURL), false);
}
void Browser::ShowBrokenPageTab(TabContents* contents) {
UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_);
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), false);
}
void Browser::ShowOptionsTab(const std::string& sub_page) {
GURL url(chrome::kChromeUISettingsURL + sub_page);
ShowSingletonTab(url, true);
}
void Browser::OpenClearBrowsingDataDialog() {
UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_ShowDlg"),
profile_);
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableTabbedOptions)) {
ShowOptionsTab(
chrome::kAdvancedOptionsSubPage + std::string(kHashMark) +
chrome::kClearBrowserDataSubPage);
} else {
window_->ShowClearBrowsingDataDialog();
}
}
void Browser::OpenOptionsDialog() {
UserMetrics::RecordAction(UserMetricsAction("ShowOptions"), profile_);
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableTabbedOptions)) {
ShowOptionsTab(chrome::kDefaultOptionsSubPage);
} else {
ShowOptionsWindow(OPTIONS_PAGE_DEFAULT, OPTIONS_GROUP_NONE, profile_);
}
}
void Browser::OpenKeywordEditor() {
UserMetrics::RecordAction(UserMetricsAction("EditSearchEngines"), profile_);
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableTabbedOptions)) {
ShowOptionsTab(chrome::kSearchEnginesSubPage);
} else {
window_->ShowSearchEnginesDialog();
}
}
void Browser::OpenPasswordManager() {
window_->ShowPasswordManager();
}
void Browser::OpenImportSettingsDialog() {
UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg"), profile_);
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableTabbedOptions)) {
ShowOptionsTab(
chrome::kPersonalOptionsSubPage + std::string(kHashMark) +
chrome::kImportDataSubPage);
} else {
window_->ShowImportDialog();
}
}
void Browser::OpenSyncMyBookmarksDialog() {
sync_ui_util::OpenSyncMyBookmarksDialog(
profile_, ProfileSyncService::START_FROM_WRENCH);
}
void Browser::OpenAboutChromeDialog() {
UserMetrics::RecordAction(UserMetricsAction("AboutChrome"), profile_);
#if defined(OS_CHROMEOS)
ShowSingletonTab(GURL(chrome::kChromeUIAboutURL), false);
#else
window_->ShowAboutChromeDialog();
#endif
}
void Browser::OpenUpdateChromeDialog() {
UserMetrics::RecordAction(UserMetricsAction("UpdateChrome"), profile_);
window_->ShowUpdateChromeDialog();
}
void Browser::OpenHelpTab() {
GURL help_url(kHelpContentUrl);
#if defined(OS_CHROMEOS)
// TODO(nkostylev): Always redirect to HelpApp http://crosbug.com/6923
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession))
help_url = GURL(kHelpContentOnlineUrl);
#endif
GURL localized_help_url = google_util::AppendGoogleLocaleParam(help_url);
AddSelectedTabWithURL(localized_help_url, PageTransition::AUTO_BOOKMARK);
}
void Browser::OpenThemeGalleryTabAndActivate() {
AddSelectedTabWithURL(GURL(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)),
PageTransition::LINK);
}
void Browser::OpenPrivacyDashboardTabAndActivate() {
OpenURL(GURL(kPrivacyDashboardUrl), GURL(),
NEW_FOREGROUND_TAB, PageTransition::LINK);
window_->Activate();
}
void Browser::OpenAutoFillHelpTabAndActivate() {
GURL help_url = google_util::AppendGoogleLocaleParam(GURL(kAutofillHelpUrl));
AddSelectedTabWithURL(help_url, PageTransition::LINK);
}
void Browser::OpenSearchEngineOptionsDialog() {
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableTabbedOptions)) {
OpenKeywordEditor();
} else {
ShowOptionsWindow(OPTIONS_PAGE_GENERAL, OPTIONS_GROUP_DEFAULT_SEARCH,
profile_);
}
}
#if defined(OS_CHROMEOS)
void Browser::OpenSystemOptionsDialog() {
UserMetrics::RecordAction(UserMetricsAction("OpenSystemOptionsDialog"),
profile_);
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableTabbedOptions)) {
ShowOptionsTab(chrome::kSystemOptionsSubPage);
} else {
ShowOptionsWindow(OPTIONS_PAGE_SYSTEM, OPTIONS_GROUP_NONE,
profile_);
}
}
void Browser::OpenInternetOptionsDialog() {
UserMetrics::RecordAction(UserMetricsAction("OpenInternetOptionsDialog"),
profile_);
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableTabbedOptions)) {
ShowOptionsTab(chrome::kInternetOptionsSubPage);
} else {
ShowOptionsWindow(OPTIONS_PAGE_INTERNET, OPTIONS_GROUP_DEFAULT_SEARCH,
profile_);
}
}
void Browser::OpenLanguageOptionsDialog() {
UserMetrics::RecordAction(UserMetricsAction("OpenLanguageOptionsDialog"),
profile_);
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableTabbedOptions)) {
ShowOptionsTab(chrome::kLanguageOptionsSubPage);
} else {
chromeos::LanguageConfigView::Show(profile_, NULL);
}
}
void Browser::OpenSystemTabAndActivate() {
OpenURL(GURL(chrome::kChromeUISystemInfoURL), GURL(),
NEW_FOREGROUND_TAB, PageTransition::LINK);
window_->Activate();
}
void Browser::OpenMobilePlanTabAndActivate() {
OpenURL(GURL(chrome::kChromeUIMobileSetupURL), GURL(),
NEW_FOREGROUND_TAB, PageTransition::LINK);
window_->Activate();
}
#endif
void Browser::OpenPluginsTabAndActivate() {
OpenURL(GURL(chrome::kAboutPluginsURL), GURL(),
NEW_FOREGROUND_TAB, PageTransition::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->RegisterDictionaryPref(prefs::kBrowserWindowPlacement);
prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0);
prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, -1);
prefs->RegisterDictionaryPref(prefs::kPreferencesWindowPlacement);
prefs->RegisterIntegerPref(prefs::kExtensionSidebarWidth, -1);
// Educated guess: Chrome has a bundled Flash version supporting
// clearing LSO data, Chromium hasn't.
#if defined(GOOGLE_CHROME_BUILD)
prefs->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, true);
#else
prefs->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, false);
#endif
}
// static
void Browser::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterStringPref(prefs::kHomePage,
chrome::kChromeUINewTabURL);
prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
prefs->RegisterBooleanPref(prefs::kClearSiteDataOnExit, false);
prefs->RegisterBooleanPref(prefs::kClearPluginLSODataOnExit, false);
prefs->RegisterBooleanPref(prefs::kShowHomeButton, false);
#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::kShowPageOptionsButtons, false);
prefs->RegisterBooleanPref(prefs::kShowUpdatePromotionInfoBar, true);
#endif
prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, "");
prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true);
prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true);
prefs->RegisterBooleanPref(prefs::kDeleteCache, true);
prefs->RegisterBooleanPref(prefs::kDeleteCookies, true);
prefs->RegisterBooleanPref(prefs::kDeletePasswords, false);
prefs->RegisterBooleanPref(prefs::kDeleteFormData, false);
prefs->RegisterBooleanPref(prefs::kDeleteLSOData, false);
prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true);
prefs->RegisterBooleanPref(prefs::kShowOmniboxSearchHint, true);
prefs->RegisterBooleanPref(prefs::kWebAppCreateOnDesktop, true);
prefs->RegisterBooleanPref(prefs::kWebAppCreateInAppsMenu, true);
prefs->RegisterBooleanPref(prefs::kWebAppCreateInQuickLaunchBar, true);
prefs->RegisterBooleanPref(prefs::kUseVerticalTabs, false);
prefs->RegisterBooleanPref(prefs::kEnableTranslate, true);
prefs->RegisterBooleanPref(prefs::kRemotingHasSetupCompleted, false);
prefs->RegisterStringPref(prefs::kCloudPrintEmail, std::string());
prefs->RegisterBooleanPref(prefs::kDevToolsDisabled, false);
prefs->RegisterRealPref(prefs::kDefaultZoomLevel, 0.0);
prefs->RegisterIntegerPref(prefs::kMultipleProfilePrefMigration, 0);
// We need to register the type of this preference in order to query
// it even though it's only typically controlled via policy.
prefs->RegisterBooleanPref(prefs::kDisable3DAPIs, false);
}
// 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;
}
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(); break;
case IDC_EXIT: Exit(); break;
case IDC_TOGGLE_VERTICAL_TABS: ToggleUseVerticalTabs(); 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_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(PageZoom::ZOOM_IN); break;
case IDC_ZOOM_NORMAL: Zoom(PageZoom::RESET); break;
case IDC_ZOOM_MINUS: Zoom(PageZoom::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: // fall through to OpenTaskManager().
case IDC_VIEW_BACKGROUND_PAGES: OpenTaskManager(); break;
case IDC_FEEDBACK: OpenBugReportDialog(); break;
case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break;
case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break;
case IDC_SHOW_APP_MENU: ShowAppMenu(); 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: OpenKeywordEditor(); 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: OpenHelpTab(); break;
#if defined(OS_CHROMEOS)
case IDC_SYSTEM_OPTIONS: OpenSystemOptionsDialog(); break;
case IDC_INTERNET_OPTIONS: OpenInternetOptionsDialog(); break;
case IDC_LANGUAGE_OPTIONS: OpenLanguageOptionsDialog(); break;
#endif
default:
LOG(WARNING) << "Received Unimplemented Command: " << id;
break;
}
}
bool Browser::ExecuteCommandIfEnabled(int id) {
if (command_updater_.SupportsCommand(id) &&
command_updater_.IsCommandEnabled(id)) {
ExecuteCommand(id);
return true;
}
return false;
}
bool Browser::IsReservedCommand(int command_id) {
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,
PageTransition::Type 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();
}
GURL Browser::GetHomePage() const {
// --homepage overrides any preferences.
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kHomePage)) {
// TODO(evanm): clean up usage of DIR_CURRENT.
// http://code.google.com/p/chromium/issues/detail?id=60630
// For now, allow this code to call getcwd().
base::ThreadRestrictions::ScopedAllowIO allow_io;
FilePath browser_directory;
PathService::Get(base::DIR_CURRENT, &browser_directory);
GURL home_page(URLFixerUpper::FixupRelativeFile(browser_directory,
command_line.GetSwitchValuePath(switches::kHomePage)));
if (home_page.is_valid())
return home_page;
}
if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage))
return GURL(chrome::kChromeUINewTabURL);
GURL home_page(URLFixerUpper::FixupURL(
profile_->GetPrefs()->GetString(prefs::kHomePage),
std::string()));
if (!home_page.is_valid())
return GURL(chrome::kChromeUINewTabURL);
return home_page;
}
///////////////////////////////////////////////////////////////////////////////
// Browser, PageNavigator implementation:
void Browser::OpenURL(const GURL& url, const GURL& referrer,
WindowOpenDisposition disposition,
PageTransition::Type transition) {
OpenURLFromTab(NULL, url, referrer, disposition, transition);
}
///////////////////////////////////////////////////////////////////////////////
// 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),
PageTransition::TYPED);
params.disposition = foreground ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
params.tabstrip_index = index;
browser::Navigate(&params);
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_NORMAL, profile_);
browser->set_override_bounds(new_window_bounds);
browser->set_maximized_state(
maximize ? MAXIMIZED_STATE_MAXIMIZED : MAXIMIZED_STATE_UNMAXIMIZED);
browser->CreateBrowserWindow();
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,
PageTransition::Type 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);
}
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();
TabContents* new_contents = contents_dupe->tab_contents();
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_SELECTED |
TabStripModel::ADD_INHERIT_GROUP |
(pinned ? TabStripModel::ADD_PINNED : 0);
tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1,
contents_dupe,
add_types);
} else {
Browser* browser = NULL;
if (type_ & TYPE_APP) {
CHECK((type_ & TYPE_POPUP) == 0);
CHECK(type_ != TYPE_APP_PANEL);
browser = Browser::CreateForApp(app_name_, gfx::Size(), profile_,
false);
} else if (type_ == 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, PageTransition::LINK);
}
if (profile_->HasSessionService()) {
SessionService* session_service = profile_->GetSessionService();
if (session_service)
session_service->TabRestored(&new_contents->controller(), pinned);
}
}
void Browser::CloseFrameAfterDragSession() {
#if defined(OS_WIN) || defined(OS_LINUX)
// 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, method_factory_.NewRunnableMethod(&Browser::CloseFrame));
#endif
}
void Browser::CreateHistoricalTab(TabContentsWrapper* contents) {
// We don't create historical tabs for incognito windows or windows without
// profiles.
if (!profile() || profile()->IsOffTheRecord() ||
!profile()->GetTabRestoreService()) {
return;
}
// We only create historical tab entries for tabbed browser windows.
if (CanSupportWindowFeature(FEATURE_TABSTRIP)) {
profile()->GetTabRestoreService()->CreateHistoricalTab(
&contents->controller());
}
}
bool Browser::RunUnloadListenerBeforeClosing(TabContentsWrapper* contents) {
return Browser::RunUnloadEventsHelper(contents->tab_contents());
}
bool Browser::CanReloadContents(TabContents* source) const {
return type() != TYPE_DEVTOOLS;
}
bool Browser::CanCloseContentsAt(int index) {
if (!CanCloseTab())
return false;
if (tab_handler_->GetTabStripModel()->count() > 1)
return true;
// We are closing the last tab 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.
return CanCloseWithInProgressDownloads();
}
bool Browser::CanBookmarkAllTabs() const {
BookmarkModel* model = profile()->GetBookmarkModel();
return (model && model->IsLoaded() && (tab_count() > 1));
}
void Browser::BookmarkAllTabs() {
BookmarkModel* model = profile()->GetBookmarkModel();
DCHECK(model && model->IsLoaded());
BookmarkEditor::EditDetails details;
details.type = BookmarkEditor::EditDetails::NEW_FOLDER;
bookmark_utils::GetURLsForOpenTabs(this, &(details.urls));
DCHECK(!details.urls.empty());
BookmarkEditor::Show(window()->GetNativeHandle(), profile_,
model->GetParentForNewNodes(), details,
BookmarkEditor::SHOW_TREE);
}
bool Browser::CanCloseTab() const {
TabCloseableStateWatcher* watcher =
g_browser_process->tab_closeable_state_watcher();
return !watcher || watcher->CanCloseTab(this);
}
void Browser::ToggleUseVerticalTabs() {
use_vertical_tabs_.SetValue(!UseVerticalTabs());
UseVerticalTabsChanged();
}
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) {
contents->tab_contents()->set_delegate(this);
contents->controller().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, NotificationType::TAB_CONTENTS_DISCONNECTED,
Source<TabContentsWrapper>(contents));
}
void Browser::TabClosingAt(TabStripModel* tab_strip_model,
TabContentsWrapper* contents,
int index) {
NotificationService::current()->Notify(
NotificationType::TAB_CLOSING,
Source<NavigationController>(&contents->controller()),
NotificationService::NoDetails());
// Sever the TabContents' connection back to us.
contents->tab_contents()->set_delegate(NULL);
}
void Browser::TabDetachedAt(TabContentsWrapper* contents, int index) {
TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH);
}
void Browser::TabDeselectedAt(TabContentsWrapper* contents, int index) {
if (instant())
instant()->DestroyPreviewContents();
// 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::TabSelectedAt(TabContentsWrapper* old_contents,
TabContentsWrapper* new_contents,
int index,
bool user_gesture) {
DCHECK(old_contents != new_contents);
// If we have any update pending, do it now.
if (!chrome_updater_factory_.empty() && old_contents)
ProcessPendingUIUpdates();
// Propagate the profile to the location bar.
UpdateToolbar(true);
// Update reload/stop state.
UpdateReloadStopState(new_contents->tab_contents()->is_loading(), 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(GetSelectedTabContents()->GetStatusText());
}
if (HasFindBarController()) {
find_bar_controller_->ChangeTabContents(new_contents->tab_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.
if (profile_->HasSessionService()) {
SessionService* session_service = profile_->GetSessionService();
if (session_service && !tab_handler_->GetTabStripModel()->closing_all()) {
session_service->SetSelectedTabInWindow(
session_id(), tab_handler_->GetTabStripModel()->selected_index());
}
}
}
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()->selected_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 = profile()->GetSessionService();
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->controller(),
tab_handler_->GetTabStripModel()->IsTabPinned(index));
}
}
void Browser::TabPinnedStateChanged(TabContentsWrapper* contents, int index) {
if (!profile()->HasSessionService())
return;
SessionService* session_service = profile()->GetSessionService();
if (session_service) {
session_service->SetPinnedState(
session_id(),
GetTabContentsAt(index)->controller().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, method_factory_.NewRunnableMethod(&Browser::CloseFrame));
}
///////////////////////////////////////////////////////////////////////////////
// Browser, TabContentsDelegate implementation:
void Browser::OpenURLFromTab(TabContents* source,
const GURL& url,
const GURL& referrer,
WindowOpenDisposition disposition,
PageTransition::Type transition) {
browser::NavigateParams params(this, url, transition);
params.source_contents =
tabstrip_model()->GetTabContentsAt(
tabstrip_model()->GetWrapperIndex(source));
params.referrer = referrer;
params.disposition = disposition;
params.tabstrip_add_types = TabStripModel::ADD_NONE;
params.show_window = true;
browser::Navigate(&params);
}
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 don't schedule updates to commands since they will only change once per
// navigation, so we don't have to worry about flickering.
if (changed_flags & TabContents::INVALIDATE_URL)
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);
// TODO(beng): This belongs behind the platform-specific View interface.
// That's why it's there.
#if defined(OS_CHROMEOS)
if (disposition == NEW_POPUP) {
// If the popup is bigger than a given factor of the screen, then
// turn it into a foreground tab (on chrome os only)
// Also check for width or height == 0, which would otherwise indicate
// a tab sized popup window.
GdkScreen* screen = gdk_screen_get_default();
int max_width = gdk_screen_get_width(screen) * kPopupMaxWidthFactor;
int max_height = gdk_screen_get_height(screen) * kPopupMaxHeightFactor;
if (initial_pos.width() > max_width || initial_pos.width() == 0 ||
initial_pos.height() > max_height || initial_pos.height() == 0) {
disposition = NEW_FOREGROUND_TAB;
}
}
#endif
TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents);
browser::NavigateParams params(this, wrapper);
params.source_contents =
tabstrip_model()->GetTabContentsAt(
tabstrip_model()->GetWrapperIndex(source));
params.disposition = disposition;
params.window_bounds = initial_pos;
params.show_window = true;
browser::Navigate(&params);
}
void Browser::ActivateContents(TabContents* contents) {
tab_handler_->GetTabStripModel()->SelectTabContentsAt(
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) {
UpdateReloadStopState(source->is_loading(), false);
if (GetStatusBubble()) {
GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
}
if (!source->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) {
source->render_view_host()->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);
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 ((type() & TYPE_POPUP) == 0) {
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::IsPopup(const TabContents* source) const {
// A non-tabbed BROWSER is an unconstrained popup.
return !!(type() & TYPE_POPUP);
}
void Browser::ToolbarSizeChanged(TabContents* source, bool is_animating) {
if (source == GetSelectedTabContents() || source == NULL) {
// This will refresh the shelf if needed.
window_->SelectedTabToolbarSizeChanged(is_animating);
}
}
void Browser::URLStarredChanged(TabContents* source, bool starred) {
if (source == GetSelectedTabContents())
window_->SetStarredState(starred);
}
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(), string16());
}
}
void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
if (!GetStatusBubble())
return;
if (source == GetSelectedTabContents()) {
PrefService* prefs = profile_->GetPrefs();
GetStatusBubble()->SetURL(
url, UTF8ToUTF16(prefs->GetString(prefs::kAcceptLanguages)));
}
}
void Browser::UpdateDownloadShelfVisibility(bool visible) {
if (GetStatusBubble())
GetStatusBubble()->UpdateDownloadShelfVisibility(visible);
}
bool Browser::UseVerticalTabs() const {
return use_vertical_tabs_.GetValue();
}
void Browser::ContentsZoomChange(bool zoom_in) {
ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
}
void Browser::OnContentSettingsChange(TabContents* source) {
if (source == GetSelectedTabContents())
window_->GetLocationBar()->UpdateContentSettingsIcons();
}
void Browser::SetTabContentBlocked(TabContents* contents, bool blocked) {
int index = tabstrip_model()->GetWrapperIndex(contents);
if (index == TabStripModel::kNoTab) {
NOTREACHED();
return;
}
tabstrip_model()->SetTabBlocked(index, blocked);
}
void Browser::TabContentsFocused(TabContents* tab_content) {
window_->TabContentsFocused(tab_content);
}
bool Browser::TakeFocus(bool reverse) {
NotificationService::current()->Notify(
NotificationType::FOCUS_RETURNED_TO_BROWSER,
Source<Browser>(this),
NotificationService::NoDetails());
return false;
}
bool Browser::IsApplication() const {
return (type_ & TYPE_APP) != 0;
}
void Browser::ConvertContentsToApplication(TabContents* contents) {
const GURL& url = contents->controller().GetActiveEntry()->url();
std::string app_name = web_app::GenerateApplicationNameFromURL(url);
RegisterAppPrefs(app_name);
DetachContents(contents);
Browser* app_browser = Browser::CreateForApp(
app_name, gfx::Size(), profile_, false);
TabContentsWrapper* 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();
}