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