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
3 // found in the LICENSE file.
5 #include "components/web_modal/web_contents_modal_dialog_manager.h"
7 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
8 #include "content/public/browser/navigation_details.h"
9 #include "content/public/browser/navigation_entry.h"
10 #include "content/public/browser/render_view_host.h"
11 #include "content/public/browser/web_contents.h"
12 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
14 using content::WebContents
;
16 DEFINE_WEB_CONTENTS_USER_DATA_KEY(web_modal::WebContentsModalDialogManager
);
20 WebContentsModalDialogManager::~WebContentsModalDialogManager() {
21 DCHECK(child_dialogs_
.empty());
24 void WebContentsModalDialogManager::SetDelegate(
25 WebContentsModalDialogManagerDelegate
* d
) {
28 for (WebContentsModalDialogList::iterator it
= child_dialogs_
.begin();
29 it
!= child_dialogs_
.end(); it
++) {
30 // Delegate can be NULL on Views/Win32 during tab drag.
31 (*it
)->manager
->HostChanged(d
? d
->GetWebContentsModalDialogHost() : NULL
);
35 void WebContentsModalDialogManager::ShowModalDialog(
36 NativeWebContentsModalDialog dialog
) {
37 scoped_ptr
<SingleWebContentsDialogManager
> mgr(
38 CreateNativeWebModalManager(dialog
, this));
39 ShowDialogWithManager(dialog
, mgr
.Pass());
42 // TODO(gbillock): Maybe "ShowBubbleWithManager"?
43 void WebContentsModalDialogManager::ShowDialogWithManager(
44 NativeWebContentsModalDialog dialog
,
45 scoped_ptr
<SingleWebContentsDialogManager
> manager
) {
47 manager
->HostChanged(delegate_
->GetWebContentsModalDialogHost());
48 child_dialogs_
.push_back(new DialogState(dialog
, manager
.Pass()));
50 if (child_dialogs_
.size() == 1) {
51 BlockWebContentsInteraction(true);
52 if (delegate_
&& delegate_
->IsWebContentsVisible(web_contents()))
53 child_dialogs_
.back()->manager
->Show();
57 bool WebContentsModalDialogManager::IsDialogActive() const {
58 return !child_dialogs_
.empty();
61 void WebContentsModalDialogManager::FocusTopmostDialog() const {
62 DCHECK(!child_dialogs_
.empty());
63 child_dialogs_
.front()->manager
->Focus();
66 content::WebContents
* WebContentsModalDialogManager::GetWebContents() const {
67 return web_contents();
70 void WebContentsModalDialogManager::WillClose(
71 NativeWebContentsModalDialog dialog
) {
72 WebContentsModalDialogList::iterator dlg
= FindDialogState(dialog
);
74 // The Views tab contents modal dialog calls WillClose twice. Ignore the
76 if (dlg
== child_dialogs_
.end())
79 bool removed_topmost_dialog
= dlg
== child_dialogs_
.begin();
80 scoped_ptr
<DialogState
> deleter(*dlg
);
81 child_dialogs_
.erase(dlg
);
82 if (!child_dialogs_
.empty() && removed_topmost_dialog
&&
83 !closing_all_dialogs_
) {
84 child_dialogs_
.front()->manager
->Show();
87 BlockWebContentsInteraction(!child_dialogs_
.empty());
90 WebContentsModalDialogManager::WebContentsModalDialogManager(
91 content::WebContents
* web_contents
)
92 : content::WebContentsObserver(web_contents
),
94 closing_all_dialogs_(false) {
97 WebContentsModalDialogManager::DialogState::DialogState(
98 NativeWebContentsModalDialog dialog
,
99 scoped_ptr
<SingleWebContentsDialogManager
> mgr
)
101 manager(mgr
.release()) {
104 WebContentsModalDialogManager::DialogState::~DialogState() {}
106 WebContentsModalDialogManager::WebContentsModalDialogList::iterator
107 WebContentsModalDialogManager::FindDialogState(
108 NativeWebContentsModalDialog dialog
) {
109 WebContentsModalDialogList::iterator i
;
110 for (i
= child_dialogs_
.begin(); i
!= child_dialogs_
.end(); ++i
) {
111 if ((*i
)->dialog
== dialog
)
118 // TODO(gbillock): Move this to Views impl within Show()? It would
119 // call WebContents* contents = native_delegate_->GetWebContents(); and
120 // then set the block state. Advantage: could restrict some of the
121 // WCMDM delegate methods, then, and pass them behind the scenes.
122 void WebContentsModalDialogManager::BlockWebContentsInteraction(bool blocked
) {
123 WebContents
* contents
= web_contents();
125 // The WebContents has already disconnected.
129 // RenderViewHost may be NULL during shutdown.
130 content::RenderViewHost
* host
= contents
->GetRenderViewHost();
132 host
->SetIgnoreInputEvents(blocked
);
134 delegate_
->SetWebContentsBlocked(contents
, blocked
);
137 void WebContentsModalDialogManager::CloseAllDialogs() {
138 closing_all_dialogs_
= true;
140 // Clear out any dialogs since we are leaving this page entirely.
141 while (!child_dialogs_
.empty()) {
142 child_dialogs_
.front()->manager
->Close();
145 closing_all_dialogs_
= false;
148 void WebContentsModalDialogManager::DidNavigateMainFrame(
149 const content::LoadCommittedDetails
& details
,
150 const content::FrameNavigateParams
& params
) {
151 // Close constrained windows if necessary.
152 if (!net::registry_controlled_domains::SameDomainOrHost(
153 details
.previous_url
, details
.entry
->GetURL(),
154 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES
))
158 void WebContentsModalDialogManager::DidGetIgnoredUIEvent() {
159 if (!child_dialogs_
.empty()) {
160 child_dialogs_
.front()->manager
->Focus();
164 void WebContentsModalDialogManager::WasShown() {
165 if (!child_dialogs_
.empty())
166 child_dialogs_
.front()->manager
->Show();
169 void WebContentsModalDialogManager::WasHidden() {
170 if (!child_dialogs_
.empty())
171 child_dialogs_
.front()->manager
->Hide();
174 void WebContentsModalDialogManager::WebContentsDestroyed() {
175 // First cleanly close all child dialogs.
176 // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked
177 // some of these to close. CloseAllDialogs is async, so it might get called
178 // twice before it runs.
182 void WebContentsModalDialogManager::DidAttachInterstitialPage() {
183 // TODO(wittman): Test closing on interstitial webui works properly on Mac.
184 #if defined(USE_AURA)
189 } // namespace web_modal