OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/browser_list.h" | 5 #include "chrome/browser/browser_list.h" |
6 | 6 |
7 #include "base/histogram.h" | 7 #include "base/histogram.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "build/build_config.h" | 10 #include "build/build_config.h" |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 } | 165 } |
166 | 166 |
167 // static | 167 // static |
168 void BrowserList::RemoveBrowser(Browser* browser) { | 168 void BrowserList::RemoveBrowser(Browser* browser) { |
169 RemoveBrowserFrom(browser, &last_active_browsers_); | 169 RemoveBrowserFrom(browser, &last_active_browsers_); |
170 | 170 |
171 // Closing all windows does not indicate quitting the application on the Mac, | 171 // Closing all windows does not indicate quitting the application on the Mac, |
172 // however, many UI tests rely on this behavior so leave it be for now and | 172 // however, many UI tests rely on this behavior so leave it be for now and |
173 // simply ignore the behavior on the Mac outside of unit tests. | 173 // simply ignore the behavior on the Mac outside of unit tests. |
174 // TODO(andybons): Fix the UI tests to Do The Right Thing. | 174 // TODO(andybons): Fix the UI tests to Do The Right Thing. |
175 bool close_app_non_mac = (browsers_.size() == 1); | 175 bool closing_last_browser = (browsers_.size() == 1); |
176 NotificationService::current()->Notify( | 176 NotificationService::current()->Notify( |
177 NotificationType::BROWSER_CLOSED, | 177 NotificationType::BROWSER_CLOSED, |
178 Source<Browser>(browser), Details<bool>(&close_app_non_mac)); | 178 Source<Browser>(browser), Details<bool>(&closing_last_browser)); |
179 | 179 |
180 // Send out notifications before anything changes. Do some basic checking to | 180 // Send out notifications before anything changes. Do some basic checking to |
181 // try to catch evil observers that change the list from under us. | 181 // try to catch evil observers that change the list from under us. |
182 size_t original_count = observers_.size(); | 182 size_t original_count = observers_.size(); |
183 FOR_EACH_OBSERVER(Observer, observers_, OnBrowserRemoving(browser)); | 183 FOR_EACH_OBSERVER(Observer, observers_, OnBrowserRemoving(browser)); |
184 DCHECK_EQ(original_count, observers_.size()) | 184 DCHECK_EQ(original_count, observers_.size()) |
185 << "observer list modified during notification"; | 185 << "observer list modified during notification"; |
186 | 186 |
187 RemoveBrowserFrom(browser, &browsers_); | 187 RemoveBrowserFrom(browser, &browsers_); |
188 | 188 |
189 // If the last Browser object was destroyed, make sure we try to close any | 189 // If the last Browser object was destroyed, make sure we try to close any |
190 // remaining dependent windows too. | 190 // remaining dependent windows too. |
191 if (browsers_.empty()) { | 191 if (browsers_.empty()) { |
192 AllBrowsersClosed(); | |
193 | |
194 delete activity_observer; | 192 delete activity_observer; |
195 activity_observer = NULL; | 193 activity_observer = NULL; |
196 } | 194 } |
197 | 195 |
198 g_browser_process->ReleaseModule(); | 196 g_browser_process->ReleaseModule(); |
| 197 |
| 198 // If we're exiting, send out the APP_TERMINATING notification to allow other |
| 199 // modules to shut themselves down. |
| 200 if (browsers_.empty() && |
| 201 (browser_shutdown::IsTryingToQuit() || |
| 202 g_browser_process->IsShuttingDown())) { |
| 203 // Last browser has just closed, and this is a user-initiated quit or there |
| 204 // is no module keeping the app alive, so send out our notification. |
| 205 NotificationService::current()->Notify(NotificationType::APP_TERMINATING, |
| 206 NotificationService::AllSources(), |
| 207 NotificationService::NoDetails()); |
| 208 AllBrowsersClosedAndAppExiting(); |
| 209 } |
199 } | 210 } |
200 | 211 |
201 // static | 212 // static |
202 void BrowserList::AddObserver(BrowserList::Observer* observer) { | 213 void BrowserList::AddObserver(BrowserList::Observer* observer) { |
203 observers_.AddObserver(observer); | 214 observers_.AddObserver(observer); |
204 } | 215 } |
205 | 216 |
206 // static | 217 // static |
207 void BrowserList::RemoveObserver(BrowserList::Observer* observer) { | 218 void BrowserList::RemoveObserver(BrowserList::Observer* observer) { |
208 observers_.RemoveObserver(observer); | 219 observers_.RemoveObserver(observer); |
209 } | 220 } |
210 | 221 |
211 // static | 222 // static |
212 void BrowserList::CloseAllBrowsers(bool use_post) { | 223 void BrowserList::CloseAllBrowsers(bool use_post) { |
| 224 // Tell everyone that we are shutting down. |
| 225 browser_shutdown::SetTryingToQuit(true); |
| 226 |
213 // Before we close the browsers shutdown all session services. That way an | 227 // Before we close the browsers shutdown all session services. That way an |
214 // exit can restore all browsers open before exiting. | 228 // exit can restore all browsers open before exiting. |
215 ProfileManager::ShutdownSessionServices(); | 229 ProfileManager::ShutdownSessionServices(); |
216 | 230 |
| 231 // If there are no browsers, send the APP_TERMINATING action here. Otherwise, |
| 232 // it will be sent by RemoveBrowser() when the last browser has closed. |
| 233 if (browsers_.empty()) { |
| 234 NotificationService::current()->Notify(NotificationType::APP_TERMINATING, |
| 235 NotificationService::AllSources(), |
| 236 NotificationService::NoDetails()); |
| 237 AllBrowsersClosedAndAppExiting(); |
| 238 return; |
| 239 } |
217 for (BrowserList::const_iterator i = BrowserList::begin(); | 240 for (BrowserList::const_iterator i = BrowserList::begin(); |
218 i != BrowserList::end();) { | 241 i != BrowserList::end();) { |
219 if (use_post) { | 242 if (use_post) { |
220 (*i)->window()->Close(); | 243 (*i)->window()->Close(); |
221 ++i; | 244 ++i; |
222 } else { | 245 } else { |
223 // This path is hit during logoff/power-down. In this case we won't get | 246 // This path is hit during logoff/power-down. In this case we won't get |
224 // a final message and so we force the browser to be deleted. | 247 // a final message and so we force the browser to be deleted. |
225 Browser* browser = *i; | 248 Browser* browser = *i; |
226 browser->window()->Close(); | 249 browser->window()->Close(); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 // static | 325 // static |
303 bool BrowserList::HasBrowserWithProfile(Profile* profile) { | 326 bool BrowserList::HasBrowserWithProfile(Profile* profile) { |
304 return FindBrowserMatching(BrowserList::begin(), | 327 return FindBrowserMatching(BrowserList::begin(), |
305 BrowserList::end(), | 328 BrowserList::end(), |
306 profile, Browser::TYPE_ANY, | 329 profile, Browser::TYPE_ANY, |
307 Browser::FEATURE_NONE, | 330 Browser::FEATURE_NONE, |
308 kMatchNothing) != NULL; | 331 kMatchNothing) != NULL; |
309 } | 332 } |
310 | 333 |
311 // static | 334 // static |
312 bool BrowserList::IsInPersistentMode() { | 335 int BrowserList::keep_alive_count_ = 0; |
313 // TODO(atwilson): check the boolean state variable that you will set for | 336 |
314 // persisent instances. | 337 // static |
315 return false; | 338 void BrowserList::StartKeepAlive() { |
| 339 // Increment the browser process refcount as long as we're keeping the |
| 340 // application alive. |
| 341 if (!WillKeepAlive()) |
| 342 g_browser_process->AddRefModule(); |
| 343 keep_alive_count_++; |
316 } | 344 } |
317 | 345 |
318 // static | 346 // static |
| 347 void BrowserList::EndKeepAlive() { |
| 348 DCHECK(keep_alive_count_ > 0); |
| 349 keep_alive_count_--; |
| 350 // Allow the app to shutdown again. |
| 351 if (!WillKeepAlive()) { |
| 352 g_browser_process->ReleaseModule(); |
| 353 // If there are no browsers open and we aren't already shutting down, |
| 354 // initiate a shutdown. Also skips shutdown if this is a unit test |
| 355 // (MessageLoop::current() == null). |
| 356 if (browsers_.empty() && !browser_shutdown::IsTryingToQuit() && |
| 357 MessageLoop::current()) |
| 358 CloseAllBrowsers(true); |
| 359 } |
| 360 } |
| 361 |
| 362 // static |
| 363 bool BrowserList::WillKeepAlive() { |
| 364 return keep_alive_count_ > 0; |
| 365 } |
| 366 |
| 367 // static |
319 BrowserList::BrowserVector BrowserList::last_active_browsers_; | 368 BrowserList::BrowserVector BrowserList::last_active_browsers_; |
320 | 369 |
321 // static | 370 // static |
322 void BrowserList::SetLastActive(Browser* browser) { | 371 void BrowserList::SetLastActive(Browser* browser) { |
323 RemoveBrowserFrom(browser, &last_active_browsers_); | 372 RemoveBrowserFrom(browser, &last_active_browsers_); |
324 last_active_browsers_.push_back(browser); | 373 last_active_browsers_.push_back(browser); |
325 | 374 |
326 FOR_EACH_OBSERVER(Observer, observers_, OnBrowserSetLastActive(browser)); | 375 FOR_EACH_OBSERVER(Observer, observers_, OnBrowserSetLastActive(browser)); |
327 } | 376 } |
328 | 377 |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 } | 504 } |
456 | 505 |
457 TabContents* next_tab = | 506 TabContents* next_tab = |
458 (*browser_iterator_)->GetTabContentsAt(web_view_index_); | 507 (*browser_iterator_)->GetTabContentsAt(web_view_index_); |
459 if (next_tab) { | 508 if (next_tab) { |
460 cur_ = next_tab; | 509 cur_ = next_tab; |
461 return; | 510 return; |
462 } | 511 } |
463 } | 512 } |
464 } | 513 } |
OLD | NEW |