1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/instant/instant_unload_handler.h" 6 7 #include "chrome/browser/ui/browser.h" 8 #include "chrome/browser/ui/browser_navigator.h" 9 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 10 #include "content/browser/renderer_host/render_view_host.h" 11 #include "content/browser/tab_contents/tab_contents.h" 12 #include "content/browser/tab_contents/tab_contents_delegate.h" 13 14 // TabContentsDelegate implementation. This owns the TabContents supplied to the 15 // constructor. 16 class InstantUnloadHandler::TabContentsDelegateImpl 17 : public TabContentsDelegate { 18 public: 19 TabContentsDelegateImpl(InstantUnloadHandler* handler, 20 TabContentsWrapper* tab_contents, 21 int index) 22 : handler_(handler), 23 tab_contents_(tab_contents), 24 index_(index) { 25 tab_contents->tab_contents()->set_delegate(this); 26 } 27 28 ~TabContentsDelegateImpl() { 29 } 30 31 // Releases ownership of the TabContentsWrapper to the caller. 32 TabContentsWrapper* ReleaseTab() { 33 TabContentsWrapper* tab = tab_contents_.release(); 34 tab->tab_contents()->set_delegate(NULL); 35 return tab; 36 } 37 38 // See description above field. 39 int index() const { return index_; } 40 41 // TabContentsDelegate overrides: 42 virtual void WillRunBeforeUnloadConfirm() { 43 handler_->Activate(this); 44 } 45 46 virtual bool ShouldSuppressDialogs() { 47 return true; // Return true so dialogs are suppressed. 48 } 49 50 virtual void CloseContents(TabContents* source) { 51 handler_->Destroy(this); 52 } 53 54 // All of the following are overriden to do nothing (they are pure 55 // virtual). When we're attemping to close the tab, none of this matters. 56 virtual void OpenURLFromTab(TabContents* source, 57 const GURL& url, const GURL& referrer, 58 WindowOpenDisposition disposition, 59 PageTransition::Type transition) {} 60 virtual void NavigationStateChanged(const TabContents* source, 61 unsigned changed_flags) {} 62 virtual void AddNewContents(TabContents* source, 63 TabContents* new_contents, 64 WindowOpenDisposition disposition, 65 const gfx::Rect& initial_pos, 66 bool user_gesture) {} 67 virtual void ActivateContents(TabContents* contents) {} 68 virtual void DeactivateContents(TabContents* contents) {} 69 virtual void LoadingStateChanged(TabContents* source) {} 70 virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {} 71 virtual void UpdateTargetURL(TabContents* source, const GURL& url) {} 72 73 private: 74 InstantUnloadHandler* handler_; 75 scoped_ptr<TabContentsWrapper> tab_contents_; 76 77 // The index |tab_contents_| was originally at. If we add the tab back we add 78 // it at this index. 79 const int index_; 80 81 DISALLOW_COPY_AND_ASSIGN(TabContentsDelegateImpl); 82 }; 83 84 InstantUnloadHandler::InstantUnloadHandler(Browser* browser) 85 : browser_(browser) { 86 } 87 88 InstantUnloadHandler::~InstantUnloadHandler() { 89 } 90 91 void InstantUnloadHandler::RunUnloadListenersOrDestroy(TabContentsWrapper* tab, 92 int index) { 93 if (!tab->tab_contents()->NeedToFireBeforeUnload()) { 94 // Tab doesn't have any before unload listeners and can be safely deleted. 95 delete tab; 96 return; 97 } 98 99 // Tab has before unload listener. Install a delegate and fire the before 100 // unload listener. 101 TabContentsDelegateImpl* delegate = 102 new TabContentsDelegateImpl(this, tab, index); 103 delegates_.push_back(delegate); 104 // TODO: decide if we really want false here. false is used for tab closes, 105 // and is needed so that the tab correctly closes but it doesn't really match 106 // what's logically happening. 107 tab->tab_contents()->render_view_host()->FirePageBeforeUnload(false); 108 } 109 110 void InstantUnloadHandler::Activate(TabContentsDelegateImpl* delegate) { 111 // Take ownership of the TabContents from the delegate. 112 TabContentsWrapper* tab = delegate->ReleaseTab(); 113 browser::NavigateParams params(browser_, tab); 114 params.disposition = NEW_FOREGROUND_TAB; 115 params.tabstrip_index = delegate->index(); 116 117 // Remove (and delete) the delegate. 118 ScopedVector<TabContentsDelegateImpl>::iterator i = 119 std::find(delegates_.begin(), delegates_.end(), delegate); 120 DCHECK(i != delegates_.end()); 121 delegates_.erase(i); 122 delegate = NULL; 123 124 // Add the tab back in. 125 browser::Navigate(¶ms); 126 } 127 128 void InstantUnloadHandler::Destroy(TabContentsDelegateImpl* delegate) { 129 ScopedVector<TabContentsDelegateImpl>::iterator i = 130 std::find(delegates_.begin(), delegates_.end(), delegate); 131 DCHECK(i != delegates_.end()); 132 delegates_.erase(i); 133 } 134