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

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

Issue 23835007: DevTools: Do not close devtools if there are dirty files in workspace (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Jeremy's comments Created 7 years, 1 month 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 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/fast_unload_controller.h" 5 #include "chrome/browser/ui/fast_unload_controller.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/message_loop/message_loop.h" 8 #include "base/message_loop/message_loop.h"
9 #include "chrome/browser/chrome_notification_types.h" 9 #include "chrome/browser/chrome_notification_types.h"
10 #include "chrome/browser/devtools/devtools_window.h" 10 #include "chrome/browser/devtools/devtools_window.h"
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 } 64 }
65 65
66 bool FastUnloadController::CanCloseContents(content::WebContents* contents) { 66 bool FastUnloadController::CanCloseContents(content::WebContents* contents) {
67 // Don't try to close the tab when the whole browser is being closed, since 67 // Don't try to close the tab when the whole browser is being closed, since
68 // that avoids the fast shutdown path where we just kill all the renderers. 68 // that avoids the fast shutdown path where we just kill all the renderers.
69 return !is_attempting_to_close_browser_ || 69 return !is_attempting_to_close_browser_ ||
70 is_calling_before_unload_handlers(); 70 is_calling_before_unload_handlers();
71 } 71 }
72 72
73 // static 73 // static
74 bool FastUnloadController::ShouldRunUnloadEventsHelper(
75 content::WebContents* contents) {
76 // If |contents| is being inspected, DevTools needs to intercept beforeunload
77 // events.
78 return DevToolsWindow::GetInstanceForInspectedRenderViewHost(
79 contents->GetRenderViewHost()) != NULL;
80 }
81
82 // static
74 bool FastUnloadController::RunUnloadEventsHelper( 83 bool FastUnloadController::RunUnloadEventsHelper(
75 content::WebContents* contents) { 84 content::WebContents* contents) {
85 // If there's a devtools window attached to |contents|,
86 // we would like devtools to call its own beforeunload handlers first,
87 // and then call beforeunload handlers for |contents|.
88 // See DevToolsWindow::InterceptPageBeforeUnload for details.
89 if (DevToolsWindow::InterceptPageBeforeUnload(contents)) {
90 return true;
91 }
76 // If the WebContents is not connected yet, then there's no unload 92 // If the WebContents is not connected yet, then there's no unload
77 // handler we can fire even if the WebContents has an unload listener. 93 // handler we can fire even if the WebContents has an unload listener.
78 // One case where we hit this is in a tab that has an infinite loop 94 // One case where we hit this is in a tab that has an infinite loop
79 // before load. 95 // before load.
80 if (contents->NeedToFireBeforeUnload()) { 96 if (contents->NeedToFireBeforeUnload()) {
81 // If the page has unload listeners, then we tell the renderer to fire 97 // If the page has unload listeners, then we tell the renderer to fire
82 // them. Once they have fired, we'll get a message back saying whether 98 // them. Once they have fired, we'll get a message back saying whether
83 // to proceed closing the page or not, which sends us back to this method 99 // to proceed closing the page or not, which sends us back to this method
84 // with the NeedToFireBeforeUnload bit cleared. 100 // with the NeedToFireBeforeUnload bit cleared.
85 contents->GetRenderViewHost()->FirePageBeforeUnload(false); 101 contents->GetRenderViewHost()->FirePageBeforeUnload(false);
86 return true; 102 return true;
87 } 103 }
88 return false; 104 return false;
89 } 105 }
90 106
91 bool FastUnloadController::BeforeUnloadFired(content::WebContents* contents, 107 bool FastUnloadController::BeforeUnloadFired(content::WebContents* contents,
92 bool proceed) { 108 bool proceed) {
109 if (!proceed)
110 DevToolsWindow::OnPageCloseCanceled(contents);
111
93 if (!is_attempting_to_close_browser_) { 112 if (!is_attempting_to_close_browser_) {
94 if (!proceed) { 113 if (!proceed) {
95 contents->SetClosedByUserGesture(false); 114 contents->SetClosedByUserGesture(false);
96 } else { 115 } else {
97 // No more dialogs are possible, so remove the tab and finish 116 // No more dialogs are possible, so remove the tab and finish
98 // running unload listeners asynchrounously. 117 // running unload listeners asynchrounously.
99 browser_->tab_strip_model()->delegate()->CreateHistoricalTab(contents); 118 browser_->tab_strip_model()->delegate()->CreateHistoricalTab(contents);
100 DetachWebContents(contents); 119 DetachWebContents(contents);
101 } 120 }
102 return proceed; 121 return proceed;
(...skipping 16 matching lines...) Expand all
119 return false; 138 return false;
120 } 139 }
121 140
122 return true; 141 return true;
123 } 142 }
124 143
125 bool FastUnloadController::ShouldCloseWindow() { 144 bool FastUnloadController::ShouldCloseWindow() {
126 if (HasCompletedUnloadProcessing()) 145 if (HasCompletedUnloadProcessing())
127 return true; 146 return true;
128 147
148 // Special case for when we quit an application. The Devtools window can
149 // close if it's beforeunload event has already fired which will happen due
150 // to the interception of it's content's beforeunload.
151 if (browser_->is_devtools() &&
152 DevToolsWindow::HasFiredBeforeUnloadEventForDevToolsBrowser(browser_)) {
153 return true;
154 }
155
129 // The behavior followed here varies based on the current phase of the 156 // The behavior followed here varies based on the current phase of the
130 // operation and whether a batched shutdown is in progress. 157 // operation and whether a batched shutdown is in progress.
131 // 158 //
132 // If there are tabs with outstanding beforeunload handlers: 159 // If there are tabs with outstanding beforeunload handlers:
133 // 1. If a batched shutdown is in progress: return false. 160 // 1. If a batched shutdown is in progress: return false.
134 // This is to prevent interference with batched shutdown already in 161 // This is to prevent interference with batched shutdown already in
135 // progress. 162 // progress.
136 // 2. Otherwise: start sending beforeunload events and return false. 163 // 2. Otherwise: start sending beforeunload events and return false.
137 // 164 //
138 // Otherwise, If there are no tabs with outstanding beforeunload handlers: 165 // Otherwise, If there are no tabs with outstanding beforeunload handlers:
139 // 3. If a batched shutdown is in progress: start sending unload events and 166 // 3. If a batched shutdown is in progress: start sending unload events and
140 // return false. 167 // return false.
141 // 4. Otherwise: return true. 168 // 4. Otherwise: return true.
142 is_attempting_to_close_browser_ = true; 169 is_attempting_to_close_browser_ = true;
143 // Cases 1 and 4. 170 // Cases 1 and 4.
144 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired(); 171 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired();
145 if (need_beforeunload_fired == is_calling_before_unload_handlers()) 172 if (need_beforeunload_fired == is_calling_before_unload_handlers())
146 return !need_beforeunload_fired; 173 return !need_beforeunload_fired;
147 174
148 // Cases 2 and 3. 175 // Cases 2 and 3.
149 on_close_confirmed_.Reset(); 176 on_close_confirmed_.Reset();
150 ProcessPendingTabs(); 177 ProcessPendingTabs();
151 return false; 178 return false;
152 } 179 }
153 180
154 bool FastUnloadController::CallBeforeUnloadHandlers( 181 bool FastUnloadController::CallBeforeUnloadHandlers(
155 const base::Callback<void(bool)>& on_close_confirmed) { 182 const base::Callback<void(bool)>& on_close_confirmed) {
156 if (!TabsNeedBeforeUnloadFired()) 183 // The DevTools browser gets its beforeunload events as the results of
184 // intercepting events from the inspected tab, so don't send them here as
185 // well.
186 if (browser_->is_devtools() || !TabsNeedBeforeUnloadFired())
157 return false; 187 return false;
158 188
159 on_close_confirmed_ = on_close_confirmed; 189 on_close_confirmed_ = on_close_confirmed;
160 is_attempting_to_close_browser_ = true; 190 is_attempting_to_close_browser_ = true;
161 ProcessPendingTabs(); 191 ProcessPendingTabs();
162 return true; 192 return true;
163 } 193 }
164 194
165 void FastUnloadController::ResetBeforeUnloadHandlers() { 195 void FastUnloadController::ResetBeforeUnloadHandlers() {
166 if (!is_calling_before_unload_handlers()) 196 if (!is_calling_before_unload_handlers())
167 return; 197 return;
168 CancelWindowClose(); 198 CancelWindowClose();
169 } 199 }
170 200
171 bool FastUnloadController::TabsNeedBeforeUnloadFired() { 201 bool FastUnloadController::TabsNeedBeforeUnloadFired() {
172 if (!tabs_needing_before_unload_.empty() || 202 if (!tabs_needing_before_unload_.empty() ||
173 tab_needing_before_unload_ack_ != NULL) 203 tab_needing_before_unload_ack_ != NULL)
174 return true; 204 return true;
175 205
176 if (!is_calling_before_unload_handlers() && !tabs_needing_unload_.empty()) 206 if (!is_calling_before_unload_handlers() && !tabs_needing_unload_.empty())
177 return false; 207 return false;
178 208
179 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) { 209 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
180 content::WebContents* contents = 210 content::WebContents* contents =
181 browser_->tab_strip_model()->GetWebContentsAt(i); 211 browser_->tab_strip_model()->GetWebContentsAt(i);
212 bool should_fire_beforeunload = contents->NeedToFireBeforeUnload() ||
213 DevToolsWindow::NeedsToInterceptBeforeUnload(contents);
182 if (!ContainsKey(tabs_needing_unload_, contents) && 214 if (!ContainsKey(tabs_needing_unload_, contents) &&
183 !ContainsKey(tabs_needing_unload_ack_, contents) && 215 !ContainsKey(tabs_needing_unload_ack_, contents) &&
184 tab_needing_before_unload_ack_ != contents && 216 tab_needing_before_unload_ack_ != contents &&
185 contents->NeedToFireBeforeUnload()) 217 should_fire_beforeunload)
186 tabs_needing_before_unload_.insert(contents); 218 tabs_needing_before_unload_.insert(contents);
187 } 219 }
188 return !tabs_needing_before_unload_.empty(); 220 return !tabs_needing_before_unload_.empty();
189 } 221 }
190 222
191 //////////////////////////////////////////////////////////////////////////////// 223 ////////////////////////////////////////////////////////////////////////////////
192 // FastUnloadController, content::NotificationObserver implementation: 224 // FastUnloadController, content::NotificationObserver implementation:
193 225
194 void FastUnloadController::Observe( 226 void FastUnloadController::Observe(
195 int type, 227 int type,
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 content::WebContents* contents = *it; 339 content::WebContents* contents = *it;
308 tabs_needing_before_unload_.erase(it); 340 tabs_needing_before_unload_.erase(it);
309 // Null check render_view_host here as this gets called on a PostTask and 341 // Null check render_view_host here as this gets called on a PostTask and
310 // the tab's render_view_host may have been nulled out. 342 // the tab's render_view_host may have been nulled out.
311 if (contents->GetRenderViewHost()) { 343 if (contents->GetRenderViewHost()) {
312 tab_needing_before_unload_ack_ = contents; 344 tab_needing_before_unload_ack_ = contents;
313 345
314 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents); 346 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
315 core_tab_helper->OnCloseStarted(); 347 core_tab_helper->OnCloseStarted();
316 348
317 contents->GetRenderViewHost()->FirePageBeforeUnload(false); 349 // If there's a devtools window attached to |contents|,
350 // we would like devtools to call its own beforeunload handlers first,
351 // and then call beforeunload handlers for |contents|.
352 // See DevToolsWindow::InterceptPageBeforeUnload for details.
353 if (!DevToolsWindow::InterceptPageBeforeUnload(contents))
354 contents->GetRenderViewHost()->FirePageBeforeUnload(false);
318 } else { 355 } else {
319 ProcessPendingTabs(); 356 ProcessPendingTabs();
320 } 357 }
321 return; 358 return;
322 } 359 }
323 360
324 if (is_calling_before_unload_handlers()) { 361 if (is_calling_before_unload_handlers()) {
325 on_close_confirmed_.Run(true); 362 on_close_confirmed_.Run(true);
326 return; 363 return;
327 } 364 }
328
329 // Process all the unload handlers. (The beforeunload handlers have finished.) 365 // Process all the unload handlers. (The beforeunload handlers have finished.)
330 if (!tabs_needing_unload_.empty()) { 366 if (!tabs_needing_unload_.empty()) {
331 browser_->OnWindowClosing(); 367 browser_->OnWindowClosing();
332 368
333 // Run unload handlers detached since no more interaction is possible. 369 // Run unload handlers detached since no more interaction is possible.
334 WebContentsSet::iterator it = tabs_needing_unload_.begin(); 370 WebContentsSet::iterator it = tabs_needing_unload_.begin();
335 while (it != tabs_needing_unload_.end()) { 371 while (it != tabs_needing_unload_.end()) {
336 WebContentsSet::iterator current = it++; 372 WebContentsSet::iterator current = it++;
337 content::WebContents* contents = *current; 373 content::WebContents* contents = *current;
338 tabs_needing_unload_.erase(current); 374 tabs_needing_unload_.erase(current);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 tab_needing_before_unload_ack_ == NULL && 412 tab_needing_before_unload_ack_ == NULL &&
377 tabs_needing_unload_.empty() && 413 tabs_needing_unload_.empty() &&
378 tabs_needing_unload_ack_.empty(); 414 tabs_needing_unload_ack_.empty();
379 } 415 }
380 416
381 void FastUnloadController::CancelWindowClose() { 417 void FastUnloadController::CancelWindowClose() {
382 // Closing of window can be canceled from a beforeunload handler. 418 // Closing of window can be canceled from a beforeunload handler.
383 DCHECK(is_attempting_to_close_browser_); 419 DCHECK(is_attempting_to_close_browser_);
384 tabs_needing_before_unload_.clear(); 420 tabs_needing_before_unload_.clear();
385 if (tab_needing_before_unload_ack_ != NULL) { 421 if (tab_needing_before_unload_ack_ != NULL) {
386
387 CoreTabHelper* core_tab_helper = 422 CoreTabHelper* core_tab_helper =
388 CoreTabHelper::FromWebContents(tab_needing_before_unload_ack_); 423 CoreTabHelper::FromWebContents(tab_needing_before_unload_ack_);
389 core_tab_helper->OnCloseCanceled(); 424 core_tab_helper->OnCloseCanceled();
425 DevToolsWindow::OnPageCloseCanceled(tab_needing_before_unload_ack_);
390 tab_needing_before_unload_ack_ = NULL; 426 tab_needing_before_unload_ack_ = NULL;
391 } 427 }
392 for (WebContentsSet::iterator it = tabs_needing_unload_.begin(); 428 for (WebContentsSet::iterator it = tabs_needing_unload_.begin();
393 it != tabs_needing_unload_.end(); it++) { 429 it != tabs_needing_unload_.end(); it++) {
394 content::WebContents* contents = *it; 430 content::WebContents* contents = *it;
395 431
396 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents); 432 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
397 core_tab_helper->OnCloseCanceled(); 433 core_tab_helper->OnCloseCanceled();
434 DevToolsWindow::OnPageCloseCanceled(contents);
398 } 435 }
399 tabs_needing_unload_.clear(); 436 tabs_needing_unload_.clear();
400 437
401 // No need to clear tabs_needing_unload_ack_. Those tabs are already detached. 438 // No need to clear tabs_needing_unload_ack_. Those tabs are already detached.
402 439
403 if (is_calling_before_unload_handlers()) { 440 if (is_calling_before_unload_handlers()) {
404 base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_; 441 base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_;
405 on_close_confirmed_.Reset(); 442 on_close_confirmed_.Reset();
406 on_close_confirmed.Run(false); 443 on_close_confirmed.Run(false);
407 } 444 }
(...skipping 30 matching lines...) Expand all
438 } 475 }
439 476
440 void FastUnloadController::PostTaskForProcessPendingTabs() { 477 void FastUnloadController::PostTaskForProcessPendingTabs() {
441 base::MessageLoop::current()->PostTask( 478 base::MessageLoop::current()->PostTask(
442 FROM_HERE, 479 FROM_HERE,
443 base::Bind(&FastUnloadController::ProcessPendingTabs, 480 base::Bind(&FastUnloadController::ProcessPendingTabs,
444 weak_factory_.GetWeakPtr())); 481 weak_factory_.GetWeakPtr()));
445 } 482 }
446 483
447 } // namespace chrome 484 } // namespace chrome
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698