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

Side by Side Diff: chrome/browser/ui/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 (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/message_loop/message_loop.h" 7 #include "base/message_loop/message_loop.h"
8 #include "chrome/browser/chrome_notification_types.h" 8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/devtools/devtools_window.h" 9 #include "chrome/browser/devtools/devtools_window.h"
10 #include "chrome/browser/ui/browser.h" 10 #include "chrome/browser/ui/browser.h"
(...skipping 24 matching lines...) Expand all
35 bool UnloadController::CanCloseContents(content::WebContents* contents) { 35 bool UnloadController::CanCloseContents(content::WebContents* contents) {
36 // Don't try to close the tab when the whole browser is being closed, since 36 // Don't try to close the tab when the whole browser is being closed, since
37 // that avoids the fast shutdown path where we just kill all the renderers. 37 // that avoids the fast shutdown path where we just kill all the renderers.
38 if (is_attempting_to_close_browser_) 38 if (is_attempting_to_close_browser_)
39 ClearUnloadState(contents, true); 39 ClearUnloadState(contents, true);
40 return !is_attempting_to_close_browser_ || 40 return !is_attempting_to_close_browser_ ||
41 is_calling_before_unload_handlers(); 41 is_calling_before_unload_handlers();
42 } 42 }
43 43
44 // static 44 // static
45 bool UnloadController::CanFastShutdownWebContents(
46 content::WebContents* contents) {
47 return DevToolsWindow::GetInstanceForInspectedRenderViewHost(
48 contents->GetRenderViewHost()) == NULL;
49 }
50
51 // static
45 bool UnloadController::RunUnloadEventsHelper(content::WebContents* contents) { 52 bool UnloadController::RunUnloadEventsHelper(content::WebContents* contents) {
53 // If there's a devtools window attached to |contents|,
54 // we would like devtools to call its own beforeunload handlers first,
55 // and then call beforeunload handlers for |contents|.
56 // See DevToolsWindow::InterceptPageBeforeUnload for details.
57 if (DevToolsWindow::InterceptPageBeforeUnload(contents)) {
58 return true;
59 }
46 // If the WebContents is not connected yet, then there's no unload 60 // If the WebContents is not connected yet, then there's no unload
47 // handler we can fire even if the WebContents has an unload listener. 61 // handler we can fire even if the WebContents has an unload listener.
48 // One case where we hit this is in a tab that has an infinite loop 62 // One case where we hit this is in a tab that has an infinite loop
49 // before load. 63 // before load.
50 if (contents->NeedToFireBeforeUnload()) { 64 if (contents->NeedToFireBeforeUnload()) {
51 // If the page has unload listeners, then we tell the renderer to fire 65 // If the page has unload listeners, then we tell the renderer to fire
52 // them. Once they have fired, we'll get a message back saying whether 66 // them. Once they have fired, we'll get a message back saying whether
53 // to proceed closing the page or not, which sends us back to this method 67 // to proceed closing the page or not, which sends us back to this method
54 // with the NeedToFireBeforeUnload bit cleared. 68 // with the NeedToFireBeforeUnload bit cleared.
55 contents->GetRenderViewHost()->FirePageBeforeUnload(false); 69 contents->GetRenderViewHost()->FirePageBeforeUnload(false);
56 return true; 70 return true;
57 } 71 }
58 return false; 72 return false;
59 } 73 }
60 74
61 bool UnloadController::BeforeUnloadFired(content::WebContents* contents, 75 bool UnloadController::BeforeUnloadFired(content::WebContents* contents,
62 bool proceed) { 76 bool proceed) {
77 if (!proceed)
78 DevToolsWindow::OnPageCloseCanceled(contents);
79
63 if (!is_attempting_to_close_browser_) { 80 if (!is_attempting_to_close_browser_) {
64 if (!proceed) 81 if (!proceed)
65 contents->SetClosedByUserGesture(false); 82 contents->SetClosedByUserGesture(false);
66 return proceed; 83 return proceed;
67 } 84 }
68 85
69 if (!proceed) { 86 if (!proceed) {
70 CancelWindowClose(); 87 CancelWindowClose();
71 contents->SetClosedByUserGesture(false); 88 contents->SetClosedByUserGesture(false);
72 return false; 89 return false;
(...skipping 10 matching lines...) Expand all
83 return false; 100 return false;
84 } 101 }
85 102
86 return true; 103 return true;
87 } 104 }
88 105
89 bool UnloadController::ShouldCloseWindow() { 106 bool UnloadController::ShouldCloseWindow() {
90 if (HasCompletedUnloadProcessing()) 107 if (HasCompletedUnloadProcessing())
91 return true; 108 return true;
92 109
110 if (browser_->is_devtools() &&
111 DevToolsWindow::ShouldCloseDevToolsBrowser(browser_)) {
112 return true;
113 }
114
93 // The behavior followed here varies based on the current phase of the 115 // The behavior followed here varies based on the current phase of the
94 // operation and whether a batched shutdown is in progress. 116 // operation and whether a batched shutdown is in progress.
95 // 117 //
96 // If there are tabs with outstanding beforeunload handlers: 118 // If there are tabs with outstanding beforeunload handlers:
97 // 1. If a batched shutdown is in progress: return false. 119 // 1. If a batched shutdown is in progress: return false.
98 // This is to prevent interference with batched shutdown already in 120 // This is to prevent interference with batched shutdown already in
99 // progress. 121 // progress.
100 // 2. Otherwise: start sending beforeunload events and return false. 122 // 2. Otherwise: start sending beforeunload events and return false.
101 // 123 //
102 // Otherwise, If there are no tabs with outstanding beforeunload handlers: 124 // Otherwise, If there are no tabs with outstanding beforeunload handlers:
103 // 3. If a batched shutdown is in progress: start sending unload events and 125 // 3. If a batched shutdown is in progress: start sending unload events and
104 // return false. 126 // return false.
105 // 4. Otherwise: return true. 127 // 4. Otherwise: return true.
106 is_attempting_to_close_browser_ = true; 128 is_attempting_to_close_browser_ = true;
107 // Cases 1 and 4. 129 // Cases 1 and 4.
108 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired(); 130 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired();
109 if (need_beforeunload_fired == is_calling_before_unload_handlers()) 131 if (need_beforeunload_fired == is_calling_before_unload_handlers())
110 return !need_beforeunload_fired; 132 return !need_beforeunload_fired;
111 133
112 // Cases 2 and 3. 134 // Cases 2 and 3.
113 on_close_confirmed_.Reset(); 135 on_close_confirmed_.Reset();
114 ProcessPendingTabs(); 136 ProcessPendingTabs();
115 return false; 137 return false;
116 } 138 }
117 139
118 bool UnloadController::CallBeforeUnloadHandlers( 140 bool UnloadController::CallBeforeUnloadHandlers(
119 const base::Callback<void(bool)>& on_close_confirmed) { 141 const base::Callback<void(bool)>& on_close_confirmed) {
120 if (HasCompletedUnloadProcessing() || !TabsNeedBeforeUnloadFired()) 142 // DevTools browser will get its beforeunload events triggered on
143 // inspected tab closing.
144 if (browser_->is_devtools() || HasCompletedUnloadProcessing() ||
145 !TabsNeedBeforeUnloadFired())
121 return false; 146 return false;
122 147
123 is_attempting_to_close_browser_ = true; 148 is_attempting_to_close_browser_ = true;
124 on_close_confirmed_ = on_close_confirmed; 149 on_close_confirmed_ = on_close_confirmed;
125 150
126 ProcessPendingTabs(); 151 ProcessPendingTabs();
127 return true; 152 return true;
128 } 153 }
129 154
130 void UnloadController::ResetBeforeUnloadHandlers() { 155 void UnloadController::ResetBeforeUnloadHandlers() {
131 if (!is_calling_before_unload_handlers()) 156 if (!is_calling_before_unload_handlers())
132 return; 157 return;
133 CancelWindowClose(); 158 CancelWindowClose();
134 } 159 }
135 160
136 bool UnloadController::TabsNeedBeforeUnloadFired() { 161 bool UnloadController::TabsNeedBeforeUnloadFired() {
137 if (tabs_needing_before_unload_fired_.empty()) { 162 if (tabs_needing_before_unload_fired_.empty()) {
138 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) { 163 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
139 content::WebContents* contents = 164 content::WebContents* contents =
140 browser_->tab_strip_model()->GetWebContentsAt(i); 165 browser_->tab_strip_model()->GetWebContentsAt(i);
166 bool fire_beforeunload = contents->NeedToFireBeforeUnload() ||
jeremy 2013/11/10 12:50:30 nit: Again - should_fire...
lushnikov 2013/11/11 15:22:54 Done.
167 DevToolsWindow::NeedToFireBeforeUnload(contents);
141 if (!ContainsKey(tabs_needing_unload_fired_, contents) && 168 if (!ContainsKey(tabs_needing_unload_fired_, contents) &&
142 contents->NeedToFireBeforeUnload()) { 169 fire_beforeunload) {
143 tabs_needing_before_unload_fired_.insert(contents); 170 tabs_needing_before_unload_fired_.insert(contents);
144 } 171 }
145 } 172 }
146 } 173 }
147 return !tabs_needing_before_unload_fired_.empty(); 174 return !tabs_needing_before_unload_fired_.empty();
148 } 175 }
149 176
150 //////////////////////////////////////////////////////////////////////////////// 177 ////////////////////////////////////////////////////////////////////////////////
151 // UnloadController, content::NotificationObserver implementation: 178 // UnloadController, content::NotificationObserver implementation:
152 179
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 } 256 }
230 257
231 // Process beforeunload tabs first. When that queue is empty, process 258 // Process beforeunload tabs first. When that queue is empty, process
232 // unload tabs. 259 // unload tabs.
233 if (!tabs_needing_before_unload_fired_.empty()) { 260 if (!tabs_needing_before_unload_fired_.empty()) {
234 content::WebContents* web_contents = 261 content::WebContents* web_contents =
235 *(tabs_needing_before_unload_fired_.begin()); 262 *(tabs_needing_before_unload_fired_.begin());
236 // Null check render_view_host here as this gets called on a PostTask and 263 // Null check render_view_host here as this gets called on a PostTask and
237 // the tab's render_view_host may have been nulled out. 264 // the tab's render_view_host may have been nulled out.
238 if (web_contents->GetRenderViewHost()) { 265 if (web_contents->GetRenderViewHost()) {
239 web_contents->GetRenderViewHost()->FirePageBeforeUnload(false); 266 // If there's a devtools window attached to |web_contents|,
267 // we would like devtools to call its own beforeunload handlers first,
268 // and then call beforeunload handlers for |web_contents|.
269 // See DevToolsWindow::InterceptPageBeforeUnload for details.
270 if (!DevToolsWindow::InterceptPageBeforeUnload(web_contents))
271 web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
240 } else { 272 } else {
241 ClearUnloadState(web_contents, true); 273 ClearUnloadState(web_contents, true);
242 } 274 }
243 } else if (is_calling_before_unload_handlers()) { 275 } else if (is_calling_before_unload_handlers()) {
244 on_close_confirmed_.Run(true); 276 on_close_confirmed_.Run(true);
245 } else if (!tabs_needing_unload_fired_.empty()) { 277 } else if (!tabs_needing_unload_fired_.empty()) {
246 // We've finished firing all beforeunload events and can proceed with unload 278 // We've finished firing all beforeunload events and can proceed with unload
247 // events. 279 // events.
248 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting 280 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
249 // somewhere around here so that we have accurate measurements of shutdown 281 // somewhere around here so that we have accurate measurements of shutdown
(...skipping 17 matching lines...) Expand all
267 bool UnloadController::HasCompletedUnloadProcessing() const { 299 bool UnloadController::HasCompletedUnloadProcessing() const {
268 return is_attempting_to_close_browser_ && 300 return is_attempting_to_close_browser_ &&
269 tabs_needing_before_unload_fired_.empty() && 301 tabs_needing_before_unload_fired_.empty() &&
270 tabs_needing_unload_fired_.empty(); 302 tabs_needing_unload_fired_.empty();
271 } 303 }
272 304
273 void UnloadController::CancelWindowClose() { 305 void UnloadController::CancelWindowClose() {
274 // Closing of window can be canceled from a beforeunload handler. 306 // Closing of window can be canceled from a beforeunload handler.
275 DCHECK(is_attempting_to_close_browser_); 307 DCHECK(is_attempting_to_close_browser_);
276 tabs_needing_before_unload_fired_.clear(); 308 tabs_needing_before_unload_fired_.clear();
309 for (UnloadListenerSet::iterator it = tabs_needing_unload_fired_.begin();
310 it != tabs_needing_unload_fired_.end(); ++it) {
311 DevToolsWindow::OnPageCloseCanceled(*it);
312 }
277 tabs_needing_unload_fired_.clear(); 313 tabs_needing_unload_fired_.clear();
278 if (is_calling_before_unload_handlers()) { 314 if (is_calling_before_unload_handlers()) {
279 base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_; 315 base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_;
280 on_close_confirmed_.Reset(); 316 on_close_confirmed_.Reset();
281 on_close_confirmed.Run(false); 317 on_close_confirmed.Run(false);
282 } 318 }
283 is_attempting_to_close_browser_ = false; 319 is_attempting_to_close_browser_ = false;
284 320
285 content::NotificationService::current()->Notify( 321 content::NotificationService::current()->Notify(
286 chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 322 chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
(...skipping 24 matching lines...) Expand all
311 } else { 347 } else {
312 base::MessageLoop::current()->PostTask( 348 base::MessageLoop::current()->PostTask(
313 FROM_HERE, 349 FROM_HERE,
314 base::Bind(&UnloadController::ProcessPendingTabs, 350 base::Bind(&UnloadController::ProcessPendingTabs,
315 weak_factory_.GetWeakPtr())); 351 weak_factory_.GetWeakPtr()));
316 } 352 }
317 } 353 }
318 } 354 }
319 355
320 } // namespace chrome 356 } // namespace chrome
OLDNEW
« chrome/browser/ui/fast_unload_controller.cc ('K') | « chrome/browser/ui/unload_controller.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698