Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / lifetime / browser_close_manager.cc
blobaec1b86c3541e48b96a9a0a58f49b823740efae7
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 "base/auto_reset.h"
8 #include "chrome/browser/background/background_mode_manager.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/browser_shutdown.h"
11 #include "chrome/browser/download/download_service.h"
12 #include "chrome/browser/download/download_service_factory.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_iterator.h"
16 #include "chrome/browser/ui/browser_list.h"
17 #include "chrome/browser/ui/browser_window.h"
18 #include "chrome/browser/ui/chrome_pages.h"
19 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "content/public/browser/web_contents.h"
23 namespace {
25 // Navigates a browser window for |profile|, creating one if necessary, to the
26 // downloads page if there are downloads in progress for |profile|.
27 void ShowInProgressDownloads(Profile* profile) {
28 DownloadService* download_service =
29 DownloadServiceFactory::GetForBrowserContext(profile);
30 if (download_service->NonMaliciousDownloadCount() > 0) {
31 chrome::ScopedTabbedBrowserDisplayer displayer(profile,
32 chrome::GetActiveDesktop());
33 chrome::ShowDownloads(displayer.browser());
37 } // namespace
39 BrowserCloseManager::BrowserCloseManager()
40 : current_browser_(nullptr),
41 iterating_over_browsers_during_shutdown_(false) {
42 BrowserList::AddObserver(this);
45 BrowserCloseManager::~BrowserCloseManager() {
46 BrowserList::RemoveObserver(this);
49 void BrowserCloseManager::StartClosingBrowsers() {
50 // If the session is ending, skip straight to closing the browsers. There's no
51 // time to wait for beforeunload dialogs.
52 if (browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION) {
53 // Tell everyone that we are shutting down.
54 browser_shutdown::SetTryingToQuit(true);
55 CloseBrowsers();
56 return;
58 TryToCloseBrowsers();
61 void BrowserCloseManager::OnBrowserAdded(Browser* browser) {
62 CHECK(!iterating_over_browsers_during_shutdown_);
65 void BrowserCloseManager::OnBrowserRemoved(Browser* browser) {
66 CHECK(!iterating_over_browsers_during_shutdown_);
69 void BrowserCloseManager::CancelBrowserClose() {
70 browser_shutdown::SetTryingToQuit(false);
71 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
72 it->ResetBeforeUnloadHandlers();
76 void BrowserCloseManager::TryToCloseBrowsers() {
77 // If all browser windows can immediately be closed, fall out of this loop and
78 // close the browsers. If any browser window cannot be closed, temporarily
79 // stop closing. CallBeforeUnloadHandlers prompts the user and calls
80 // OnBrowserReportCloseable with the result. If the user confirms the close,
81 // this will trigger TryToCloseBrowsers to try again.
82 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
83 if (it->CallBeforeUnloadHandlers(
84 base::Bind(&BrowserCloseManager::OnBrowserReportCloseable, this))) {
85 current_browser_ = *it;
86 return;
89 CheckForDownloadsInProgress();
92 void BrowserCloseManager::OnBrowserReportCloseable(bool proceed) {
93 if (!current_browser_)
94 return;
96 current_browser_ = NULL;
98 if (proceed)
99 TryToCloseBrowsers();
100 else
101 CancelBrowserClose();
104 void BrowserCloseManager::CheckForDownloadsInProgress() {
105 #if defined(OS_MACOSX)
106 // Mac has its own in-progress downloads prompt in app_controller_mac.mm.
107 CloseBrowsers();
108 return;
109 #endif
111 int download_count = DownloadService::NonMaliciousDownloadCountAllProfiles();
112 if (download_count == 0) {
113 CloseBrowsers();
114 return;
117 ConfirmCloseWithPendingDownloads(
118 download_count,
119 base::Bind(&BrowserCloseManager::OnReportDownloadsCancellable, this));
122 void BrowserCloseManager::ConfirmCloseWithPendingDownloads(
123 int download_count,
124 const base::Callback<void(bool)>& callback) {
125 Browser* browser =
126 BrowserList::GetInstance(chrome::GetActiveDesktop())->GetLastActive();
127 DCHECK(browser);
128 browser->window()->ConfirmBrowserCloseWithPendingDownloads(
129 download_count,
130 Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN,
131 true,
132 callback);
135 void BrowserCloseManager::OnReportDownloadsCancellable(bool proceed) {
136 if (proceed) {
137 CloseBrowsers();
138 return;
141 CancelBrowserClose();
143 // Open the downloads page for each profile with downloads in progress.
144 std::vector<Profile*> profiles(
145 g_browser_process->profile_manager()->GetLoadedProfiles());
146 for (Profile* profile : profiles) {
147 ShowInProgressDownloads(profile);
148 if (profile->HasOffTheRecordProfile())
149 ShowInProgressDownloads(profile->GetOffTheRecordProfile());
153 void BrowserCloseManager::CloseBrowsers() {
154 // This method can be entered synchronously from
155 // application_lifetime.cc::CloseAllBrowsers, or asynchronously via
156 // OnBrowserReportClosable or OnReportDownloadsCancellable.
157 // In the async cases, the reference to BrowserCloseManager is held by the
158 // Browser or BrowserWindow, so closing a Browser can cause |this| to be
159 // destroyed. Hold a reference here so that |this| outlives CloseBrowsers.
160 // This is only needed to access |iterating_over_browser_during_shutdown_|,
161 // make this method file-local when it no longer needs |this|.
162 scoped_refptr<BrowserCloseManager> browser_close_manager(this);
164 #if defined(ENABLE_SESSION_SERVICE)
165 // Before we close the browsers shutdown all session services. That way an
166 // exit can restore all browsers open before exiting.
167 ProfileManager::ShutdownSessionServices();
168 #endif
169 if (!browser_shutdown::IsTryingToQuit()) {
170 BackgroundModeManager* background_mode_manager =
171 g_browser_process->background_mode_manager();
172 if (background_mode_manager)
173 background_mode_manager->SuspendBackgroundMode();
176 base::AutoReset<bool> is_iterating(&iterating_over_browsers_during_shutdown_,
177 true);
178 bool session_ending =
179 browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION;
180 for (scoped_ptr<chrome::BrowserIterator> it_ptr(
181 new chrome::BrowserIterator());
182 !it_ptr->done();) {
183 Browser* browser = **it_ptr;
184 browser->window()->Close();
185 if (!session_ending) {
186 it_ptr->Next();
187 } else {
188 // This path is hit during logoff/power-down. In this case we won't get
189 // a final message and so we force the browser to be deleted.
190 // Close doesn't immediately destroy the browser
191 // (Browser::TabStripEmpty() uses invoke later) but when we're ending the
192 // session we need to make sure the browser is destroyed now. So, invoke
193 // DestroyBrowser to make sure the browser is deleted and cleanup can
194 // happen.
195 while (browser->tab_strip_model()->count())
196 delete browser->tab_strip_model()->GetWebContentsAt(0);
198 base::AutoReset<bool> not_iterating(
199 &iterating_over_browsers_during_shutdown_, false);
200 browser->window()->DestroyBrowser();
202 it_ptr.reset(new chrome::BrowserIterator());
203 if (!it_ptr->done() && browser == **it_ptr) {
204 // Destroying the browser should have removed it from the browser list.
205 // We should never get here.
206 NOTREACHED();
207 return;