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

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::ShouldRunUnloadEventsHelper(
46 content::WebContents* contents) {
47 // If |contents| is being inspected, DevTools needs to intercept beforeunload
48 // events.
49 return DevToolsWindow::GetInstanceForInspectedRenderViewHost(
50 contents->GetRenderViewHost()) != NULL;
51 }
52
53 // static
45 bool UnloadController::RunUnloadEventsHelper(content::WebContents* contents) { 54 bool UnloadController::RunUnloadEventsHelper(content::WebContents* contents) {
55 // If there's a devtools window attached to |contents|,
56 // we would like devtools to call its own beforeunload handlers first,
57 // and then call beforeunload handlers for |contents|.
58 // See DevToolsWindow::InterceptPageBeforeUnload for details.
59 if (DevToolsWindow::InterceptPageBeforeUnload(contents)) {
60 return true;
61 }
46 // If the WebContents is not connected yet, then there's no unload 62 // 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. 63 // 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 64 // One case where we hit this is in a tab that has an infinite loop
49 // before load. 65 // before load.
50 if (contents->NeedToFireBeforeUnload()) { 66 if (contents->NeedToFireBeforeUnload()) {
51 // If the page has unload listeners, then we tell the renderer to fire 67 // 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 68 // 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 69 // to proceed closing the page or not, which sends us back to this method
54 // with the NeedToFireBeforeUnload bit cleared. 70 // with the NeedToFireBeforeUnload bit cleared.
55 contents->GetRenderViewHost()->FirePageBeforeUnload(false); 71 contents->GetRenderViewHost()->FirePageBeforeUnload(false);
56 return true; 72 return true;
57 } 73 }
58 return false; 74 return false;
59 } 75 }
60 76
61 bool UnloadController::BeforeUnloadFired(content::WebContents* contents, 77 bool UnloadController::BeforeUnloadFired(content::WebContents* contents,
62 bool proceed) { 78 bool proceed) {
79 if (!proceed)
80 DevToolsWindow::OnPageCloseCanceled(contents);
81
63 if (!is_attempting_to_close_browser_) { 82 if (!is_attempting_to_close_browser_) {
64 if (!proceed) 83 if (!proceed)
65 contents->SetClosedByUserGesture(false); 84 contents->SetClosedByUserGesture(false);
66 return proceed; 85 return proceed;
67 } 86 }
68 87
69 if (!proceed) { 88 if (!proceed) {
70 CancelWindowClose(); 89 CancelWindowClose();
71 contents->SetClosedByUserGesture(false); 90 contents->SetClosedByUserGesture(false);
72 return false; 91 return false;
(...skipping 10 matching lines...) Expand all
83 return false; 102 return false;
84 } 103 }
85 104
86 return true; 105 return true;
87 } 106 }
88 107
89 bool UnloadController::ShouldCloseWindow() { 108 bool UnloadController::ShouldCloseWindow() {
90 if (HasCompletedUnloadProcessing()) 109 if (HasCompletedUnloadProcessing())
91 return true; 110 return true;
92 111
112 // Special case for when we quit an application. The Devtools window can
113 // close if it's beforeunload event has already fired which will happen due
114 // to the interception of it's content's beforeunload.
115 if (browser_->is_devtools() &&
116 DevToolsWindow::HasFiredBeforeUnloadEventForDevToolsBrowser(browser_)) {
117 return true;
118 }
119
93 // The behavior followed here varies based on the current phase of the 120 // The behavior followed here varies based on the current phase of the
94 // operation and whether a batched shutdown is in progress. 121 // operation and whether a batched shutdown is in progress.
95 // 122 //
96 // If there are tabs with outstanding beforeunload handlers: 123 // If there are tabs with outstanding beforeunload handlers:
97 // 1. If a batched shutdown is in progress: return false. 124 // 1. If a batched shutdown is in progress: return false.
98 // This is to prevent interference with batched shutdown already in 125 // This is to prevent interference with batched shutdown already in
99 // progress. 126 // progress.
100 // 2. Otherwise: start sending beforeunload events and return false. 127 // 2. Otherwise: start sending beforeunload events and return false.
101 // 128 //
102 // Otherwise, If there are no tabs with outstanding beforeunload handlers: 129 // Otherwise, If there are no tabs with outstanding beforeunload handlers:
103 // 3. If a batched shutdown is in progress: start sending unload events and 130 // 3. If a batched shutdown is in progress: start sending unload events and
104 // return false. 131 // return false.
105 // 4. Otherwise: return true. 132 // 4. Otherwise: return true.
106 is_attempting_to_close_browser_ = true; 133 is_attempting_to_close_browser_ = true;
107 // Cases 1 and 4. 134 // Cases 1 and 4.
108 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired(); 135 bool need_beforeunload_fired = TabsNeedBeforeUnloadFired();
109 if (need_beforeunload_fired == is_calling_before_unload_handlers()) 136 if (need_beforeunload_fired == is_calling_before_unload_handlers())
110 return !need_beforeunload_fired; 137 return !need_beforeunload_fired;
111 138
112 // Cases 2 and 3. 139 // Cases 2 and 3.
113 on_close_confirmed_.Reset(); 140 on_close_confirmed_.Reset();
114 ProcessPendingTabs(); 141 ProcessPendingTabs();
115 return false; 142 return false;
116 } 143 }
117 144
118 bool UnloadController::CallBeforeUnloadHandlers( 145 bool UnloadController::CallBeforeUnloadHandlers(
119 const base::Callback<void(bool)>& on_close_confirmed) { 146 const base::Callback<void(bool)>& on_close_confirmed) {
120 if (HasCompletedUnloadProcessing() || !TabsNeedBeforeUnloadFired()) 147 // The DevTools browser gets its beforeunload events as the results of
148 // intercepting events from the inspected tab, so don't send them here as
149 // well.
150 if (browser_->is_devtools() || HasCompletedUnloadProcessing() ||
151 !TabsNeedBeforeUnloadFired())
121 return false; 152 return false;
122 153
123 is_attempting_to_close_browser_ = true; 154 is_attempting_to_close_browser_ = true;
124 on_close_confirmed_ = on_close_confirmed; 155 on_close_confirmed_ = on_close_confirmed;
125 156
126 ProcessPendingTabs(); 157 ProcessPendingTabs();
127 return true; 158 return true;
128 } 159 }
129 160
130 void UnloadController::ResetBeforeUnloadHandlers() { 161 void UnloadController::ResetBeforeUnloadHandlers() {
131 if (!is_calling_before_unload_handlers()) 162 if (!is_calling_before_unload_handlers())
132 return; 163 return;
133 CancelWindowClose(); 164 CancelWindowClose();
134 } 165 }
135 166
136 bool UnloadController::TabsNeedBeforeUnloadFired() { 167 bool UnloadController::TabsNeedBeforeUnloadFired() {
137 if (tabs_needing_before_unload_fired_.empty()) { 168 if (tabs_needing_before_unload_fired_.empty()) {
138 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) { 169 for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
139 content::WebContents* contents = 170 content::WebContents* contents =
140 browser_->tab_strip_model()->GetWebContentsAt(i); 171 browser_->tab_strip_model()->GetWebContentsAt(i);
172 bool should_fire_beforeunload = contents->NeedToFireBeforeUnload() ||
173 DevToolsWindow::NeedsToInterceptBeforeUnload(contents);
141 if (!ContainsKey(tabs_needing_unload_fired_, contents) && 174 if (!ContainsKey(tabs_needing_unload_fired_, contents) &&
142 contents->NeedToFireBeforeUnload()) { 175 should_fire_beforeunload) {
143 tabs_needing_before_unload_fired_.insert(contents); 176 tabs_needing_before_unload_fired_.insert(contents);
144 } 177 }
145 } 178 }
146 } 179 }
147 return !tabs_needing_before_unload_fired_.empty(); 180 return !tabs_needing_before_unload_fired_.empty();
148 } 181 }
149 182
150 //////////////////////////////////////////////////////////////////////////////// 183 ////////////////////////////////////////////////////////////////////////////////
151 // UnloadController, content::NotificationObserver implementation: 184 // UnloadController, content::NotificationObserver implementation:
152 185
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 } 262 }
230 263
231 // Process beforeunload tabs first. When that queue is empty, process 264 // Process beforeunload tabs first. When that queue is empty, process
232 // unload tabs. 265 // unload tabs.
233 if (!tabs_needing_before_unload_fired_.empty()) { 266 if (!tabs_needing_before_unload_fired_.empty()) {
234 content::WebContents* web_contents = 267 content::WebContents* web_contents =
235 *(tabs_needing_before_unload_fired_.begin()); 268 *(tabs_needing_before_unload_fired_.begin());
236 // Null check render_view_host here as this gets called on a PostTask and 269 // 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. 270 // the tab's render_view_host may have been nulled out.
238 if (web_contents->GetRenderViewHost()) { 271 if (web_contents->GetRenderViewHost()) {
239 web_contents->GetRenderViewHost()->FirePageBeforeUnload(false); 272 // If there's a devtools window attached to |web_contents|,
273 // we would like devtools to call its own beforeunload handlers first,
jeremy 2013/11/14 08:53:13 nit: devtools capitalization here and throughout *
lushnikov 2013/11/14 09:49:39 Oops, just checked other usages of "devtools" word
274 // and then call beforeunload handlers for |web_contents|.
275 // See DevToolsWindow::InterceptPageBeforeUnload for details.
276 if (!DevToolsWindow::InterceptPageBeforeUnload(web_contents))
277 web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
240 } else { 278 } else {
241 ClearUnloadState(web_contents, true); 279 ClearUnloadState(web_contents, true);
242 } 280 }
243 } else if (is_calling_before_unload_handlers()) { 281 } else if (is_calling_before_unload_handlers()) {
244 on_close_confirmed_.Run(true); 282 on_close_confirmed_.Run(true);
245 } else if (!tabs_needing_unload_fired_.empty()) { 283 } else if (!tabs_needing_unload_fired_.empty()) {
246 // We've finished firing all beforeunload events and can proceed with unload 284 // We've finished firing all beforeunload events and can proceed with unload
247 // events. 285 // events.
248 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting 286 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
249 // somewhere around here so that we have accurate measurements of shutdown 287 // somewhere around here so that we have accurate measurements of shutdown
(...skipping 17 matching lines...) Expand all
267 bool UnloadController::HasCompletedUnloadProcessing() const { 305 bool UnloadController::HasCompletedUnloadProcessing() const {
268 return is_attempting_to_close_browser_ && 306 return is_attempting_to_close_browser_ &&
269 tabs_needing_before_unload_fired_.empty() && 307 tabs_needing_before_unload_fired_.empty() &&
270 tabs_needing_unload_fired_.empty(); 308 tabs_needing_unload_fired_.empty();
271 } 309 }
272 310
273 void UnloadController::CancelWindowClose() { 311 void UnloadController::CancelWindowClose() {
274 // Closing of window can be canceled from a beforeunload handler. 312 // Closing of window can be canceled from a beforeunload handler.
275 DCHECK(is_attempting_to_close_browser_); 313 DCHECK(is_attempting_to_close_browser_);
276 tabs_needing_before_unload_fired_.clear(); 314 tabs_needing_before_unload_fired_.clear();
315 for (UnloadListenerSet::iterator it = tabs_needing_unload_fired_.begin();
316 it != tabs_needing_unload_fired_.end(); ++it) {
317 DevToolsWindow::OnPageCloseCanceled(*it);
318 }
277 tabs_needing_unload_fired_.clear(); 319 tabs_needing_unload_fired_.clear();
278 if (is_calling_before_unload_handlers()) { 320 if (is_calling_before_unload_handlers()) {
279 base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_; 321 base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_;
280 on_close_confirmed_.Reset(); 322 on_close_confirmed_.Reset();
281 on_close_confirmed.Run(false); 323 on_close_confirmed.Run(false);
282 } 324 }
283 is_attempting_to_close_browser_ = false; 325 is_attempting_to_close_browser_ = false;
284 326
285 content::NotificationService::current()->Notify( 327 content::NotificationService::current()->Notify(
286 chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 328 chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
(...skipping 24 matching lines...) Expand all
311 } else { 353 } else {
312 base::MessageLoop::current()->PostTask( 354 base::MessageLoop::current()->PostTask(
313 FROM_HERE, 355 FROM_HERE,
314 base::Bind(&UnloadController::ProcessPendingTabs, 356 base::Bind(&UnloadController::ProcessPendingTabs,
315 weak_factory_.GetWeakPtr())); 357 weak_factory_.GetWeakPtr()));
316 } 358 }
317 } 359 }
318 } 360 }
319 361
320 } // namespace chrome 362 } // namespace chrome
OLDNEW
« chrome/browser/devtools/devtools_window.h ('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