1 // Copyright 2013 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/lifetime/browser_close_manager.h"
7 #include "chrome/browser/background/background_mode_manager.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/browser_shutdown.h"
10 #include "chrome/browser/download/download_service.h"
11 #include "chrome/browser/download/download_service_factory.h"
12 #include "chrome/browser/profiles/profile_manager.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_iterator.h"
15 #include "chrome/browser/ui/browser_list.h"
16 #include "chrome/browser/ui/browser_window.h"
17 #include "chrome/browser/ui/chrome_pages.h"
18 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "content/public/browser/web_contents.h"
24 // Navigates a browser window for |profile|, creating one if necessary, to the
25 // downloads page if there are downloads in progress for |profile|.
26 void ShowInProgressDownloads(Profile
* profile
) {
27 DownloadService
* download_service
=
28 DownloadServiceFactory::GetForBrowserContext(profile
);
29 if (download_service
->NonMaliciousDownloadCount() > 0) {
30 chrome::ScopedTabbedBrowserDisplayer
displayer(profile
,
31 chrome::GetActiveDesktop());
32 chrome::ShowDownloads(displayer
.browser());
38 BrowserCloseManager::BrowserCloseManager() : current_browser_(nullptr) {
41 BrowserCloseManager::~BrowserCloseManager() {
44 void BrowserCloseManager::StartClosingBrowsers() {
45 // If the session is ending, skip straight to closing the browsers. There's no
46 // time to wait for beforeunload dialogs.
47 if (browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION
) {
48 // Tell everyone that we are shutting down.
49 browser_shutdown::SetTryingToQuit(true);
56 void BrowserCloseManager::CancelBrowserClose() {
57 browser_shutdown::SetTryingToQuit(false);
58 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
59 it
->ResetBeforeUnloadHandlers();
63 void BrowserCloseManager::TryToCloseBrowsers() {
64 // If all browser windows can immediately be closed, fall out of this loop and
65 // close the browsers. If any browser window cannot be closed, temporarily
66 // stop closing. CallBeforeUnloadHandlers prompts the user and calls
67 // OnBrowserReportCloseable with the result. If the user confirms the close,
68 // this will trigger TryToCloseBrowsers to try again.
69 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
70 if (it
->CallBeforeUnloadHandlers(
71 base::Bind(&BrowserCloseManager::OnBrowserReportCloseable
, this))) {
72 current_browser_
= *it
;
76 CheckForDownloadsInProgress();
79 void BrowserCloseManager::OnBrowserReportCloseable(bool proceed
) {
80 if (!current_browser_
)
83 current_browser_
= NULL
;
91 void BrowserCloseManager::CheckForDownloadsInProgress() {
92 #if defined(OS_MACOSX)
93 // Mac has its own in-progress downloads prompt in app_controller_mac.mm.
98 int download_count
= DownloadService::NonMaliciousDownloadCountAllProfiles();
99 if (download_count
== 0) {
104 ConfirmCloseWithPendingDownloads(
106 base::Bind(&BrowserCloseManager::OnReportDownloadsCancellable
, this));
109 void BrowserCloseManager::ConfirmCloseWithPendingDownloads(
111 const base::Callback
<void(bool)>& callback
) {
113 BrowserList::GetInstance(chrome::GetActiveDesktop())->GetLastActive();
115 browser
->window()->ConfirmBrowserCloseWithPendingDownloads(
117 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN
,
122 void BrowserCloseManager::OnReportDownloadsCancellable(bool proceed
) {
128 CancelBrowserClose();
130 // Open the downloads page for each profile with downloads in progress.
131 std::vector
<Profile
*> profiles(
132 g_browser_process
->profile_manager()->GetLoadedProfiles());
133 for (Profile
* profile
: profiles
) {
134 ShowInProgressDownloads(profile
);
135 if (profile
->HasOffTheRecordProfile())
136 ShowInProgressDownloads(profile
->GetOffTheRecordProfile());
140 void BrowserCloseManager::CloseBrowsers() {
141 #if defined(ENABLE_SESSION_SERVICE)
142 // Before we close the browsers shutdown all session services. That way an
143 // exit can restore all browsers open before exiting.
144 ProfileManager::ShutdownSessionServices();
146 if (!browser_shutdown::IsTryingToQuit()) {
147 BackgroundModeManager
* background_mode_manager
=
148 g_browser_process
->background_mode_manager();
149 if (background_mode_manager
)
150 background_mode_manager
->SuspendBackgroundMode();
153 bool session_ending
=
154 browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION
;
155 for (scoped_ptr
<chrome::BrowserIterator
> it_ptr(
156 new chrome::BrowserIterator());
158 Browser
* browser
= **it_ptr
;
159 browser
->window()->Close();
160 if (!session_ending
) {
163 // This path is hit during logoff/power-down. In this case we won't get
164 // a final message and so we force the browser to be deleted.
165 // Close doesn't immediately destroy the browser
166 // (Browser::TabStripEmpty() uses invoke later) but when we're ending the
167 // session we need to make sure the browser is destroyed now. So, invoke
168 // DestroyBrowser to make sure the browser is deleted and cleanup can
170 while (browser
->tab_strip_model()->count())
171 delete browser
->tab_strip_model()->GetWebContentsAt(0);
172 browser
->window()->DestroyBrowser();
173 it_ptr
.reset(new chrome::BrowserIterator());
174 if (!it_ptr
->done() && browser
== **it_ptr
) {
175 // Destroying the browser should have removed it from the browser list.
176 // We should never get here.