Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / ui / browser_list.cc
blob851a9f8ca791e33639009faadca239dc3ef2017c
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"
7 #include <algorithm>
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;
28 // static
29 base::LazyInstance<ObserverList<chrome::BrowserListObserver> >::Leaky
30 BrowserList::observers_ = LAZY_INSTANCE_INITIALIZER;
32 // static
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());
42 return NULL;
45 // static
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_;
52 else
53 NOTREACHED();
54 if (!*list)
55 *list = new BrowserList;
56 return *list;
59 // static
60 void 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);
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));
77 // static
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();
110 // static
111 void BrowserList::AddObserver(chrome::BrowserListObserver* observer) {
112 observers_.Get().AddObserver(observer);
115 // static
116 void BrowserList::RemoveObserver(chrome::BrowserListObserver* observer) {
117 observers_.Get().RemoveObserver(observer);
120 // static
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();
134 // static
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,
144 on_close_success,
145 profile->GetPath());
148 // static
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,
156 browsers_to_close,
157 on_close_success,
158 profile_path))) {
159 return;
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();
170 // static
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();
192 // static
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));
204 // static
205 bool BrowserList::IsOffTheRecordSessionActive() {
206 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
207 if (it->profile()->IsOffTheRecord())
208 return true;
210 return false;
213 // static
214 bool 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;
223 return false;
226 ////////////////////////////////////////////////////////////////////////////////
227 // BrowserList, private:
229 BrowserList::BrowserList() {
232 BrowserList::~BrowserList() {
235 // static
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);