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(gfx::NativeWindow dialog
) {
36 scoped_ptr
<SingleWebContentsDialogManager
> mgr(
37 CreateNativeWebModalManager(dialog
, this));
38 ShowDialogWithManager(dialog
, mgr
.Pass());
41 // TODO(gbillock): Maybe "ShowBubbleWithManager"?
42 void WebContentsModalDialogManager::ShowDialogWithManager(
43 gfx::NativeWindow dialog
,
44 scoped_ptr
<SingleWebContentsDialogManager
> manager
) {
46 manager
->HostChanged(delegate_
->GetWebContentsModalDialogHost());
47 child_dialogs_
.push_back(new DialogState(dialog
, manager
.Pass()));
49 if (child_dialogs_
.size() == 1) {
50 BlockWebContentsInteraction(true);
51 if (delegate_
&& delegate_
->IsWebContentsVisible(web_contents()))
52 child_dialogs_
.back()->manager
->Show();
56 bool WebContentsModalDialogManager::IsDialogActive() const {
57 return !child_dialogs_
.empty();
60 void WebContentsModalDialogManager::FocusTopmostDialog() const {
61 DCHECK(!child_dialogs_
.empty());
62 child_dialogs_
.front()->manager
->Focus();
65 content::WebContents
* WebContentsModalDialogManager::GetWebContents() const {
66 return web_contents();
69 void WebContentsModalDialogManager::WillClose(gfx::NativeWindow dialog
) {
70 WebContentsModalDialogList::iterator dlg
= FindDialogState(dialog
);
72 // The Views tab contents modal dialog calls WillClose twice. Ignore the
74 if (dlg
== child_dialogs_
.end())
77 bool removed_topmost_dialog
= dlg
== child_dialogs_
.begin();
78 scoped_ptr
<DialogState
> deleter(*dlg
);
79 child_dialogs_
.erase(dlg
);
80 if (!child_dialogs_
.empty() && removed_topmost_dialog
&&
81 !closing_all_dialogs_
) {
82 child_dialogs_
.front()->manager
->Show();
85 BlockWebContentsInteraction(!child_dialogs_
.empty());
88 WebContentsModalDialogManager::WebContentsModalDialogManager(
89 content::WebContents
* web_contents
)
90 : content::WebContentsObserver(web_contents
),
92 closing_all_dialogs_(false) {
95 WebContentsModalDialogManager::DialogState::DialogState(
96 gfx::NativeWindow dialog
,
97 scoped_ptr
<SingleWebContentsDialogManager
> mgr
)
99 manager(mgr
.release()) {
102 WebContentsModalDialogManager::DialogState::~DialogState() {}
104 WebContentsModalDialogManager::WebContentsModalDialogList::iterator
105 WebContentsModalDialogManager::FindDialogState(gfx::NativeWindow dialog
) {
106 WebContentsModalDialogList::iterator i
;
107 for (i
= child_dialogs_
.begin(); i
!= child_dialogs_
.end(); ++i
) {
108 if ((*i
)->dialog
== dialog
)
115 // TODO(gbillock): Move this to Views impl within Show()? It would
116 // call WebContents* contents = native_delegate_->GetWebContents(); and
117 // then set the block state. Advantage: could restrict some of the
118 // WCMDM delegate methods, then, and pass them behind the scenes.
119 void WebContentsModalDialogManager::BlockWebContentsInteraction(bool blocked
) {
120 WebContents
* contents
= web_contents();
122 // The WebContents has already disconnected.
126 // RenderViewHost may be NULL during shutdown.
127 content::RenderViewHost
* host
= contents
->GetRenderViewHost();
129 host
->SetIgnoreInputEvents(blocked
);
131 delegate_
->SetWebContentsBlocked(contents
, blocked
);
134 void WebContentsModalDialogManager::CloseAllDialogs() {
135 closing_all_dialogs_
= true;
137 // Clear out any dialogs since we are leaving this page entirely.
138 while (!child_dialogs_
.empty()) {
139 child_dialogs_
.front()->manager
->Close();
142 closing_all_dialogs_
= false;
145 void WebContentsModalDialogManager::DidNavigateMainFrame(
146 const content::LoadCommittedDetails
& details
,
147 const content::FrameNavigateParams
& params
) {
148 // Close constrained windows if necessary.
149 if (!net::registry_controlled_domains::SameDomainOrHost(
150 details
.previous_url
, details
.entry
->GetURL(),
151 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES
))
155 void WebContentsModalDialogManager::DidGetIgnoredUIEvent() {
156 if (!child_dialogs_
.empty()) {
157 child_dialogs_
.front()->manager
->Focus();
161 void WebContentsModalDialogManager::WasShown() {
162 if (!child_dialogs_
.empty())
163 child_dialogs_
.front()->manager
->Show();
166 void WebContentsModalDialogManager::WasHidden() {
167 if (!child_dialogs_
.empty())
168 child_dialogs_
.front()->manager
->Hide();
171 void WebContentsModalDialogManager::WebContentsDestroyed() {
172 // First cleanly close all child dialogs.
173 // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked
174 // some of these to close. CloseAllDialogs is async, so it might get called
175 // twice before it runs.
179 void WebContentsModalDialogManager::DidAttachInterstitialPage() {
180 // TODO(wittman): Test closing on interstitial webui works properly on Mac.
181 #if defined(USE_AURA)
186 } // namespace web_modal