Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: chrome/browser/ui/unload_controller.cc

Issue 2681203002: Add Browser::SkipCallBeforeUnload so that the browser windows can be closed regardless of beforeunl… (Closed)
Patch Set: sky's comments Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/ui/unload_controller.h" 5 #include "chrome/browser/ui/unload_controller.h"
6 6
7 #include "base/location.h" 7 #include "base/location.h"
8 #include "base/single_thread_task_runner.h" 8 #include "base/single_thread_task_runner.h"
9 #include "base/threading/thread_task_runner_handle.h" 9 #include "base/threading/thread_task_runner_handle.h"
10 #include "chrome/browser/chrome_notification_types.h" 10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/devtools/devtools_window.h" 11 #include "chrome/browser/devtools/devtools_window.h"
12 #include "chrome/browser/ui/browser.h" 12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_tabstrip.h" 13 #include "chrome/browser/ui/browser_tabstrip.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h" 14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/browser/ui/unload_controller_web_contents_delegate.h"
15 #include "content/public/browser/notification_service.h" 16 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/notification_source.h" 17 #include "content/public/browser/notification_source.h"
17 #include "content/public/browser/notification_types.h" 18 #include "content/public/browser/notification_types.h"
18 #include "content/public/browser/render_view_host.h" 19 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/web_contents.h" 20 #include "content/public/browser/web_contents.h"
20 #include "extensions/features/features.h" 21 #include "extensions/features/features.h"
21 22
22 #if BUILDFLAG(ENABLE_EXTENSIONS) 23 #if BUILDFLAG(ENABLE_EXTENSIONS)
23 #include "extensions/browser/extension_registry.h" 24 #include "extensions/browser/extension_registry.h"
24 #include "extensions/common/constants.h" 25 #include "extensions/common/constants.h"
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 if (!proceed) { 114 if (!proceed) {
114 CancelWindowClose(); 115 CancelWindowClose();
115 contents->SetClosedByUserGesture(false); 116 contents->SetClosedByUserGesture(false);
116 return false; 117 return false;
117 } 118 }
118 119
119 if (RemoveFromSet(&tabs_needing_before_unload_fired_, contents)) { 120 if (RemoveFromSet(&tabs_needing_before_unload_fired_, contents)) {
120 // Now that beforeunload has fired, put the tab on the queue to fire 121 // Now that beforeunload has fired, put the tab on the queue to fire
121 // unload. 122 // unload.
122 tabs_needing_unload_fired_.insert(contents); 123 tabs_needing_unload_fired_.insert(contents);
123 ProcessPendingTabs(); 124 ProcessPendingTabs(false);
124 // We want to handle firing the unload event ourselves since we want to 125 // We want to handle firing the unload event ourselves since we want to
125 // fire all the beforeunload events before attempting to fire the unload 126 // fire all the beforeunload events before attempting to fire the unload
126 // events should the user cancel closing the browser. 127 // events should the user cancel closing the browser.
127 return false; 128 return false;
128 } 129 }
129 130
130 return true; 131 return true;
131 } 132 }
132 133
133 bool UnloadController::ShouldCloseWindow() { 134 bool UnloadController::ShouldCloseWindow() {
(...skipping 22 matching lines...) Expand all
156 // return false. 157 // return false.
157 // 4. Otherwise: return true. 158 // 4. Otherwise: return true.
158 is_attempting_to_close_browser_ = true; 159 is_attempting_to_close_browser_ = true;
159 // Cases 1 and 4. 160 // Cases 1 and 4.
160 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired(); 161 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired();
161 if (need_beforeunload_fired == is_calling_before_unload_handlers()) 162 if (need_beforeunload_fired == is_calling_before_unload_handlers())
162 return !need_beforeunload_fired; 163 return !need_beforeunload_fired;
163 164
164 // Cases 2 and 3. 165 // Cases 2 and 3.
165 on_close_confirmed_.Reset(); 166 on_close_confirmed_.Reset();
166 ProcessPendingTabs(); 167 ProcessPendingTabs(false);
167 return false; 168 return false;
168 } 169 }
169 170
170 bool UnloadController::CallBeforeUnloadHandlers( 171 bool UnloadController::TryToCloseWindow(
172 bool skip_before_unload_event,
171 const base::Callback<void(bool)>& on_close_confirmed) { 173 const base::Callback<void(bool)>& on_close_confirmed) {
172 // The devtools browser gets its beforeunload events as the results of 174 // The devtools browser gets its beforeunload events as the results of
173 // intercepting events from the inspected tab, so don't send them here as 175 // intercepting events from the inspected tab, so don't send them here as
174 // well. 176 // well.
175 if (browser_->is_devtools() || HasCompletedUnloadProcessing() || 177 if (browser_->is_devtools() || HasCompletedUnloadProcessing() ||
176 !TabsNeedBeforeUnloadFired()) 178 !TabsNeedBeforeUnloadFired())
177 return false; 179 return false;
178 180
179 is_attempting_to_close_browser_ = true; 181 is_attempting_to_close_browser_ = true;
180 on_close_confirmed_ = on_close_confirmed; 182 on_close_confirmed_ = on_close_confirmed;
181 183
182 ProcessPendingTabs(); 184 ProcessPendingTabs(skip_before_unload_event);
183 return true; 185 return true;
184 } 186 }
185 187
186 void UnloadController::ResetBeforeUnloadHandlers() { 188 void UnloadController::ResetTryToCloseWindow() {
187 if (!is_calling_before_unload_handlers()) 189 if (!is_calling_before_unload_handlers())
188 return; 190 return;
189 CancelWindowClose(); 191 CancelWindowClose();
190 } 192 }
191 193
192 bool UnloadController::TabsNeedBeforeUnloadFired() { 194 bool UnloadController::TabsNeedBeforeUnloadFired() {
193 if (tabs_needing_before_unload_fired_.empty()) { 195 if (tabs_needing_before_unload_fired_.empty()) {
194 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) { 196 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
195 content::WebContents* contents = 197 content::WebContents* contents =
196 browser_->tab_strip_model()->GetWebContentsAt(i); 198 browser_->tab_strip_model()->GetWebContentsAt(i);
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 } 285 }
284 286
285 void UnloadController::TabDetachedImpl(content::WebContents* contents) { 287 void UnloadController::TabDetachedImpl(content::WebContents* contents) {
286 if (is_attempting_to_close_browser_) 288 if (is_attempting_to_close_browser_)
287 ClearUnloadState(contents, false); 289 ClearUnloadState(contents, false);
288 registrar_.Remove(this, 290 registrar_.Remove(this,
289 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, 291 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
290 content::Source<content::WebContents>(contents)); 292 content::Source<content::WebContents>(contents));
291 } 293 }
292 294
293 void UnloadController::ProcessPendingTabs() { 295 void UnloadController::ProcessPendingTabs(bool skip_before_unload_event) {
294 if (!is_attempting_to_close_browser_) { 296 if (!is_attempting_to_close_browser_) {
295 // Because we might invoke this after a delay it's possible for the value of 297 // Because we might invoke this after a delay it's possible for the value of
296 // is_attempting_to_close_browser_ to have changed since we scheduled the 298 // is_attempting_to_close_browser_ to have changed since we scheduled the
297 // task. 299 // task.
298 return; 300 return;
299 } 301 }
300 302
301 if (HasCompletedUnloadProcessing()) { 303 if (HasCompletedUnloadProcessing()) {
302 // We've finished all the unload events and can proceed to close the 304 // We've finished all the unload events and can proceed to close the
303 // browser. 305 // browser.
304 browser_->OnWindowClosing(); 306 browser_->OnWindowClosing();
305 return; 307 return;
306 } 308 }
307 309
310 if (skip_before_unload_event) {
311 tabs_needing_unload_fired_.insert(tabs_needing_before_unload_fired_.begin(),
312 tabs_needing_before_unload_fired_.end());
313 if (!web_contents_delegate_)
314 web_contents_delegate_.reset(new UnloadControllerWebContentsDelegate());
315 for (UnloadListenerSet::iterator it = tabs_needing_unload_fired_.begin();
316 it != tabs_needing_unload_fired_.end(); ++it) {
317 content::WebContents* contents = *it;
318 if (contents->GetRenderViewHost())
319 contents->SetDelegate(web_contents_delegate_.get());
320 }
321 tabs_needing_before_unload_fired_.clear();
322 }
323
308 // Process beforeunload tabs first. When that queue is empty, process 324 // Process beforeunload tabs first. When that queue is empty, process
309 // unload tabs. 325 // unload tabs.
310 if (!tabs_needing_before_unload_fired_.empty()) { 326 if (!tabs_needing_before_unload_fired_.empty()) {
311 content::WebContents* web_contents = 327 content::WebContents* web_contents =
312 *(tabs_needing_before_unload_fired_.begin()); 328 *(tabs_needing_before_unload_fired_.begin());
313 // Null check render_view_host here as this gets called on a PostTask and 329 // Null check render_view_host here as this gets called on a PostTask and
314 // the tab's render_view_host may have been nulled out. 330 // the tab's render_view_host may have been nulled out.
315 if (web_contents->GetRenderViewHost()) { 331 if (web_contents->GetRenderViewHost()) {
316 // If there's a devtools window attached to |web_contents|, 332 // If there's a devtools window attached to |web_contents|,
317 // we would like devtools to call its own beforeunload handlers first, 333 // we would like devtools to call its own beforeunload handlers first,
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 } 386 }
371 return false; 387 return false;
372 } 388 }
373 389
374 void UnloadController::ClearUnloadState(content::WebContents* web_contents, 390 void UnloadController::ClearUnloadState(content::WebContents* web_contents,
375 bool process_now) { 391 bool process_now) {
376 if (is_attempting_to_close_browser_) { 392 if (is_attempting_to_close_browser_) {
377 RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents); 393 RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents);
378 RemoveFromSet(&tabs_needing_unload_fired_, web_contents); 394 RemoveFromSet(&tabs_needing_unload_fired_, web_contents);
379 if (process_now) { 395 if (process_now) {
380 ProcessPendingTabs(); 396 ProcessPendingTabs(false);
381 } else { 397 } else {
382 base::ThreadTaskRunnerHandle::Get()->PostTask( 398 base::ThreadTaskRunnerHandle::Get()->PostTask(
383 FROM_HERE, base::Bind(&UnloadController::ProcessPendingTabs, 399 FROM_HERE, base::Bind(&UnloadController::ProcessPendingTabs,
384 weak_factory_.GetWeakPtr())); 400 weak_factory_.GetWeakPtr(), false));
385 } 401 }
386 } 402 }
387 } 403 }
388 404
389 } // namespace chrome 405 } // namespace chrome
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698