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.
5 #include "chrome/browser/ui/browser_list.h"
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"
25 using base::UserMetricsAction
;
26 using content::WebContents
;
29 base::LazyInstance
<base::ObserverList
<chrome::BrowserListObserver
>>::Leaky
30 BrowserList::observers_
= LAZY_INSTANCE_INITIALIZER
;
33 BrowserList
* BrowserList::native_instance_
= NULL
;
34 BrowserList
* BrowserList::ash_instance_
= NULL
;
36 ////////////////////////////////////////////////////////////////////////////////
37 // BrowserList, public:
39 Browser
* BrowserList::GetLastActive() const {
40 if (!last_active_browsers_
.empty())
41 return *(last_active_browsers_
.rbegin());
46 BrowserList
* 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_
;
55 *list
= new BrowserList
;
60 void BrowserList::AddBrowser(Browser
* 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
);
66 g_browser_process
->AddRefModule();
68 content::NotificationService::current()->Notify(
69 chrome::NOTIFICATION_BROWSER_OPENED
,
70 content::Source
<Browser
>(browser
),
71 content::NotificationService::NoDetails());
73 FOR_EACH_OBSERVER(chrome::BrowserListObserver
, observers_
.Get(),
74 OnBrowserAdded(browser
));
78 void 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_
);
83 content::NotificationService::current()->Notify(
84 chrome::NOTIFICATION_BROWSER_CLOSED
,
85 content::Source
<Browser
>(browser
),
86 content::NotificationService::NoDetails());
88 RemoveBrowserFrom(browser
, &browser_list
->browsers_
);
90 FOR_EACH_OBSERVER(chrome::BrowserListObserver
, observers_
.Get(),
91 OnBrowserRemoved(browser
));
93 g_browser_process
->ReleaseModule();
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();
111 void BrowserList::AddObserver(chrome::BrowserListObserver
* observer
) {
112 observers_
.Get().AddObserver(observer
);
116 void BrowserList::RemoveObserver(chrome::BrowserListObserver
* observer
) {
117 observers_
.Get().RemoveObserver(observer
);
121 void 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
);
128 for (BrowserVector::const_iterator it
= browsers_to_close
.begin();
129 it
!= browsers_to_close
.end(); ++it
) {
130 (*it
)->window()->Close();
135 void 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
);
143 TryToCloseBrowserList(browsers_to_close
,
149 void 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
,
163 on_close_success
.Run(profile_path
);
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.
169 b
->window()->Close();
174 void 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;
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();
196 void BrowserList::SetLastActive(Browser
* browser
) {
197 content::RecordAction(UserMetricsAction("ActiveBrowserChanged"));
198 BrowserList
* browser_list
= GetInstance(browser
->host_desktop_type());
200 RemoveBrowserFrom(browser
, &browser_list
->last_active_browsers_
);
201 browser_list
->last_active_browsers_
.push_back(browser
);
203 FOR_EACH_OBSERVER(chrome::BrowserListObserver
, observers_
.Get(),
204 OnBrowserSetLastActive(browser
));
208 bool BrowserList::IsOffTheRecordSessionActive() {
209 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
210 if (it
->profile()->IsOffTheRecord())
217 bool BrowserList::IsOffTheRecordSessionActiveForProfile(Profile
* profile
) {
218 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
219 if (it
->profile()->IsSameProfile(profile
) &&
220 it
->profile()->IsOffTheRecord()) {
227 ////////////////////////////////////////////////////////////////////////////////
228 // BrowserList, private:
230 BrowserList::BrowserList() {
233 BrowserList::~BrowserList() {
237 void BrowserList::RemoveBrowserFrom(Browser
* browser
,
238 BrowserVector
* browser_list
) {
239 BrowserVector::iterator remove_browser
=
240 std::find(browser_list
->begin(), browser_list
->end(), browser
);
241 if (remove_browser
!= browser_list
->end())
242 browser_list
->erase(remove_browser
);