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:
TabContentsDelegateImpl(InstantUnloadHandler * handler,TabContentsWrapper * tab_contents,int index)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
~TabContentsDelegateImpl()28 ~TabContentsDelegateImpl() {
29 }
30
31 // Releases ownership of the TabContentsWrapper to the caller.
ReleaseTab()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.
index() const39 int index() const { return index_; }
40
41 // TabContentsDelegate overrides:
WillRunBeforeUnloadConfirm()42 virtual void WillRunBeforeUnloadConfirm() {
43 handler_->Activate(this);
44 }
45
ShouldSuppressDialogs()46 virtual bool ShouldSuppressDialogs() {
47 return true; // Return true so dialogs are suppressed.
48 }
49
CloseContents(TabContents * source)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.
OpenURLFromTab(TabContents * source,const GURL & url,const GURL & referrer,WindowOpenDisposition disposition,PageTransition::Type transition)56 virtual void OpenURLFromTab(TabContents* source,
57 const GURL& url, const GURL& referrer,
58 WindowOpenDisposition disposition,
59 PageTransition::Type transition) {}
NavigationStateChanged(const TabContents * source,unsigned changed_flags)60 virtual void NavigationStateChanged(const TabContents* source,
61 unsigned changed_flags) {}
AddNewContents(TabContents * source,TabContents * new_contents,WindowOpenDisposition disposition,const gfx::Rect & initial_pos,bool user_gesture)62 virtual void AddNewContents(TabContents* source,
63 TabContents* new_contents,
64 WindowOpenDisposition disposition,
65 const gfx::Rect& initial_pos,
66 bool user_gesture) {}
ActivateContents(TabContents * contents)67 virtual void ActivateContents(TabContents* contents) {}
DeactivateContents(TabContents * contents)68 virtual void DeactivateContents(TabContents* contents) {}
LoadingStateChanged(TabContents * source)69 virtual void LoadingStateChanged(TabContents* source) {}
MoveContents(TabContents * source,const gfx::Rect & pos)70 virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {}
UpdateTargetURL(TabContents * source,const GURL & url)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
InstantUnloadHandler(Browser * browser)84 InstantUnloadHandler::InstantUnloadHandler(Browser* browser)
85 : browser_(browser) {
86 }
87
~InstantUnloadHandler()88 InstantUnloadHandler::~InstantUnloadHandler() {
89 }
90
RunUnloadListenersOrDestroy(TabContentsWrapper * tab,int index)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
Activate(TabContentsDelegateImpl * delegate)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
Destroy(TabContentsDelegateImpl * delegate)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