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

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::CanFastShutdownWebContents(
75 content::WebContents* contents) {
76 return DevToolsWindow::GetInstanceForInspectedRenderViewHost(
77 contents->GetRenderViewHost()) == NULL;
78 }
79
80 // static
74 bool FastUnloadController::RunUnloadEventsHelper( 81 bool FastUnloadController::RunUnloadEventsHelper(
75 content::WebContents* contents) { 82 content::WebContents* contents) {
83 // If there's a devtools window attached to |contents|,
84 // we would like devtools to call its own beforeunload handlers first,
85 // and then call beforeunload handlers for |contents|.
86 // See DevToolsWindow::InterceptPageBeforeUnload for details.
87 if (DevToolsWindow::InterceptPageBeforeUnload(contents)) {
88 return true;
89 }
76 // If the WebContents is not connected yet, then there's no unload 90 // 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. 91 // 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 92 // One case where we hit this is in a tab that has an infinite loop
79 // before load. 93 // before load.
80 if (contents->NeedToFireBeforeUnload()) { 94 if (contents->NeedToFireBeforeUnload()) {
81 // If the page has unload listeners, then we tell the renderer to fire 95 // 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 96 // 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 97 // to proceed closing the page or not, which sends us back to this method
84 // with the NeedToFireBeforeUnload bit cleared. 98 // with the NeedToFireBeforeUnload bit cleared.
85 contents->GetRenderViewHost()->FirePageBeforeUnload(false); 99 contents->GetRenderViewHost()->FirePageBeforeUnload(false);
86 return true; 100 return true;
87 } 101 }
88 return false; 102 return false;
89 } 103 }
90 104
91 bool FastUnloadController::BeforeUnloadFired(content::WebContents* contents, 105 bool FastUnloadController::BeforeUnloadFired(content::WebContents* contents,
92 bool proceed) { 106 bool proceed) {
107 if (!proceed)
108 DevToolsWindow::OnPageCloseCanceled(contents);
109
93 if (!is_attempting_to_close_browser_) { 110 if (!is_attempting_to_close_browser_) {
94 if (!proceed) { 111 if (!proceed) {
95 contents->SetClosedByUserGesture(false); 112 contents->SetClosedByUserGesture(false);
96 } else { 113 } else {
97 // No more dialogs are possible, so remove the tab and finish 114 // No more dialogs are possible, so remove the tab and finish
98 // running unload listeners asynchrounously. 115 // running unload listeners asynchrounously.
99 browser_->tab_strip_model()->delegate()->CreateHistoricalTab(contents); 116 browser_->tab_strip_model()->delegate()->CreateHistoricalTab(contents);
100 DetachWebContents(contents); 117 DetachWebContents(contents);
101 } 118 }
102 return proceed; 119 return proceed;
(...skipping 16 matching lines...) Expand all
119 return false; 136 return false;
120 } 137 }
121 138
122 return true; 139 return true;
123 } 140 }
124 141
125 bool FastUnloadController::ShouldCloseWindow() { 142 bool FastUnloadController::ShouldCloseWindow() {
126 if (HasCompletedUnloadProcessing()) 143 if (HasCompletedUnloadProcessing())
127 return true; 144 return true;
128 145
146 if (browser_->is_devtools() &&
147 DevToolsWindow::ShouldCloseDevToolsBrowser(browser_)) {
148 return true;
149 }
150
129 // The behavior followed here varies based on the current phase of the 151 // The behavior followed here varies based on the current phase of the
130 // operation and whether a batched shutdown is in progress. 152 // operation and whether a batched shutdown is in progress.
131 // 153 //
132 // If there are tabs with outstanding beforeunload handlers: 154 // If there are tabs with outstanding beforeunload handlers:
133 // 1. If a batched shutdown is in progress: return false. 155 // 1. If a batched shutdown is in progress: return false.
134 // This is to prevent interference with batched shutdown already in 156 // This is to prevent interference with batched shutdown already in
135 // progress. 157 // progress.
136 // 2. Otherwise: start sending beforeunload events and return false. 158 // 2. Otherwise: start sending beforeunload events and return false.
137 // 159 //
138 // Otherwise, If there are no tabs with outstanding beforeunload handlers: 160 // Otherwise, If there are no tabs with outstanding beforeunload handlers:
139 // 3. If a batched shutdown is in progress: start sending unload events and 161 // 3. If a batched shutdown is in progress: start sending unload events and
140 // return false. 162 // return false.
141 // 4. Otherwise: return true. 163 // 4. Otherwise: return true.
142 is_attempting_to_close_browser_ = true; 164 is_attempting_to_close_browser_ = true;
143 // Cases 1 and 4. 165 // Cases 1 and 4.
144 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired(); 166 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired();
145 if (need_beforeunload_fired == is_calling_before_unload_handlers()) 167 if (need_beforeunload_fired == is_calling_before_unload_handlers())
146 return !need_beforeunload_fired; 168 return !need_beforeunload_fired;
147 169
148 // Cases 2 and 3. 170 // Cases 2 and 3.
149 on_close_confirmed_.Reset(); 171 on_close_confirmed_.Reset();
150 ProcessPendingTabs(); 172 ProcessPendingTabs();
151 return false; 173 return false;
152 } 174 }
153 175
154 bool FastUnloadController::CallBeforeUnloadHandlers( 176 bool FastUnloadController::CallBeforeUnloadHandlers(
155 const base::Callback<void(bool)>& on_close_confirmed) { 177 const base::Callback<void(bool)>& on_close_confirmed) {
156 if (!TabsNeedBeforeUnloadFired()) 178 // DevTools browser gets its beforeunload events triggered on
179 // inspected tab closing.
180 if (browser_->is_devtools() || !TabsNeedBeforeUnloadFired())
157 return false; 181 return false;
158 182
159 on_close_confirmed_ = on_close_confirmed; 183 on_close_confirmed_ = on_close_confirmed;
160 is_attempting_to_close_browser_ = true; 184 is_attempting_to_close_browser_ = true;
161 ProcessPendingTabs(); 185 ProcessPendingTabs();
162 return true; 186 return true;
163 } 187 }
164 188
165 void FastUnloadController::ResetBeforeUnloadHandlers() { 189 void FastUnloadController::ResetBeforeUnloadHandlers() {
166 if (!is_calling_before_unload_handlers()) 190 if (!is_calling_before_unload_handlers())
167 return; 191 return;
168 CancelWindowClose(); 192 CancelWindowClose();
169 } 193 }
170 194
171 bool FastUnloadController::TabsNeedBeforeUnloadFired() { 195 bool FastUnloadController::TabsNeedBeforeUnloadFired() {
172 if (!tabs_needing_before_unload_.empty() || 196 if (!tabs_needing_before_unload_.empty() ||
173 tab_needing_before_unload_ack_ != NULL) 197 tab_needing_before_unload_ack_ != NULL)
174 return true; 198 return true;
175 199
176 if (!is_calling_before_unload_handlers() && !tabs_needing_unload_.empty()) 200 if (!is_calling_before_unload_handlers() && !tabs_needing_unload_.empty())
177 return false; 201 return false;
178 202
179 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) { 203 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
180 content::WebContents* contents = 204 content::WebContents* contents =
181 browser_->tab_strip_model()->GetWebContentsAt(i); 205 browser_->tab_strip_model()->GetWebContentsAt(i);
206 bool fire_beforeunload = contents->NeedToFireBeforeUnload() ||
jeremy 2013/11/10 12:50:30 Thanks! nit: how about calling this should_fire_b
lushnikov 2013/11/11 15:22:54 Done.
207 DevToolsWindow::NeedToFireBeforeUnload(contents);
182 if (!ContainsKey(tabs_needing_unload_, contents) && 208 if (!ContainsKey(tabs_needing_unload_, contents) &&
183 !ContainsKey(tabs_needing_unload_ack_, contents) && 209 !ContainsKey(tabs_needing_unload_ack_, contents) &&
184 tab_needing_before_unload_ack_ != contents && 210 tab_needing_before_unload_ack_ != contents &&
185 contents->NeedToFireBeforeUnload()) 211 fire_beforeunload)
186 tabs_needing_before_unload_.insert(contents); 212 tabs_needing_before_unload_.insert(contents);
187 } 213 }
188 return !tabs_needing_before_unload_.empty(); 214 return !tabs_needing_before_unload_.empty();
189 } 215 }
190 216
191 //////////////////////////////////////////////////////////////////////////////// 217 ////////////////////////////////////////////////////////////////////////////////
192 // FastUnloadController, content::NotificationObserver implementation: 218 // FastUnloadController, content::NotificationObserver implementation:
193 219
194 void FastUnloadController::Observe( 220 void FastUnloadController::Observe(
195 int type, 221 int type,
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 content::WebContents* contents = *it; 333 content::WebContents* contents = *it;
308 tabs_needing_before_unload_.erase(it); 334 tabs_needing_before_unload_.erase(it);
309 // Null check render_view_host here as this gets called on a PostTask and 335 // 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. 336 // the tab's render_view_host may have been nulled out.
311 if (contents->GetRenderViewHost()) { 337 if (contents->GetRenderViewHost()) {
312 tab_needing_before_unload_ack_ = contents; 338 tab_needing_before_unload_ack_ = contents;
313 339
314 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents); 340 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
315 core_tab_helper->OnCloseStarted(); 341 core_tab_helper->OnCloseStarted();
316 342
317 contents->GetRenderViewHost()->FirePageBeforeUnload(false); 343 // If there's a devtools window attached to |contents|,
344 // we would like devtools to call its own beforeunload handlers first,
345 // and then call beforeunload handlers for |contents|.
346 // See DevToolsWindow::InterceptPageBeforeUnload for details.
347 if (!DevToolsWindow::InterceptPageBeforeUnload(contents))
348 contents->GetRenderViewHost()->FirePageBeforeUnload(false);
318 } else { 349 } else {
319 ProcessPendingTabs(); 350 ProcessPendingTabs();
320 } 351 }
321 return; 352 return;
322 } 353 }
323 354
324 if (is_calling_before_unload_handlers()) { 355 if (is_calling_before_unload_handlers()) {
325 on_close_confirmed_.Run(true); 356 on_close_confirmed_.Run(true);
326 return; 357 return;
327 } 358 }
328
329 // Process all the unload handlers. (The beforeunload handlers have finished.) 359 // Process all the unload handlers. (The beforeunload handlers have finished.)
330 if (!tabs_needing_unload_.empty()) { 360 if (!tabs_needing_unload_.empty()) {
331 browser_->OnWindowClosing(); 361 browser_->OnWindowClosing();
332 362
333 // Run unload handlers detached since no more interaction is possible. 363 // Run unload handlers detached since no more interaction is possible.
334 WebContentsSet::iterator it = tabs_needing_unload_.begin(); 364 WebContentsSet::iterator it = tabs_needing_unload_.begin();
335 while (it != tabs_needing_unload_.end()) { 365 while (it != tabs_needing_unload_.end()) {
336 WebContentsSet::iterator current = it++; 366 WebContentsSet::iterator current = it++;
337 content::WebContents* contents = *current; 367 content::WebContents* contents = *current;
338 tabs_needing_unload_.erase(current); 368 tabs_needing_unload_.erase(current);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 tab_needing_before_unload_ack_ == NULL && 406 tab_needing_before_unload_ack_ == NULL &&
377 tabs_needing_unload_.empty() && 407 tabs_needing_unload_.empty() &&
378 tabs_needing_unload_ack_.empty(); 408 tabs_needing_unload_ack_.empty();
379 } 409 }
380 410
381 void FastUnloadController::CancelWindowClose() { 411 void FastUnloadController::CancelWindowClose() {
382 // Closing of window can be canceled from a beforeunload handler. 412 // Closing of window can be canceled from a beforeunload handler.
383 DCHECK(is_attempting_to_close_browser_); 413 DCHECK(is_attempting_to_close_browser_);
384 tabs_needing_before_unload_.clear(); 414 tabs_needing_before_unload_.clear();
385 if (tab_needing_before_unload_ack_ != NULL) { 415 if (tab_needing_before_unload_ack_ != NULL) {
386
387 CoreTabHelper* core_tab_helper = 416 CoreTabHelper* core_tab_helper =
388 CoreTabHelper::FromWebContents(tab_needing_before_unload_ack_); 417 CoreTabHelper::FromWebContents(tab_needing_before_unload_ack_);
389 core_tab_helper->OnCloseCanceled(); 418 core_tab_helper->OnCloseCanceled();
419 DevToolsWindow::OnPageCloseCanceled(tab_needing_before_unload_ack_);
390 tab_needing_before_unload_ack_ = NULL; 420 tab_needing_before_unload_ack_ = NULL;
391 } 421 }
392 for (WebContentsSet::iterator it = tabs_needing_unload_.begin(); 422 for (WebContentsSet::iterator it = tabs_needing_unload_.begin();
393 it != tabs_needing_unload_.end(); it++) { 423 it != tabs_needing_unload_.end(); it++) {
394 content::WebContents* contents = *it; 424 content::WebContents* contents = *it;
395 425
396 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents); 426 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
397 core_tab_helper->OnCloseCanceled(); 427 core_tab_helper->OnCloseCanceled();
428 DevToolsWindow::OnPageCloseCanceled(contents);
398 } 429 }
399 tabs_needing_unload_.clear(); 430 tabs_needing_unload_.clear();
400 431
401 // No need to clear tabs_needing_unload_ack_. Those tabs are already detached. 432 // No need to clear tabs_needing_unload_ack_. Those tabs are already detached.
402 433
403 if (is_calling_before_unload_handlers()) { 434 if (is_calling_before_unload_handlers()) {
404 base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_; 435 base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_;
405 on_close_confirmed_.Reset(); 436 on_close_confirmed_.Reset();
406 on_close_confirmed.Run(false); 437 on_close_confirmed.Run(false);
407 } 438 }
(...skipping 30 matching lines...) Expand all
438 } 469 }
439 470
440 void FastUnloadController::PostTaskForProcessPendingTabs() { 471 void FastUnloadController::PostTaskForProcessPendingTabs() {
441 base::MessageLoop::current()->PostTask( 472 base::MessageLoop::current()->PostTask(
442 FROM_HERE, 473 FROM_HERE,
443 base::Bind(&FastUnloadController::ProcessPendingTabs, 474 base::Bind(&FastUnloadController::ProcessPendingTabs,
444 weak_factory_.GetWeakPtr())); 475 weak_factory_.GetWeakPtr()));
445 } 476 }
446 477
447 } // namespace chrome 478 } // namespace chrome
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698