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

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: cr - remove delegate in UnloadController Created 3 years, 9 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"
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 if (!proceed) { 113 if (!proceed) {
114 CancelWindowClose(); 114 CancelWindowClose();
115 contents->SetClosedByUserGesture(false); 115 contents->SetClosedByUserGesture(false);
116 return false; 116 return false;
117 } 117 }
118 118
119 if (RemoveFromSet(&tabs_needing_before_unload_fired_, contents)) { 119 if (RemoveFromSet(&tabs_needing_before_unload_fired_, contents)) {
120 // Now that beforeunload has fired, put the tab on the queue to fire 120 // Now that beforeunload has fired, put the tab on the queue to fire
121 // unload. 121 // unload.
122 tabs_needing_unload_fired_.insert(contents); 122 tabs_needing_unload_fired_.insert(contents);
123 ProcessPendingTabs(); 123 ProcessPendingTabs(false);
124 // We want to handle firing the unload event ourselves since we want to 124 // 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 125 // fire all the beforeunload events before attempting to fire the unload
126 // events should the user cancel closing the browser. 126 // events should the user cancel closing the browser.
127 return false; 127 return false;
128 } 128 }
129 129
130 return true; 130 return true;
131 } 131 }
132 132
133 bool UnloadController::ShouldCloseWindow() { 133 bool UnloadController::ShouldCloseWindow() {
(...skipping 22 matching lines...) Expand all
156 // return false. 156 // return false.
157 // 4. Otherwise: return true. 157 // 4. Otherwise: return true.
158 is_attempting_to_close_browser_ = true; 158 is_attempting_to_close_browser_ = true;
159 // Cases 1 and 4. 159 // Cases 1 and 4.
160 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired(); 160 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired();
161 if (need_beforeunload_fired == is_calling_before_unload_handlers()) 161 if (need_beforeunload_fired == is_calling_before_unload_handlers())
162 return !need_beforeunload_fired; 162 return !need_beforeunload_fired;
163 163
164 // Cases 2 and 3. 164 // Cases 2 and 3.
165 on_close_confirmed_.Reset(); 165 on_close_confirmed_.Reset();
166 ProcessPendingTabs(); 166 ProcessPendingTabs(false);
167 return false; 167 return false;
168 } 168 }
169 169
170 bool UnloadController::CallBeforeUnloadHandlers( 170 bool UnloadController::TryToCloseWindow(
171 bool skip_beforeunload,
171 const base::Callback<void(bool)>& on_close_confirmed) { 172 const base::Callback<void(bool)>& on_close_confirmed) {
172 // The devtools browser gets its beforeunload events as the results of 173 // 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 174 // intercepting events from the inspected tab, so don't send them here as
174 // well. 175 // well.
175 if (browser_->is_devtools() || HasCompletedUnloadProcessing() || 176 if (browser_->is_devtools() || HasCompletedUnloadProcessing() ||
176 !TabsNeedBeforeUnloadFired()) 177 !TabsNeedBeforeUnloadFired())
177 return false; 178 return false;
178 179
179 is_attempting_to_close_browser_ = true; 180 is_attempting_to_close_browser_ = true;
180 on_close_confirmed_ = on_close_confirmed; 181 on_close_confirmed_ = on_close_confirmed;
181 182
182 ProcessPendingTabs(); 183 ProcessPendingTabs(skip_beforeunload);
183 return true; 184 return !skip_beforeunload;
184 } 185 }
185 186
186 void UnloadController::ResetBeforeUnloadHandlers() { 187 void UnloadController::ResetTryToCloseWindow() {
187 if (!is_calling_before_unload_handlers()) 188 if (!is_calling_before_unload_handlers())
188 return; 189 return;
189 CancelWindowClose(); 190 CancelWindowClose();
190 } 191 }
191 192
192 bool UnloadController::TabsNeedBeforeUnloadFired() { 193 bool UnloadController::TabsNeedBeforeUnloadFired() {
193 if (tabs_needing_before_unload_fired_.empty()) { 194 if (tabs_needing_before_unload_fired_.empty()) {
194 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) { 195 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
195 content::WebContents* contents = 196 content::WebContents* contents =
196 browser_->tab_strip_model()->GetWebContentsAt(i); 197 browser_->tab_strip_model()->GetWebContentsAt(i);
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 } 284 }
284 285
285 void UnloadController::TabDetachedImpl(content::WebContents* contents) { 286 void UnloadController::TabDetachedImpl(content::WebContents* contents) {
286 if (is_attempting_to_close_browser_) 287 if (is_attempting_to_close_browser_)
287 ClearUnloadState(contents, false); 288 ClearUnloadState(contents, false);
288 registrar_.Remove(this, 289 registrar_.Remove(this,
289 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, 290 content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
290 content::Source<content::WebContents>(contents)); 291 content::Source<content::WebContents>(contents));
291 } 292 }
292 293
293 void UnloadController::ProcessPendingTabs() { 294 void UnloadController::ProcessPendingTabs(bool skip_beforeunload) {
294 // Cancel posted/queued ProcessPendingTabs task if there is any. 295 // Cancel posted/queued ProcessPendingTabs task if there is any.
295 weak_factory_.InvalidateWeakPtrs(); 296 weak_factory_.InvalidateWeakPtrs();
296 297
297 if (!is_attempting_to_close_browser_) { 298 if (!is_attempting_to_close_browser_) {
298 // Because we might invoke this after a delay it's possible for the value of 299 // Because we might invoke this after a delay it's possible for the value of
299 // is_attempting_to_close_browser_ to have changed since we scheduled the 300 // is_attempting_to_close_browser_ to have changed since we scheduled the
300 // task. 301 // task.
301 return; 302 return;
302 } 303 }
303 304
304 if (HasCompletedUnloadProcessing() && !TabsNeedBeforeUnloadFired()) { 305 if (HasCompletedUnloadProcessing() && !TabsNeedBeforeUnloadFired()) {
305 // We've finished all the unload events and can proceed to close the 306 // We've finished all the unload events and can proceed to close the
306 // browser. 307 // browser.
307 browser_->OnWindowClosing(); 308 browser_->OnWindowClosing();
308 return; 309 return;
309 } 310 }
310 311
312 if (skip_beforeunload) {
313 tabs_needing_unload_fired_.insert(tabs_needing_before_unload_fired_.begin(),
314 tabs_needing_before_unload_fired_.end());
315 tabs_needing_before_unload_fired_.clear();
316 }
317
311 // Process beforeunload tabs first. When that queue is empty, process 318 // Process beforeunload tabs first. When that queue is empty, process
312 // unload tabs. 319 // unload tabs.
313 if (!tabs_needing_before_unload_fired_.empty()) { 320 if (!tabs_needing_before_unload_fired_.empty()) {
314 content::WebContents* web_contents = 321 content::WebContents* web_contents =
315 *(tabs_needing_before_unload_fired_.begin()); 322 *(tabs_needing_before_unload_fired_.begin());
316 // Null check render_view_host here as this gets called on a PostTask and 323 // Null check render_view_host here as this gets called on a PostTask and
317 // the tab's render_view_host may have been nulled out. 324 // the tab's render_view_host may have been nulled out.
318 if (web_contents->GetRenderViewHost()) { 325 if (web_contents->GetRenderViewHost()) {
319 // If there's a devtools window attached to |web_contents|, 326 // If there's a devtools window attached to |web_contents|,
320 // we would like devtools to call its own beforeunload handlers first, 327 // we would like devtools to call its own beforeunload handlers first,
321 // and then call beforeunload handlers for |web_contents|. 328 // and then call beforeunload handlers for |web_contents|.
322 // See DevToolsWindow::InterceptPageBeforeUnload for details. 329 // See DevToolsWindow::InterceptPageBeforeUnload for details.
323 if (!DevToolsWindow::InterceptPageBeforeUnload(web_contents)) 330 if (!DevToolsWindow::InterceptPageBeforeUnload(web_contents))
324 web_contents->DispatchBeforeUnload(); 331 web_contents->DispatchBeforeUnload();
325 } else { 332 } else {
326 ClearUnloadState(web_contents, true); 333 ClearUnloadState(web_contents, true);
327 } 334 }
328 } else if (is_calling_before_unload_handlers()) { 335 } else if (is_calling_before_unload_handlers()) {
329 base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_; 336 base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_;
330 // Reset |on_close_confirmed_| in case the callback tests 337 // Reset |on_close_confirmed_| in case the callback tests
331 // |is_calling_before_unload_handlers()|, we want to return that calling 338 // |is_calling_before_unload_handlers()|, we want to return that calling
332 // is complete. 339 // is complete.
333 if (tabs_needing_unload_fired_.empty()) 340 if (tabs_needing_unload_fired_.empty())
334 on_close_confirmed_.Reset(); 341 on_close_confirmed_.Reset();
335 on_close_confirmed.Run(true); 342 if (!skip_beforeunload)
343 on_close_confirmed.Run(true);
336 } else if (!tabs_needing_unload_fired_.empty()) { 344 } else if (!tabs_needing_unload_fired_.empty()) {
337 // We've finished firing all beforeunload events and can proceed with unload 345 // We've finished firing all beforeunload events and can proceed with unload
338 // events. 346 // events.
339 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting 347 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
340 // somewhere around here so that we have accurate measurements of shutdown 348 // somewhere around here so that we have accurate measurements of shutdown
341 // time. 349 // time.
342 // TODO(ojan): We can probably fire all the unload events in parallel and 350 // TODO(ojan): We can probably fire all the unload events in parallel and
343 // get a perf benefit from that in the cases where the tab hangs in it's 351 // get a perf benefit from that in the cases where the tab hangs in it's
344 // unload handler or takes a long time to page in. 352 // unload handler or takes a long time to page in.
345 content::WebContents* web_contents = *(tabs_needing_unload_fired_.begin()); 353 content::WebContents* web_contents = *(tabs_needing_unload_fired_.begin());
(...skipping 27 matching lines...) Expand all
373 } 381 }
374 return false; 382 return false;
375 } 383 }
376 384
377 void UnloadController::ClearUnloadState(content::WebContents* web_contents, 385 void UnloadController::ClearUnloadState(content::WebContents* web_contents,
378 bool process_now) { 386 bool process_now) {
379 if (is_attempting_to_close_browser_) { 387 if (is_attempting_to_close_browser_) {
380 RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents); 388 RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents);
381 RemoveFromSet(&tabs_needing_unload_fired_, web_contents); 389 RemoveFromSet(&tabs_needing_unload_fired_, web_contents);
382 if (process_now) { 390 if (process_now) {
383 ProcessPendingTabs(); 391 ProcessPendingTabs(false);
384 } else { 392 } else {
385 // Do not post a new task if there is already any. 393 // Do not post a new task if there is already any.
386 if (weak_factory_.HasWeakPtrs()) 394 if (weak_factory_.HasWeakPtrs())
387 return; 395 return;
388 base::ThreadTaskRunnerHandle::Get()->PostTask( 396 base::ThreadTaskRunnerHandle::Get()->PostTask(
389 FROM_HERE, base::Bind(&UnloadController::ProcessPendingTabs, 397 FROM_HERE, base::Bind(&UnloadController::ProcessPendingTabs,
390 weak_factory_.GetWeakPtr())); 398 weak_factory_.GetWeakPtr(), false));
391 } 399 }
392 } 400 }
393 } 401 }
394 402
395 } // namespace chrome 403 } // namespace chrome
OLDNEW
« no previous file with comments | « chrome/browser/ui/unload_controller.h ('k') | chrome/browser/ui/unload_controller_web_contents_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698