browser_list.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/browser_list.h" 6 7#include <algorithm> 8 9#include "base/auto_reset.h" 10#include "base/logging.h" 11#include "chrome/browser/browser_process.h" 12#include "chrome/browser/browser_shutdown.h" 13#include "chrome/browser/chrome_notification_types.h" 14#include "chrome/browser/lifetime/application_lifetime.h" 15#include "chrome/browser/profiles/profile.h" 16#include "chrome/browser/ui/browser.h" 17#include "chrome/browser/ui/browser_finder.h" 18#include "chrome/browser/ui/browser_iterator.h" 19#include "chrome/browser/ui/browser_list_observer.h" 20#include "chrome/browser/ui/browser_window.h" 21#include "chrome/browser/ui/host_desktop.h" 22#include "content/public/browser/notification_service.h" 23#include "content/public/browser/user_metrics.h" 24 25using base::UserMetricsAction; 26using content::WebContents; 27 28// static 29base::LazyInstance<ObserverList<chrome::BrowserListObserver> >::Leaky 30 BrowserList::observers_ = LAZY_INSTANCE_INITIALIZER; 31 32// static 33BrowserList* BrowserList::native_instance_ = NULL; 34BrowserList* BrowserList::ash_instance_ = NULL; 35 36//////////////////////////////////////////////////////////////////////////////// 37// BrowserList, public: 38 39Browser* BrowserList::GetLastActive() const { 40 if (!last_active_browsers_.empty()) 41 return *(last_active_browsers_.rbegin()); 42 return NULL; 43} 44 45// static 46BrowserList* BrowserList::GetInstance(chrome::HostDesktopType type) { 47 BrowserList** list = NULL; 48 if (type == chrome::HOST_DESKTOP_TYPE_NATIVE) 49 list = &native_instance_; 50 else if (type == chrome::HOST_DESKTOP_TYPE_ASH) 51 list = &ash_instance_; 52 else 53 NOTREACHED(); 54 if (!*list) 55 *list = new BrowserList; 56 return *list; 57} 58 59// static 60void BrowserList::AddBrowser(Browser* browser) { 61 DCHECK(browser); 62 // Push |browser| on the appropriate list instance. 63 BrowserList* browser_list = GetInstance(browser->host_desktop_type()); 64 browser_list->browsers_.push_back(browser); 65 66 g_browser_process->AddRefModule(); 67 68 content::NotificationService::current()->Notify( 69 chrome::NOTIFICATION_BROWSER_OPENED, 70 content::Source<Browser>(browser), 71 content::NotificationService::NoDetails()); 72 73 FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(), 74 OnBrowserAdded(browser)); 75} 76 77// static 78void BrowserList::RemoveBrowser(Browser* browser) { 79 // Remove |browser| from the appropriate list instance. 80 BrowserList* browser_list = GetInstance(browser->host_desktop_type()); 81 RemoveBrowserFrom(browser, &browser_list->last_active_browsers_); 82 83 content::NotificationService::current()->Notify( 84 chrome::NOTIFICATION_BROWSER_CLOSED, 85 content::Source<Browser>(browser), 86 content::NotificationService::NoDetails()); 87 88 RemoveBrowserFrom(browser, &browser_list->browsers_); 89 90 FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(), 91 OnBrowserRemoved(browser)); 92 93 g_browser_process->ReleaseModule(); 94 95 // If we're exiting, send out the APP_TERMINATING notification to allow other 96 // modules to shut themselves down. 97 if (chrome::GetTotalBrowserCount() == 0 && 98 (browser_shutdown::IsTryingToQuit() || 99 g_browser_process->IsShuttingDown())) { 100 // Last browser has just closed, and this is a user-initiated quit or there 101 // is no module keeping the app alive, so send out our notification. No need 102 // to call ProfileManager::ShutdownSessionServices() as part of the 103 // shutdown, because Browser::WindowClosing() already makes sure that the 104 // SessionService is created and notified. 105 chrome::NotifyAppTerminating(); 106 chrome::OnAppExiting(); 107 } 108} 109 110// static 111void BrowserList::AddObserver(chrome::BrowserListObserver* observer) { 112 observers_.Get().AddObserver(observer); 113} 114 115// static 116void BrowserList::RemoveObserver(chrome::BrowserListObserver* observer) { 117 observers_.Get().RemoveObserver(observer); 118} 119 120// static 121void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) { 122 BrowserVector browsers_to_close; 123 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 124 if (it->profile()->GetOriginalProfile() == profile->GetOriginalProfile()) 125 browsers_to_close.push_back(*it); 126 } 127 128 for (BrowserVector::const_iterator it = browsers_to_close.begin(); 129 it != browsers_to_close.end(); ++it) { 130 (*it)->window()->Close(); 131 } 132} 133 134// static 135void BrowserList::CloseAllBrowsersWithProfile(Profile* profile, 136 const base::Callback<void(const base::FilePath&)>& on_close_success) { 137 BrowserVector browsers_to_close; 138 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 139 if (it->profile()->GetOriginalProfile() == profile->GetOriginalProfile()) 140 browsers_to_close.push_back(*it); 141 } 142 143 TryToCloseBrowserList(browsers_to_close, 144 on_close_success, 145 profile->GetPath()); 146} 147 148// static 149void BrowserList::TryToCloseBrowserList(const BrowserVector& browsers_to_close, 150 const base::Callback<void(const base::FilePath&)>& on_close_success, 151 const base::FilePath& profile_path) { 152 for (BrowserVector::const_iterator it = browsers_to_close.begin(); 153 it != browsers_to_close.end(); ++it) { 154 if ((*it)->CallBeforeUnloadHandlers( 155 base::Bind(&BrowserList::PostBeforeUnloadHandlers, 156 browsers_to_close, 157 on_close_success, 158 profile_path))) { 159 return; 160 } 161 } 162 163 on_close_success.Run(profile_path); 164 165 for (BrowserVector::const_iterator it = browsers_to_close.begin(); 166 it != browsers_to_close.end(); ++it) 167 (*it)->window()->Close(); 168} 169 170// static 171void BrowserList::PostBeforeUnloadHandlers( 172 const BrowserVector& browsers_to_close, 173 const base::Callback<void(const base::FilePath&)>& on_close_success, 174 const base::FilePath& profile_path, 175 bool tab_close_confirmed) { 176 // We need this bool to avoid infinite recursion when resetting the 177 // BeforeUnload handlers, since doing that will trigger calls back to this 178 // method for each affected window. 179 static bool resetting_handlers = false; 180 181 if (tab_close_confirmed) { 182 TryToCloseBrowserList(browsers_to_close, on_close_success, profile_path); 183 } else if (!resetting_handlers) { 184 base::AutoReset<bool> resetting_handlers_scoper(&resetting_handlers, true); 185 for (BrowserVector::const_iterator it = browsers_to_close.begin(); 186 it != browsers_to_close.end(); ++it) { 187 (*it)->ResetBeforeUnloadHandlers(); 188 } 189 } 190} 191 192// static 193void BrowserList::SetLastActive(Browser* browser) { 194 content::RecordAction(UserMetricsAction("ActiveBrowserChanged")); 195 BrowserList* browser_list = GetInstance(browser->host_desktop_type()); 196 197 RemoveBrowserFrom(browser, &browser_list->last_active_browsers_); 198 browser_list->last_active_browsers_.push_back(browser); 199 200 FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(), 201 OnBrowserSetLastActive(browser)); 202} 203 204// static 205bool BrowserList::IsOffTheRecordSessionActive() { 206 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 207 if (it->profile()->IsOffTheRecord()) 208 return true; 209 } 210 return false; 211} 212 213// static 214bool BrowserList::IsOffTheRecordSessionActiveForProfile(Profile* profile) { 215 if (profile->IsGuestSession()) 216 return true; 217 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 218 if (it->profile()->IsSameProfile(profile) && 219 it->profile()->IsOffTheRecord()) { 220 return true; 221 } 222 } 223 return false; 224} 225 226//////////////////////////////////////////////////////////////////////////////// 227// BrowserList, private: 228 229BrowserList::BrowserList() { 230} 231 232BrowserList::~BrowserList() { 233} 234 235// static 236void BrowserList::RemoveBrowserFrom(Browser* browser, 237 BrowserVector* browser_list) { 238 BrowserVector::iterator remove_browser = 239 std::find(browser_list->begin(), browser_list->end(), browser); 240 if (remove_browser != browser_list->end()) 241 browser_list->erase(remove_browser); 242} 243