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

Unified Diff: chrome/browser/ui/browser.cc

Issue 10749002: Move unload handling off Browser onto its own class, UnloadController. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 5 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/browser.h ('k') | chrome/browser/ui/unload_controller.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/browser.cc
===================================================================
--- chrome/browser/ui/browser.cc (revision 145675)
+++ chrome/browser/ui/browser.cc (working copy)
@@ -135,6 +135,7 @@
#include "chrome/browser/ui/tabs/dock_info.h"
#include "chrome/browser/ui/tabs/tab_menu_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/unload_controller.h"
#include "chrome/browser/ui/web_applications/web_app_ui.h"
#include "chrome/browser/ui/webui/feedback_ui.h"
#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
@@ -302,10 +303,11 @@
tab_strip_model_(new TabStripModel(this, profile))),
app_type_(APP_TYPE_HOST),
chrome_updater_factory_(this),
- is_attempting_to_close_browser_(false),
cancel_download_confirmation_state_(NOT_PROMPTED),
initial_show_state_(ui::SHOW_STATE_DEFAULT),
is_session_restore_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ unload_controller_(new chrome::UnloadController(this))),
weak_factory_(this),
ALLOW_THIS_IN_INITIALIZER_LIST(
content_setting_bubble_model_delegate_(
@@ -575,16 +577,11 @@
if (!CanCloseWithInProgressDownloads())
return false;
- if (HasCompletedUnloadProcessing())
- return true;
+ return unload_controller_->ShouldCloseWindow();
+}
- is_attempting_to_close_browser_ = true;
-
- if (!TabsNeedBeforeUnloadFired())
- return true;
-
- ProcessPendingTabs();
- return false;
+bool Browser::IsAttemptingToCloseBrowser() const {
+ return unload_controller_->is_attempting_to_close_browser();
}
void Browser::OnWindowClosing() {
@@ -669,7 +666,7 @@
DCHECK(num_downloads_blocking);
*num_downloads_blocking = 0;
- if (is_attempting_to_close_browser_)
+ if (IsAttemptingToCloseBrowser())
return DOWNLOAD_CLOSE_OK;
// If we're not running a full browser process with a profile manager
@@ -689,10 +686,9 @@
iter != BrowserList::end(); ++iter) {
// Don't count this browser window or any other in the process of closing.
Browser* const browser = *iter;
- // Check is_attempting_to_close_browser_ as window closing may be
- // delayed, and windows that are in the process of closing don't
- // count against our totals.
- if (browser == this || browser->is_attempting_to_close_browser_)
+ // Window closing may be delayed, and windows that are in the process of
+ // closing don't count against our totals.
+ if (browser == this || browser->IsAttemptingToCloseBrowser())
continue;
if ((*iter)->profile() == profile())
@@ -1177,11 +1173,6 @@
// won't start if the page is loading.
LoadingStateChanged(contents->web_contents());
- // If the tab crashes in the beforeunload or unload handler, it won't be
- // able to ack. But we know we can close it.
- registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
- content::Source<WebContents>(contents->web_contents()));
-
registrar_.Add(this, content::NOTIFICATION_INTERSTITIAL_ATTACHED,
content::Source<WebContents>(contents->web_contents()));
@@ -1350,9 +1341,6 @@
// still present.
MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&Browser::CloseFrame, weak_factory_.GetWeakPtr()));
- // Set is_attempting_to_close_browser_ here, so that extensions, etc, do not
- // attempt to add tabs to the browser before it closes.
- is_attempting_to_close_browser_ = true;
}
bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
@@ -1381,14 +1369,7 @@
}
bool Browser::TabsNeedBeforeUnloadFired() {
- if (tabs_needing_before_unload_fired_.empty()) {
- for (int i = 0; i < tab_count(); ++i) {
- WebContents* contents = chrome::GetTabContentsAt(this, i)->web_contents();
- if (contents->NeedToFireBeforeUnload())
- tabs_needing_before_unload_fired_.insert(contents);
- }
- }
- return !tabs_needing_before_unload_fired_.empty();
+ return unload_controller_->TabsNeedBeforeUnloadFired();
}
bool Browser::IsFullscreenForTabOrPending() const {
@@ -1512,16 +1493,8 @@
}
void Browser::CloseContents(WebContents* source) {
- if (is_attempting_to_close_browser_) {
- // If we're trying to close the browser, just clear the state related to
- // waiting for unload to fire. Don't actually try to close the tab as it
- // will go down the slow shutdown path instead of the fast path of killing
- // all the renderer processes.
- ClearUnloadState(source, true);
- return;
- }
-
- chrome::CloseWebContents(this, source);
+ if (unload_controller_->CanCloseContents(source))
+ chrome::CloseWebContents(this, source);
}
void Browser::MoveContents(WebContents* source, const gfx::Rect& pos) {
@@ -1587,33 +1560,8 @@
void Browser::BeforeUnloadFired(WebContents* web_contents,
bool proceed,
bool* proceed_to_fire_unload) {
- if (!is_attempting_to_close_browser_) {
- *proceed_to_fire_unload = proceed;
- if (!proceed)
- web_contents->SetClosedByUserGesture(false);
- return;
- }
-
- if (!proceed) {
- CancelWindowClose();
- *proceed_to_fire_unload = false;
- web_contents->SetClosedByUserGesture(false);
- return;
- }
-
- if (RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents)) {
- // Now that beforeunload has fired, put the tab on the queue to fire
- // unload.
- tabs_needing_unload_fired_.insert(web_contents);
- ProcessPendingTabs();
- // We want to handle firing the unload event ourselves since we want to
- // fire all the beforeunload events before attempting to fire the unload
- // events should the user cancel closing the browser.
- *proceed_to_fire_unload = false;
- return;
- }
-
- *proceed_to_fire_unload = true;
+ *proceed_to_fire_unload =
+ unload_controller_->BeforeUnloadFired(web_contents, proceed);
}
void Browser::SetFocusToLocationBar(bool select_all) {
@@ -2041,15 +1989,6 @@
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
- case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED:
- if (is_attempting_to_close_browser_) {
- // Pass in false so that we delay processing. We need to delay the
- // processing as it may close the tab, which is currently on the call
- // stack above us.
- ClearUnloadState(content::Source<WebContents>(source).ptr(), false);
- }
- break;
-
case content::NOTIFICATION_SSL_VISIBLE_STATE_CHANGED:
// When the current tab's SSL state changes, we need to update the URL
// bar to reflect the new state. Note that it's possible for the selected
@@ -2396,102 +2335,6 @@
}
///////////////////////////////////////////////////////////////////////////////
-// Browser, OnBeforeUnload handling (private):
-
-void Browser::ProcessPendingTabs() {
- if (!is_attempting_to_close_browser_) {
- // Because we might invoke this after a delay it's possible for the value of
- // is_attempting_to_close_browser_ to have changed since we scheduled the
- // task.
- return;
- }
-
- if (HasCompletedUnloadProcessing()) {
- // We've finished all the unload events and can proceed to close the
- // browser.
- OnWindowClosing();
- return;
- }
-
- // Process beforeunload tabs first. When that queue is empty, process
- // unload tabs.
- if (!tabs_needing_before_unload_fired_.empty()) {
- WebContents* web_contents = *(tabs_needing_before_unload_fired_.begin());
- // Null check render_view_host here as this gets called on a PostTask and
- // the tab's render_view_host may have been nulled out.
- if (web_contents->GetRenderViewHost()) {
- web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
- } else {
- ClearUnloadState(web_contents, true);
- }
- } else if (!tabs_needing_unload_fired_.empty()) {
- // We've finished firing all beforeunload events and can proceed with unload
- // events.
- // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
- // somewhere around here so that we have accurate measurements of shutdown
- // time.
- // TODO(ojan): We can probably fire all the unload events in parallel and
- // get a perf benefit from that in the cases where the tab hangs in it's
- // unload handler or takes a long time to page in.
- WebContents* web_contents = *(tabs_needing_unload_fired_.begin());
- // Null check render_view_host here as this gets called on a PostTask and
- // the tab's render_view_host may have been nulled out.
- if (web_contents->GetRenderViewHost()) {
- web_contents->GetRenderViewHost()->ClosePage();
- } else {
- ClearUnloadState(web_contents, true);
- }
- } else {
- NOTREACHED();
- }
-}
-
-bool Browser::HasCompletedUnloadProcessing() const {
- return is_attempting_to_close_browser_ &&
- tabs_needing_before_unload_fired_.empty() &&
- tabs_needing_unload_fired_.empty();
-}
-
-void Browser::CancelWindowClose() {
- // Closing of window can be canceled from a beforeunload handler.
- DCHECK(is_attempting_to_close_browser_);
- tabs_needing_before_unload_fired_.clear();
- tabs_needing_unload_fired_.clear();
- is_attempting_to_close_browser_ = false;
-
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
- content::Source<Browser>(this),
- content::NotificationService::NoDetails());
-}
-
-bool Browser::RemoveFromSet(UnloadListenerSet* set, WebContents* web_contents) {
- DCHECK(is_attempting_to_close_browser_);
-
- UnloadListenerSet::iterator iter =
- std::find(set->begin(), set->end(), web_contents);
- if (iter != set->end()) {
- set->erase(iter);
- return true;
- }
- return false;
-}
-
-void Browser::ClearUnloadState(WebContents* web_contents, bool process_now) {
- if (is_attempting_to_close_browser_) {
- RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents);
- RemoveFromSet(&tabs_needing_unload_fired_, web_contents);
- if (process_now) {
- ProcessPendingTabs();
- } else {
- MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&Browser::ProcessPendingTabs, weak_factory_.GetWeakPtr()));
- }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
// Browser, In-progress download termination handling (private):
bool Browser::CanCloseWithInProgressDownloads() {
@@ -2559,14 +2402,6 @@
find_bar_controller_->ChangeTabContents(NULL);
}
- if (is_attempting_to_close_browser_) {
- // If this is the last tab with unload handlers, then ProcessPendingTabs
- // would call back into the TabStripModel (which is invoking this method on
- // us). Avoid that by passing in false so that the call to
- // ProcessPendingTabs is delayed.
- ClearUnloadState(contents->web_contents(), false);
- }
-
// Stop observing search model changes for this tab.
search_delegate_->OnTabDetached(contents);
@@ -2574,8 +2409,6 @@
content::Source<WebContents>(contents->web_contents()));
registrar_.Remove(this, content::NOTIFICATION_INTERSTITIAL_DETACHED,
content::Source<WebContents>(contents->web_contents()));
- registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
- content::Source<WebContents>(contents->web_contents()));
}
bool Browser::SupportsWindowFeatureImpl(WindowFeature feature,
« no previous file with comments | « chrome/browser/ui/browser.h ('k') | chrome/browser/ui/unload_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698