OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/web_modal/web_contents_modal_dialog_manager.h" | 5 #include "components/web_modal/web_contents_modal_dialog_manager.h" |
6 | 6 |
7 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" | 7 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" |
8 #include "content/public/browser/navigation_details.h" | 8 #include "content/public/browser/navigation_details.h" |
9 #include "content/public/browser/navigation_entry.h" | 9 #include "content/public/browser/navigation_entry.h" |
10 #include "content/public/browser/notification_details.h" | 10 #include "content/public/browser/notification_details.h" |
11 #include "content/public/browser/notification_source.h" | 11 #include "content/public/browser/notification_source.h" |
12 #include "content/public/browser/notification_types.h" | 12 #include "content/public/browser/notification_types.h" |
13 #include "content/public/browser/render_view_host.h" | 13 #include "content/public/browser/render_view_host.h" |
14 #include "content/public/browser/web_contents.h" | 14 #include "content/public/browser/web_contents.h" |
15 #include "content/public/browser/web_contents_view.h" | 15 #include "content/public/browser/web_contents_view.h" |
16 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | |
17 | 16 |
18 using content::WebContents; | 17 using content::WebContents; |
19 | 18 |
20 DEFINE_WEB_CONTENTS_USER_DATA_KEY(web_modal::WebContentsModalDialogManager); | 19 DEFINE_WEB_CONTENTS_USER_DATA_KEY(web_modal::WebContentsModalDialogManager); |
21 | 20 |
22 namespace web_modal { | 21 namespace web_modal { |
23 | 22 |
24 WebContentsModalDialogManager::~WebContentsModalDialogManager() { | 23 WebContentsModalDialogManager::~WebContentsModalDialogManager() { |
25 DCHECK(child_dialogs_.empty()); | 24 DCHECK(child_dialogs_.empty()); |
26 } | 25 } |
27 | 26 |
28 void WebContentsModalDialogManager::ShowDialog( | 27 void WebContentsModalDialogManager::ShowDialog( |
29 NativeWebContentsModalDialog dialog) { | 28 NativeWebContentsModalDialog dialog) { |
30 child_dialogs_.push_back(dialog); | 29 child_dialogs_.push_back(DialogState(dialog)); |
31 | 30 |
32 native_manager_->ManageDialog(dialog); | 31 native_manager_->ManageDialog(dialog); |
33 | 32 |
34 if (child_dialogs_.size() == 1) { | 33 if (child_dialogs_.size() == 1) { |
35 if (delegate_ && delegate_->IsWebContentsVisible(web_contents())) | 34 if (delegate_ && delegate_->IsWebContentsVisible(web_contents())) |
36 native_manager_->ShowDialog(dialog); | 35 native_manager_->ShowDialog(dialog); |
37 BlockWebContentsInteraction(true); | 36 BlockWebContentsInteraction(true); |
38 } | 37 } |
39 } | 38 } |
40 | 39 |
41 bool WebContentsModalDialogManager::IsShowingDialog() const { | 40 bool WebContentsModalDialogManager::IsShowingDialog() const { |
42 return !child_dialogs_.empty(); | 41 return !child_dialogs_.empty(); |
43 } | 42 } |
44 | 43 |
45 void WebContentsModalDialogManager::FocusTopmostDialog() { | 44 void WebContentsModalDialogManager::FocusTopmostDialog() { |
46 DCHECK(!child_dialogs_.empty()); | 45 DCHECK(!child_dialogs_.empty()); |
47 native_manager_->FocusDialog(child_dialogs_.front()); | 46 native_manager_->FocusDialog(child_dialogs_.front().dialog); |
| 47 } |
| 48 |
| 49 void WebContentsModalDialogManager::SetInhibitCloseOnLoadStart( |
| 50 NativeWebContentsModalDialog dialog, |
| 51 bool inhibit) { |
| 52 WebContentsModalDialogList::iterator loc = FindDialogState(dialog); |
| 53 DCHECK(loc != child_dialogs_.end()); |
| 54 loc->inhibit_close_on_load_start = true; |
48 } | 55 } |
49 | 56 |
50 content::WebContents* WebContentsModalDialogManager::GetWebContents() const { | 57 content::WebContents* WebContentsModalDialogManager::GetWebContents() const { |
51 return web_contents(); | 58 return web_contents(); |
52 } | 59 } |
53 | 60 |
54 void WebContentsModalDialogManager::WillClose( | 61 void WebContentsModalDialogManager::WillClose( |
55 NativeWebContentsModalDialog dialog) { | 62 NativeWebContentsModalDialog dialog) { |
56 WebContentsModalDialogList::iterator i( | 63 WebContentsModalDialogList::iterator i = FindDialogState(dialog); |
57 std::find(child_dialogs_.begin(), child_dialogs_.end(), dialog)); | |
58 | 64 |
59 // The Views tab contents modal dialog calls WillClose twice. Ignore the | 65 // The Views tab contents modal dialog calls WillClose twice. Ignore the |
60 // second invocation. | 66 // second invocation. |
61 if (i == child_dialogs_.end()) | 67 if (i == child_dialogs_.end()) |
62 return; | 68 return; |
63 | 69 |
64 bool removed_topmost_dialog = i == child_dialogs_.begin(); | 70 bool removed_topmost_dialog = i == child_dialogs_.begin(); |
65 child_dialogs_.erase(i); | 71 child_dialogs_.erase(i); |
66 if (!child_dialogs_.empty() && removed_topmost_dialog && | 72 if (!child_dialogs_.empty() && removed_topmost_dialog && |
67 !closing_all_dialogs_) | 73 !closing_all_dialogs_) |
68 native_manager_->ShowDialog(child_dialogs_.front()); | 74 native_manager_->ShowDialog(child_dialogs_.front().dialog); |
69 | 75 |
70 BlockWebContentsInteraction(!child_dialogs_.empty()); | 76 BlockWebContentsInteraction(!child_dialogs_.empty()); |
71 } | 77 } |
72 | 78 |
73 void WebContentsModalDialogManager::Observe( | 79 void WebContentsModalDialogManager::Observe( |
74 int type, | 80 int type, |
75 const content::NotificationSource& source, | 81 const content::NotificationSource& source, |
76 const content::NotificationDetails& details) { | 82 const content::NotificationDetails& details) { |
77 DCHECK(type == content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED); | 83 if (type == content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED) { |
| 84 if (child_dialogs_.empty()) |
| 85 return; |
78 | 86 |
79 if (child_dialogs_.empty()) | 87 bool visible = *content::Details<bool>(details).ptr(); |
80 return; | 88 if (visible) |
81 | 89 native_manager_->ShowDialog(child_dialogs_.front().dialog); |
82 bool visible = *content::Details<bool>(details).ptr(); | 90 else |
83 if (visible) | 91 native_manager_->HideDialog(child_dialogs_.front().dialog); |
84 native_manager_->ShowDialog(child_dialogs_.front()); | 92 } else if (type == content::NOTIFICATION_LOAD_START) { |
85 else | 93 if (!child_dialogs_.empty() && |
86 native_manager_->HideDialog(child_dialogs_.front()); | 94 !child_dialogs_.front().inhibit_close_on_load_start) |
| 95 native_manager_->CloseDialog(child_dialogs_.front().dialog); |
| 96 } |
87 } | 97 } |
88 | 98 |
89 WebContentsModalDialogManager::WebContentsModalDialogManager( | 99 WebContentsModalDialogManager::WebContentsModalDialogManager( |
90 content::WebContents* web_contents) | 100 content::WebContents* web_contents) |
91 : content::WebContentsObserver(web_contents), | 101 : content::WebContentsObserver(web_contents), |
92 delegate_(NULL), | 102 delegate_(NULL), |
93 native_manager_(CreateNativeManager(this)), | 103 native_manager_(CreateNativeManager(this)), |
94 closing_all_dialogs_(false) { | 104 closing_all_dialogs_(false) { |
95 DCHECK(native_manager_); | 105 DCHECK(native_manager_); |
| 106 content::NavigationController* controller = |
| 107 &GetWebContents()->GetController(); |
| 108 registrar_.Add(this, |
| 109 content::NOTIFICATION_LOAD_START, |
| 110 content::Source<content::NavigationController>(controller)); |
96 registrar_.Add(this, | 111 registrar_.Add(this, |
97 content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED, | 112 content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED, |
98 content::Source<content::WebContents>(web_contents)); | 113 content::Source<content::WebContents>(web_contents)); |
99 } | 114 } |
100 | 115 |
| 116 WebContentsModalDialogManager::DialogState::DialogState( |
| 117 NativeWebContentsModalDialog dialog) |
| 118 : dialog(dialog), |
| 119 inhibit_close_on_load_start(false) { |
| 120 } |
| 121 |
| 122 WebContentsModalDialogManager::WebContentsModalDialogList::iterator |
| 123 WebContentsModalDialogManager::FindDialogState( |
| 124 NativeWebContentsModalDialog dialog) { |
| 125 WebContentsModalDialogList::iterator i; |
| 126 for (i = child_dialogs_.begin(); i != child_dialogs_.end(); ++i) { |
| 127 if (i->dialog == dialog) |
| 128 break; |
| 129 } |
| 130 |
| 131 return i; |
| 132 } |
| 133 |
101 void WebContentsModalDialogManager::BlockWebContentsInteraction(bool blocked) { | 134 void WebContentsModalDialogManager::BlockWebContentsInteraction(bool blocked) { |
102 WebContents* contents = web_contents(); | 135 WebContents* contents = web_contents(); |
103 if (!contents) { | 136 if (!contents) { |
104 // The WebContents has already disconnected. | 137 // The WebContents has already disconnected. |
105 return; | 138 return; |
106 } | 139 } |
107 | 140 |
108 // RenderViewHost may be NULL during shutdown. | 141 // RenderViewHost may be NULL during shutdown. |
109 content::RenderViewHost* host = contents->GetRenderViewHost(); | 142 content::RenderViewHost* host = contents->GetRenderViewHost(); |
110 if (host) | 143 if (host) |
111 host->SetIgnoreInputEvents(blocked); | 144 host->SetIgnoreInputEvents(blocked); |
112 if (delegate_) | 145 if (delegate_) |
113 delegate_->SetWebContentsBlocked(contents, blocked); | 146 delegate_->SetWebContentsBlocked(contents, blocked); |
114 } | 147 } |
115 | 148 |
116 void WebContentsModalDialogManager::CloseAllDialogs() { | 149 void WebContentsModalDialogManager::CloseAllDialogs() { |
117 closing_all_dialogs_ = true; | 150 closing_all_dialogs_ = true; |
118 | 151 |
119 // Clear out any dialogs since we are leaving this page entirely. | 152 // Clear out any dialogs since we are leaving this page entirely. |
120 while (!child_dialogs_.empty()) | 153 while (!child_dialogs_.empty()) |
121 native_manager_->CloseDialog(child_dialogs_.front()); | 154 native_manager_->CloseDialog(child_dialogs_.front().dialog); |
122 | 155 |
123 closing_all_dialogs_ = false; | 156 closing_all_dialogs_ = false; |
124 } | 157 } |
125 | 158 |
126 void WebContentsModalDialogManager::DidNavigateMainFrame( | |
127 const content::LoadCommittedDetails& details, | |
128 const content::FrameNavigateParams& params) { | |
129 // Close constrained windows if necessary. | |
130 if (!net::registry_controlled_domains::SameDomainOrHost( | |
131 details.previous_url, details.entry->GetURL(), | |
132 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)) | |
133 CloseAllDialogs(); | |
134 } | |
135 | |
136 void WebContentsModalDialogManager::DidGetIgnoredUIEvent() { | 159 void WebContentsModalDialogManager::DidGetIgnoredUIEvent() { |
137 if (!child_dialogs_.empty()) | 160 if (!child_dialogs_.empty()) |
138 native_manager_->FocusDialog(child_dialogs_.front()); | 161 native_manager_->FocusDialog(child_dialogs_.front().dialog); |
139 } | 162 } |
140 | 163 |
141 void WebContentsModalDialogManager::WebContentsDestroyed(WebContents* tab) { | 164 void WebContentsModalDialogManager::WebContentsDestroyed(WebContents* tab) { |
142 // First cleanly close all child dialogs. | 165 // First cleanly close all child dialogs. |
143 // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked | 166 // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked |
144 // some of these to close. CloseAllDialogs is async, so it might get called | 167 // some of these to close. CloseAllDialogs is async, so it might get called |
145 // twice before it runs. | 168 // twice before it runs. |
146 CloseAllDialogs(); | 169 CloseAllDialogs(); |
147 } | 170 } |
148 | 171 |
149 } // namespace web_modal | 172 } // namespace web_modal |
OLD | NEW |