browser_list.cc revision 29b820f8d84e3bc97d62552e54923c42407f2f29
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 (Browser* b : browsers_to_close) { 166 // BeforeUnload handlers may close browser windows, so we need to explicitly 167 // check whether they still exist. 168 if (b->window()) 169 b->window()->Close(); 170 } 171} 172 173// static 174void BrowserList::PostBeforeUnloadHandlers( 175 const BrowserVector& browsers_to_close, 176 const base::Callback<void(const base::FilePath&)>& on_close_success, 177 const base::FilePath& profile_path, 178 bool tab_close_confirmed) { 179 // We need this bool to avoid infinite recursion when resetting the 180 // BeforeUnload handlers, since doing that will trigger calls back to this 181 // method for each affected window. 182 static bool resetting_handlers = false; 183 184 if (tab_close_confirmed) { 185 TryToCloseBrowserList(browsers_to_close, on_close_success, profile_path); 186 } else if (!resetting_handlers) { 187 base::AutoReset<bool> resetting_handlers_scoper(&resetting_handlers, true); 188 for (BrowserVector::const_iterator it = browsers_to_close.begin(); 189 it != browsers_to_close.end(); ++it) { 190 (*it)->ResetBeforeUnloadHandlers(); 191 } 192 } 193} 194 195// static 196void BrowserList::SetLastActive(Browser* browser) { 197 content::RecordAction(UserMetricsAction("ActiveBrowserChanged")); 198 BrowserList* browser_list = GetInstance(browser->host_desktop_type()); 199 200 RemoveBrowserFrom(browser, &browser_list->last_active_browsers_); 201 browser_list->last_active_browsers_.push_back(browser); 202 203 FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(), 204 OnBrowserSetLastActive(browser)); 205} 206 207// static 208bool BrowserList::IsOffTheRecordSessionActive() { 209 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 210 if (it->profile()->IsOffTheRecord()) 211 return true; 212 } 213 return false; 214} 215 216// static 217bool BrowserList::IsOffTheRecordSessionActiveForProfile(Profile* profile) { 218 if (profile->IsGuestSession()) 219 return true; 220 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 221 if (it->profile()->IsSameProfile(profile) && 222 it->profile()->IsOffTheRecord()) { 223 return true; 224 } 225 } 226 return false; 227} 228 229//////////////////////////////////////////////////////////////////////////////// 230// BrowserList, private: 231 232BrowserList::BrowserList() { 233} 234 235BrowserList::~BrowserList() { 236} 237 238// static 239void BrowserList::RemoveBrowserFrom(Browser* browser, 240 BrowserVector* browser_list) { 241 BrowserVector::iterator remove_browser = 242 std::find(browser_list->begin(), browser_list->end(), browser); 243 if (remove_browser != browser_list->end()) 244 browser_list->erase(remove_browser); 245} 246