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

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

Issue 11016023: Quickly close tabs/window with long-running unload handlers. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Make UnloadDetachedHandler a delegate for all detached tabs. Created 8 years, 2 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/unload_controller.h ('k') | chrome/browser/unload_browsertest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/unload_controller.cc
diff --git a/chrome/browser/ui/unload_controller.cc b/chrome/browser/ui/unload_controller.cc
index bc8c1805360beb6682c6f656a5baf12f41a4aa42..4c4a37aad4278f9e750ffb188b92b44edc9bc587 100644
--- a/chrome/browser/ui/unload_controller.cc
+++ b/chrome/browser/ui/unload_controller.cc
@@ -4,6 +4,10 @@
#include "chrome/browser/ui/unload_controller.h"
+#include <map>
+
+#include "base/callback.h"
+#include "base/memory/scoped_vector.h"
#include "base/message_loop.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
@@ -15,15 +19,84 @@
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
namespace chrome {
+typedef base::Callback<void(void)> DetachedTabsClosedCallback;
+typedef std::map<content::WebContents*, TabContents*> DetachedTabsMap;
Ben Goodger (Google) 2012/10/31 18:28:32 this you can put at the start of the private area
+
+////////////////////////////////////////////////////////////////////////////////
+// UnloadDetachedHandler is used to close tabs quickly, http://crbug.com/142458.
+// - Allows unload handlers to run in the background.
+// - Comes into play after the beforeunload handlers (if any) have run.
+// - Does not close the tabs; it holds tabs while they are closed.
+//
+// TODO(slamm): Support closes that destroy the browser: last tab close, window.
+// http://crbug.com/156896
+// TODO(slamm): Hide unload time from the user for cross-process navigations.
+// http://crbug.com/156958
+class UnloadDetachedHandler : public content::WebContentsDelegate {
+ public:
+ explicit UnloadDetachedHandler(const DetachedTabsClosedCallback& callback)
+ : tabs_closed_callback_(callback) { }
+ ~UnloadDetachedHandler() { }
Ben Goodger (Google) 2012/10/31 18:28:32 virtual dtor
+
+ // Returns true if it succeeds.
+ bool DetachWebContents(TabStripModel* tab_strip_model,
+ content::WebContents* web_contents) {
+ if (tab_strip_model->count() > 1) {
+ // Only allow tab to be detached if it is not the last one.
+ // Otherwise, the tab_strip_model would notify the browser that
+ // the strip is empty, and cause it to close without waiting for
+ // the unload handlers.
+ int index = tab_strip_model->GetIndexOfWebContents(web_contents);
+ if (index != TabStripModel::kNoTab &&
+ web_contents->NeedToFireBeforeUnload()) {
+ TabContents* tab_contents = tab_strip_model->DetachTabContentsAt(index);
+ detached_tabs_[web_contents] = tab_contents;
+ web_contents->SetDelegate(this);
+ web_contents->OnUnloadDetachedStarted();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool HasTabs() const {
+ return !detached_tabs_.empty();
+ }
+
+ private:
+ // WebContentsDelegate implementation.
+ virtual bool ShouldSuppressDialogs() OVERRIDE {
+ return true; // Return true so dialogs are suppressed.
+ }
+ virtual void CloseContents(content::WebContents* source) OVERRIDE {
+ DetachedTabsMap::iterator it = detached_tabs_.find(source);
+ TabContents* tab_contents = (*it).second;
Ben Goodger (Google) 2012/10/31 18:28:32 So, Avi is in the process of removing TC from Chro
+ delete tab_contents;
+ detached_tabs_.erase(it);
+ tabs_closed_callback_.Run();
+ }
+
+ const DetachedTabsClosedCallback tabs_closed_callback_;
+ DetachedTabsMap detached_tabs_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(UnloadDetachedHandler);
+};
+
+
////////////////////////////////////////////////////////////////////////////////
// UnloadController, public:
UnloadController::UnloadController(Browser* browser)
: browser_(browser),
is_attempting_to_close_browser_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ unload_detached_handler_(new UnloadDetachedHandler(
+ base::Bind(&UnloadController::ProcessPendingTabs,
+ base::Unretained(this))))),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
browser_->tab_strip_model()->AddObserver(this);
}
@@ -43,8 +116,14 @@ bool UnloadController::CanCloseContents(content::WebContents* contents) {
bool UnloadController::BeforeUnloadFired(content::WebContents* contents,
bool proceed) {
if (!is_attempting_to_close_browser_) {
- if (!proceed)
+ if (proceed) {
+ // No more dialogs are possible, so remove the tab and finish
+ // running unload listeners asynchrounously.
+ unload_detached_handler_->DetachWebContents(browser_->tab_strip_model(),
+ contents);
+ } else {
contents->SetClosedByUserGesture(false);
+ }
return proceed;
}
@@ -75,7 +154,7 @@ bool UnloadController::ShouldCloseWindow() {
is_attempting_to_close_browser_ = true;
if (!TabsNeedBeforeUnloadFired())
- return true;
+ return !unload_detached_handler_->HasTabs();
ProcessPendingTabs();
return false;
@@ -182,6 +261,7 @@ void UnloadController::ProcessPendingTabs() {
// 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->OnCloseStarted();
web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
} else {
ClearUnloadState(web_contents, true);
@@ -199,7 +279,9 @@ void UnloadController::ProcessPendingTabs() {
// 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();
+ if (!unload_detached_handler_->HasTabs()) {
Ben Goodger (Google) 2012/10/31 18:28:32 nit, no braces.
+ web_contents->GetRenderViewHost()->ClosePage();
+ }
} else {
ClearUnloadState(web_contents, true);
}
« no previous file with comments | « chrome/browser/ui/unload_controller.h ('k') | chrome/browser/unload_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698