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/notification_details.h"
11 #include "content/public/browser/notification_source.h"
12 #include "content/public/browser/notification_types.h"
13 #include "content/public/browser/render_view_host.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/browser/web_contents_view.h"
16 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
18 using content::WebContents
;
20 DEFINE_WEB_CONTENTS_USER_DATA_KEY(web_modal::WebContentsModalDialogManager
);
24 WebContentsModalDialogManager::~WebContentsModalDialogManager() {
25 DCHECK(child_dialogs_
.empty());
28 void WebContentsModalDialogManager::SetDelegate(
29 WebContentsModalDialogManagerDelegate
* d
) {
31 // Delegate can be NULL on Views/Win32 during tab drag.
32 native_manager_
->HostChanged(d
? d
->GetWebContentsModalDialogHost() : NULL
);
35 void WebContentsModalDialogManager::ShowDialog(
36 NativeWebContentsModalDialog dialog
) {
37 child_dialogs_
.push_back(dialog
);
39 native_manager_
->ManageDialog(dialog
);
41 if (child_dialogs_
.size() == 1) {
42 if (delegate_
&& delegate_
->IsWebContentsVisible(web_contents()))
43 native_manager_
->ShowDialog(dialog
);
44 BlockWebContentsInteraction(true);
48 bool WebContentsModalDialogManager::IsShowingDialog() const {
49 return !child_dialogs_
.empty();
52 void WebContentsModalDialogManager::FocusTopmostDialog() {
53 DCHECK(!child_dialogs_
.empty());
54 native_manager_
->FocusDialog(child_dialogs_
.front());
57 content::WebContents
* WebContentsModalDialogManager::GetWebContents() const {
58 return web_contents();
61 void WebContentsModalDialogManager::WillClose(
62 NativeWebContentsModalDialog dialog
) {
63 WebContentsModalDialogList::iterator
i(
64 std::find(child_dialogs_
.begin(), child_dialogs_
.end(), dialog
));
66 // The Views tab contents modal dialog calls WillClose twice. Ignore the
68 if (i
== child_dialogs_
.end())
71 bool removed_topmost_dialog
= i
== child_dialogs_
.begin();
72 child_dialogs_
.erase(i
);
73 if (!child_dialogs_
.empty() && removed_topmost_dialog
&&
74 !closing_all_dialogs_
)
75 native_manager_
->ShowDialog(child_dialogs_
.front());
77 BlockWebContentsInteraction(!child_dialogs_
.empty());
80 void WebContentsModalDialogManager::Observe(
82 const content::NotificationSource
& source
,
83 const content::NotificationDetails
& details
) {
84 DCHECK(type
== content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED
);
86 if (child_dialogs_
.empty())
89 bool visible
= *content::Details
<bool>(details
).ptr();
91 native_manager_
->ShowDialog(child_dialogs_
.front());
93 native_manager_
->HideDialog(child_dialogs_
.front());
96 WebContentsModalDialogManager::WebContentsModalDialogManager(
97 content::WebContents
* web_contents
)
98 : content::WebContentsObserver(web_contents
),
100 native_manager_(CreateNativeManager(this)),
101 closing_all_dialogs_(false) {
102 DCHECK(native_manager_
);
104 content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED
,
105 content::Source
<content::WebContents
>(web_contents
));
108 void WebContentsModalDialogManager::BlockWebContentsInteraction(bool blocked
) {
109 WebContents
* contents
= web_contents();
111 // The WebContents has already disconnected.
115 // RenderViewHost may be NULL during shutdown.
116 content::RenderViewHost
* host
= contents
->GetRenderViewHost();
118 host
->SetIgnoreInputEvents(blocked
);
120 delegate_
->SetWebContentsBlocked(contents
, blocked
);
123 void WebContentsModalDialogManager::CloseAllDialogs() {
124 closing_all_dialogs_
= true;
126 // Clear out any dialogs since we are leaving this page entirely.
127 while (!child_dialogs_
.empty())
128 native_manager_
->CloseDialog(child_dialogs_
.front());
130 closing_all_dialogs_
= false;
133 void WebContentsModalDialogManager::DidNavigateMainFrame(
134 const content::LoadCommittedDetails
& details
,
135 const content::FrameNavigateParams
& params
) {
136 // Close constrained windows if necessary.
137 if (!net::registry_controlled_domains::SameDomainOrHost(
138 details
.previous_url
, details
.entry
->GetURL(),
139 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES
))
143 void WebContentsModalDialogManager::DidGetIgnoredUIEvent() {
144 if (!child_dialogs_
.empty())
145 native_manager_
->FocusDialog(child_dialogs_
.front());
148 void WebContentsModalDialogManager::WebContentsDestroyed(WebContents
* tab
) {
149 // First cleanly close all child dialogs.
150 // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked
151 // some of these to close. CloseAllDialogs is async, so it might get called
152 // twice before it runs.
156 } // namespace web_modal