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
<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 (BrowserVector::const_iterator it
= browsers_to_close
.begin();
166 it
!= browsers_to_close
.end(); ++it
)
167 (*it
)->window()->Close();
171 void 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;
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();
193 void BrowserList::SetLastActive(Browser
* browser
) {
194 content::RecordAction(UserMetricsAction("ActiveBrowserChanged"));
195 BrowserList
* browser_list
= GetInstance(browser
->host_desktop_type());
197 RemoveBrowserFrom(browser
, &browser_list
->last_active_browsers_
);
198 browser_list
->last_active_browsers_
.push_back(browser
);
200 FOR_EACH_OBSERVER(chrome::BrowserListObserver
, observers_
.Get(),
201 OnBrowserSetLastActive(browser
));
205 bool BrowserList::IsOffTheRecordSessionActive() {
206 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
207 if (it
->profile()->IsOffTheRecord())
214 bool BrowserList::IsOffTheRecordSessionActiveForProfile(Profile
* profile
) {
215 if (profile
->IsGuestSession())
217 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
218 if (it
->profile()->IsSameProfile(profile
) &&
219 it
->profile()->IsOffTheRecord()) {
226 ////////////////////////////////////////////////////////////////////////////////
227 // BrowserList, private:
229 BrowserList::BrowserList() {
232 BrowserList::~BrowserList() {
236 void 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
);