Index: chrome/browser/ui/unload_detached_handler.cc |
diff --git a/chrome/browser/ui/unload_detached_handler.cc b/chrome/browser/ui/unload_detached_handler.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0cf1c3b1115bb9c644790a8d59d3f3501b6735ca |
--- /dev/null |
+++ b/chrome/browser/ui/unload_detached_handler.cc |
@@ -0,0 +1,88 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/ui/unload_detached_handler.h" |
+ |
+#include "base/message_loop.h" |
+#include "chrome/browser/ui/tab_contents/tab_contents.h" |
+#include "chrome/browser/ui/tabs/tab_strip_model.h" |
+#include "content/public/browser/web_contents.h" |
+#include "content/public/browser/web_contents_delegate.h" |
+ |
+namespace chrome { |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// WebContentsDelegate implementation. This owns the TabContents supplied to the |
+// constructor. |
+class UnloadDetachedHandler::WebContentsDelegateImpl |
+ : public content::WebContentsDelegate { |
+ public: |
+ WebContentsDelegateImpl(UnloadDetachedHandler* handler, |
+ TabContents* tab_contents) |
+ : handler_(handler), |
+ tab_contents_(tab_contents) { |
+ tab_contents->web_contents()->SetDelegate(this); |
+ } |
+ |
+ virtual bool ShouldSuppressDialogs() OVERRIDE { |
+ return true; // Return true so dialogs are suppressed. |
+ } |
+ |
+ virtual void CloseContents(content::WebContents* source) OVERRIDE { |
+ handler_->Destroy(this); |
+ } |
+ |
+ private: |
+ UnloadDetachedHandler* const handler_; |
+ scoped_ptr<TabContents> tab_contents_; |
+ |
+ DISALLOW_IMPLICIT_CONSTRUCTORS(WebContentsDelegateImpl); |
+}; |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// UnloadDetachedHandler implementation. |
+ |
+UnloadDetachedHandler::UnloadDetachedHandler(const TabsClosedCallback& callback) |
+ : tabs_closed_callback_(callback) { |
+} |
+ |
+UnloadDetachedHandler::~UnloadDetachedHandler() { |
+} |
+ |
+bool UnloadDetachedHandler::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 it is empty. |
+ // And, the browser would 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); |
+ delegates_.push_back(new WebContentsDelegateImpl(this, tab_contents)); |
+ web_contents->OnUnloadDetachedStarted(); |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+bool UnloadDetachedHandler::HasTabs() { |
+ return !delegates_.empty(); |
+} |
+ |
+void UnloadDetachedHandler::Destroy(WebContentsDelegateImpl* delegate) { |
+ ScopedVector<WebContentsDelegateImpl>::iterator i = |
+ std::find(delegates_.begin(), delegates_.end(), delegate); |
+ DCHECK(i != delegates_.end()); |
+ |
+ // The delegate's method is a caller on the stack, so schedule the deletion |
+ // for later. |
+ delegates_.weak_erase(i); |
+ MessageLoop::current()->DeleteSoon(FROM_HERE, delegate); |
+ |
+ tabs_closed_callback_.Run(); |
+} |
+ |
+} // namespace chrome |