851a9f8ca791e33639009faadca239dc3ef2017c
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / browser_list.cc
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
39 Browser* BrowserList::GetLastActive() const {
40   if (!last_active_browsers_.empty())
41     return *(last_active_browsers_.rbegin());
42   return NULL;
43 }
44
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;
57 }
58
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);
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
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
111 void BrowserList::AddObserver(chrome::BrowserListObserver* observer) {
112   observers_.Get().AddObserver(observer);
113 }
114
115 // static
116 void BrowserList::RemoveObserver(chrome::BrowserListObserver* observer) {
117   observers_.Get().RemoveObserver(observer);
118 }
119
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);
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
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
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 (BrowserVector::const_iterator it = browsers_to_close.begin();
166        it != browsers_to_close.end(); ++it)
167     (*it)->window()->Close();
168 }
169
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;
180
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();
188     }
189   }
190 }
191
192 // static
193 void BrowserList::SetLastActive(Browser* browser) {
194   content::RecordAction(UserMetricsAction("ActiveBrowserChanged"));
195   BrowserList* browser_list = GetInstance(browser->host_desktop_type());
196
197   RemoveBrowserFrom(browser, &browser_list->last_active_browsers_);
198   browser_list->last_active_browsers_.push_back(browser);
199
200   FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(),
201                     OnBrowserSetLastActive(browser));
202 }
203
204 // static
205 bool BrowserList::IsOffTheRecordSessionActive() {
206   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
207     if (it->profile()->IsOffTheRecord())
208       return true;
209   }
210   return false;
211 }
212
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;
221     }
222   }
223   return false;
224 }
225
226 ////////////////////////////////////////////////////////////////////////////////
227 // BrowserList, private:
228
229 BrowserList::BrowserList() {
230 }
231
232 BrowserList::~BrowserList() {
233 }
234
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);
242 }