• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 using base::UserMetricsAction;
26 using content::WebContents;
27 
28 // static
29 base::LazyInstance<ObserverList<chrome::BrowserListObserver> >::Leaky
30     BrowserList::observers_ = LAZY_INSTANCE_INITIALIZER;
31 
32 // static
33 BrowserList* BrowserList::native_instance_ = NULL;
34 BrowserList* BrowserList::ash_instance_ = NULL;
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 // BrowserList, public:
38 
GetLastActive() const39 Browser* BrowserList::GetLastActive() const {
40   if (!last_active_browsers_.empty())
41     return *(last_active_browsers_.rbegin());
42   return NULL;
43 }
44 
45 // static
GetInstance(chrome::HostDesktopType type)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;
57 }
58 
59 // static
AddBrowser(Browser * browser)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);
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
RemoveBrowser(Browser * 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_);
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
AddObserver(chrome::BrowserListObserver * observer)111 void BrowserList::AddObserver(chrome::BrowserListObserver* observer) {
112   observers_.Get().AddObserver(observer);
113 }
114 
115 // static
RemoveObserver(chrome::BrowserListObserver * observer)116 void BrowserList::RemoveObserver(chrome::BrowserListObserver* observer) {
117   observers_.Get().RemoveObserver(observer);
118 }
119 
120 // static
CloseAllBrowsersWithProfile(Profile * profile)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);
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
CloseAllBrowsersWithProfile(Profile * profile,const base::Callback<void (const base::FilePath &)> & on_close_success)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);
141   }
142 
143   TryToCloseBrowserList(browsers_to_close,
144                         on_close_success,
145                         profile->GetPath());
146 }
147 
148 // static
TryToCloseBrowserList(const BrowserVector & browsers_to_close,const base::Callback<void (const base::FilePath &)> & on_close_success,const base::FilePath & profile_path)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;
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
PostBeforeUnloadHandlers(const BrowserVector & browsers_to_close,const base::Callback<void (const base::FilePath &)> & on_close_success,const base::FilePath & profile_path,bool tab_close_confirmed)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;
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
SetLastActive(Browser * browser)196 void 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
IsOffTheRecordSessionActive()208 bool 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
IsOffTheRecordSessionActiveForProfile(Profile * profile)217 bool 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 
BrowserList()232 BrowserList::BrowserList() {
233 }
234 
~BrowserList()235 BrowserList::~BrowserList() {
236 }
237 
238 // static
RemoveBrowserFrom(Browser * browser,BrowserVector * browser_list)239 void 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