Add an exponential backoff to rechecking the app list doodle.
[chromium-blink-merge.git] / components / web_modal / web_contents_modal_dialog_manager.cc
blobd49d36e1e5fc73884c1e0a6895d89cdf7e04a7b0
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);
18 namespace web_modal {
20 WebContentsModalDialogManager::~WebContentsModalDialogManager() {
21 DCHECK(child_dialogs_.empty());
24 void WebContentsModalDialogManager::SetDelegate(
25 WebContentsModalDialogManagerDelegate* d) {
26 delegate_ = 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) {
45 if (delegate_)
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
73 // second invocation.
74 if (dlg == child_dialogs_.end())
75 return;
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),
91 delegate_(NULL),
92 closing_all_dialogs_(false) {
95 WebContentsModalDialogManager::DialogState::DialogState(
96 gfx::NativeWindow dialog,
97 scoped_ptr<SingleWebContentsDialogManager> mgr)
98 : dialog(dialog),
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)
109 break;
112 return i;
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();
121 if (!contents) {
122 // The WebContents has already disconnected.
123 return;
126 // RenderViewHost may be NULL during shutdown.
127 content::RenderViewHost* host = contents->GetRenderViewHost();
128 if (host)
129 host->SetIgnoreInputEvents(blocked);
130 if (delegate_)
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))
152 CloseAllDialogs();
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.
176 CloseAllDialogs();
179 void WebContentsModalDialogManager::DidAttachInterstitialPage() {
180 // TODO(wittman): Test closing on interstitial webui works properly on Mac.
181 #if defined(USE_AURA)
182 CloseAllDialogs();
183 #endif
186 } // namespace web_modal