diff options
author | gbillock@chromium.org <gbillock@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-15 00:16:47 +0000 |
---|---|---|
committer | gbillock@chromium.org <gbillock@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-15 00:16:47 +0000 |
commit | 010152f1c2f749b629ad20d90df33d13355b5797 (patch) | |
tree | 2425644209cfc1f34ae5719c63030a70aae48e58 | |
parent | 093cc2119996683baed6074ad764d86aab55e782 (diff) | |
download | chromium_src-010152f1c2f749b629ad20d90df33d13355b5797.zip chromium_src-010152f1c2f749b629ad20d90df33d13355b5797.tar.gz chromium_src-010152f1c2f749b629ad20d90df33d13355b5797.tar.bz2 |
[WebModals] New API for browser-scoped popup management.
This interface follows the WebContents-scoped WebContentsModalDialogManager
closely, the main difference being the change in scope -- the popup
manager is intended to manage popups (bubbles and web-modals) scoped both
at the per-WebContents level as well as at the browser/system level.
The policy for the manager is not known yet, so this change is setting up
the API which will be used to register popups with the manager, and the
lifecycle which the manager uses to display them. The critical facts about
a popup are expected to be:
1. Whether it is user-initiated.
2. If it is scoped to a particular WebContents (and if so, which one),
3. If it is overlappable.
Other important management facts about popups may be added later.
The lifecycle operation is all driven through an interface called
SinglePopupManager which is a one-per-window scoped manager owned by
the PopupManager. These classes take charge of showing and hiding
their popups depending on the state of the browser window, as governed
by whatever state change observations made by the overall PopupManager
relate to its policy.
When a window is closed by direct user action, the manager notifies the
overall BubbleManager, which then removes the window from the management
queue and can show another window. A window may also be closed by
direct command from the overall BubbleManager, for example if it is
superceded by another user-initiated popup.
BUG=375393
TBR=yoz
Review URL: https://codereview.chromium.org/287123002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@283099 0039d316-1c4b-4281-b951-d872f2087c98
29 files changed, 480 insertions, 101 deletions
diff --git a/apps/app_window.cc b/apps/app_window.cc index e2d837d..db1f543 100644 --- a/apps/app_window.cc +++ b/apps/app_window.cc @@ -264,6 +264,7 @@ void AppWindow::Init(const GURL& url, content::WebContentsObserver::Observe(web_contents); } delegate_->InitWebContents(web_contents); + WebContentsModalDialogManager::CreateForWebContents(web_contents); // TODO(jamescook): Delegate out this creation. extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( @@ -286,6 +287,10 @@ void AppWindow::Init(const GURL& url, native_app_window_.reset(delegate_->CreateNativeAppWindow(this, new_params)); + popup_manager_.reset( + new web_modal::PopupManager(GetWebContentsModalDialogHost())); + popup_manager_->RegisterWith(web_contents); + // Prevent the browser process from shutting down while this window exists. AppsClient::Get()->IncrementKeepAliveCount(); UpdateExtensionAppIcon(); diff --git a/apps/app_window.h b/apps/app_window.h index f2e0e98..9873eed 100644 --- a/apps/app_window.h +++ b/apps/app_window.h @@ -8,6 +8,7 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/sessions/session_id.h" +#include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -522,6 +523,10 @@ class AppWindow : public content::NotificationObserver, scoped_ptr<AppWindowContents> app_window_contents_; scoped_ptr<Delegate> delegate_; + // Manages popup windows (bubbles, tab-modals) visible overlapping the + // app window. + scoped_ptr<web_modal::PopupManager> popup_manager_; + base::WeakPtrFactory<AppWindow> image_loader_ptr_factory_; // Bit field of FullscreenType. diff --git a/chrome/browser/chromeos/attestation/platform_verification_dialog.cc b/chrome/browser/chromeos/attestation/platform_verification_dialog.cc index a74a907..ef176f4 100644 --- a/chrome/browser/chromeos/attestation/platform_verification_dialog.cc +++ b/chrome/browser/chromeos/attestation/platform_verification_dialog.cc @@ -11,9 +11,7 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/singleton_tabs.h" #include "chrome/common/url_constants.h" -#include "components/web_modal/web_contents_modal_dialog_host.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" -#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" +#include "components/web_modal/popup_manager.h" #include "content/public/browser/web_contents.h" #include "content/public/common/page_transition_types.h" #include "extensions/browser/extension_registry.h" @@ -26,6 +24,7 @@ #include "ui/views/layout/fill_layout.h" #include "ui/views/layout/layout_constants.h" #include "ui/views/widget/widget.h" +#include "ui/views/window/dialog_delegate.h" namespace chromeos { namespace attestation { @@ -53,13 +52,13 @@ void PlatformVerificationDialog::ShowDialog( base::UTF8ToUTF16(origin), callback); - web_modal::WebContentsModalDialogManager* manager = - web_modal::WebContentsModalDialogManager::FromWebContents(web_contents); - const gfx::NativeWindow parent = - manager->delegate()->GetWebContentsModalDialogHost()->GetHostView(); - views::Widget* widget = CreateDialogWidget(dialog, NULL, parent); - manager->ShowModalDialog(widget->GetNativeView()); - widget->Show(); + // Sets up the dialog widget to be shown. + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(web_contents); + DCHECK(popup_manager); + views::Widget* widget = views::DialogDelegate::CreateDialogWidget( + dialog, NULL, popup_manager->GetHostView()); + popup_manager->ShowModalDialog(widget->GetNativeView(), web_contents); } PlatformVerificationDialog::~PlatformVerificationDialog() { diff --git a/chrome/browser/chromeos/login/ui/captive_portal_window_proxy.cc b/chrome/browser/chromeos/login/ui/captive_portal_window_proxy.cc index 11405f3..24b00ec 100644 --- a/chrome/browser/chromeos/login/ui/captive_portal_window_proxy.cc +++ b/chrome/browser/chromeos/login/ui/captive_portal_window_proxy.cc @@ -7,12 +7,11 @@ #include "chrome/browser/chromeos/login/ui/captive_portal_view.h" #include "chrome/browser/chromeos/login/ui/proxy_settings_dialog.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" -#include "components/web_modal/web_contents_modal_dialog_host.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" -#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" +#include "components/web_modal/popup_manager.h" #include "ui/views/widget/widget.h" namespace { + // The captive portal dialog is system-modal, but uses the web-content-modal // dialog manager (odd) and requires this atypical dialog widget initialization. views::Widget* CreateWindowAsFramelessChild(views::WidgetDelegate* delegate, @@ -72,16 +71,15 @@ void CaptivePortalWindowProxy::Show() { InitCaptivePortalView(); CaptivePortalView* portal = captive_portal_view_.release(); - web_modal::WebContentsModalDialogManager* manager = - web_modal::WebContentsModalDialogManager::FromWebContents(web_contents_); - const gfx::NativeWindow parent = - manager->delegate()->GetWebContentsModalDialogHost()->GetHostView(); - widget_ = CreateWindowAsFramelessChild(portal, parent); - portal->Init(); - - widget_->AddObserver(this); - manager->ShowModalDialog(widget_->GetNativeView()); - DCHECK(GetState() == STATE_DISPLAYED); + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(web_contents_); + if (popup_manager) { + widget_ = + CreateWindowAsFramelessChild(portal, popup_manager->GetHostView()); + portal->Init(); + widget_->AddObserver(this); + popup_manager->ShowModalDialog(widget_->GetNativeView(), web_contents_); + } } void CaptivePortalWindowProxy::Close() { diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc index a1a4f2d..957ac19 100644 --- a/chrome/browser/chromeos/login/ui/webui_login_view.cc +++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc @@ -192,6 +192,9 @@ void WebUILoginView::Init() { WebContentsModalDialogManager::CreateForWebContents(web_contents); WebContentsModalDialogManager::FromWebContents(web_contents)-> SetDelegate(this); + if (!popup_manager_.get()) + popup_manager_.reset(new web_modal::PopupManager(this)); + popup_manager_->RegisterWith(web_contents); web_contents->SetDelegate(this); extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.h b/chrome/browser/chromeos/login/ui/webui_login_view.h index 1d65dba..82713db 100644 --- a/chrome/browser/chromeos/login/ui/webui_login_view.h +++ b/chrome/browser/chromeos/login/ui/webui_login_view.h @@ -12,6 +12,7 @@ #include "base/observer_list.h" #include "chrome/browser/extensions/signin/scoped_gaia_auth_extension.h" #include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h" +#include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_host.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -193,6 +194,11 @@ class WebUILoginView : public views::View, ObserverList<web_modal::ModalDialogHostObserver> observer_list_; ObserverList<FrameObserver> frame_observer_list_; + // Manage popups appearing over the login window. + // TODO(gbillock): See if we can get rid of this. Perhaps in favor of + // in-content styled popups or something? There oughtta be a way... + scoped_ptr<web_modal::PopupManager> popup_manager_; + DISALLOW_COPY_AND_ASSIGN(WebUILoginView); }; diff --git a/chrome/browser/extensions/extension_view_host.cc b/chrome/browser/extensions/extension_view_host.cc index fbbec71..84e99e7 100644 --- a/chrome/browser/extensions/extension_view_host.cc +++ b/chrome/browser/extensions/extension_view_host.cc @@ -127,6 +127,9 @@ void ExtensionViewHost::LoadInitialURL() { WebContentsModalDialogManager::CreateForWebContents(host_contents()); WebContentsModalDialogManager::FromWebContents( host_contents())->SetDelegate(this); + if (!popup_manager_.get()) + popup_manager_.reset(new web_modal::PopupManager(this)); + popup_manager_->RegisterWith(host_contents()); } ExtensionHost::LoadInitialURL(); diff --git a/chrome/browser/extensions/extension_view_host.h b/chrome/browser/extensions/extension_view_host.h index 6201fc0..a7599b4 100644 --- a/chrome/browser/extensions/extension_view_host.h +++ b/chrome/browser/extensions/extension_view_host.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_VIEW_HOST_H_ #include "base/memory/scoped_ptr.h" +#include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_host.h" #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" #include "extensions/browser/extension_host.h" @@ -24,6 +25,7 @@ class ExtensionView; // The ExtensionHost for an extension that backs a view in the browser UI. For // example, this could be an extension popup, infobar or dialog, but not a // background page. +// TODO(gbillock): See if we can remove WebContentsModalDialogManager here. class ExtensionViewHost : public ExtensionHost, public web_modal::WebContentsModalDialogManagerDelegate, @@ -130,6 +132,12 @@ class ExtensionViewHost class AssociatedWebContentsObserver; scoped_ptr<AssociatedWebContentsObserver> associated_web_contents_observer_; + // Manage popups overlaying the WebContents in this EVH. + // TODO(gbillock): should usually not be used -- instead use the parent + // window's popup manager. Should only be used when the EVH is created without + // a parent window. + scoped_ptr<web_modal::PopupManager> popup_manager_; + DISALLOW_COPY_AND_ASSIGN(ExtensionViewHost); }; diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 97c8335..af3f7e7 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc @@ -152,6 +152,7 @@ #include "components/bookmarks/browser/bookmark_utils.h" #include "components/google/core/browser/google_url_tracker.h" #include "components/startup_metric_utils/startup_metric_utils.h" +#include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "content/public/browser/devtools_manager.h" #include "content/public/browser/download_item.h" @@ -444,6 +445,12 @@ Browser::Browser(const CreateParams& params) } fullscreen_controller_.reset(new FullscreenController(this)); + + // Must be initialized after window_. + // Also: surprise! a modal dialog host is not necessary to host modal dialogs + // without a modal dialog host, so that value may be null. + popup_manager_.reset(new web_modal::PopupManager( + GetWebContentsModalDialogHost())); } Browser::~Browser() { @@ -892,6 +899,10 @@ void Browser::TabInsertedAt(WebContents* contents, int index, bool foreground) { SetAsDelegate(contents, true); + + if (popup_manager_) + popup_manager_->RegisterWith(contents); + SessionTabHelper* session_tab_helper = SessionTabHelper::FromWebContents(contents); session_tab_helper->SetWindowID(session_id()); @@ -933,6 +944,9 @@ void Browser::TabClosingAt(TabStripModel* tab_strip_model, content::Source<NavigationController>(&contents->GetController()), content::NotificationService::NoDetails()); + if (popup_manager_) + popup_manager_->UnregisterWith(contents); + // Sever the WebContents' connection back to us. SetAsDelegate(contents, false); } @@ -948,6 +962,10 @@ void Browser::TabDetachedAt(WebContents* contents, int index) { session_service->SetSelectedTabInWindow(session_id(), old_active_index - 1); } + + if (popup_manager_) + popup_manager_->UnregisterWith(contents); + TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH); } diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index bdf7d18..a6492ef 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h @@ -91,6 +91,7 @@ class WebDialogDelegate; } namespace web_modal { +class PopupManager; class WebContentsModalDialogHost; } @@ -242,6 +243,9 @@ class Browser : public TabStripModelObserver, toolbar_model->swap(toolbar_model_); } #endif + web_modal::PopupManager* popup_manager() { + return popup_manager_.get(); + } TabStripModel* tab_strip_model() const { return tab_strip_model_.get(); } chrome::BrowserCommandController* command_controller() { return command_controller_.get(); @@ -823,6 +827,10 @@ class Browser : public TabStripModelObserver, // This Browser's window. BrowserWindow* window_; + // Manages popup windows (bubbles, tab-modals) visible overlapping this + // window. JS alerts are not handled by this manager. + scoped_ptr<web_modal::PopupManager> popup_manager_; + scoped_ptr<TabStripModelDelegate> tab_strip_model_delegate_; scoped_ptr<TabStripModel> tab_strip_model_; diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc index 8a593d5..ab8e5bb 100644 --- a/chrome/browser/ui/browser_commands.cc +++ b/chrome/browser/ui/browser_commands.cc @@ -64,7 +64,7 @@ #include "components/bookmarks/browser/bookmark_utils.h" #include "components/google/core/browser/google_util.h" #include "components/translate/core/browser/language_state.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "components/web_modal/popup_manager.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h" @@ -109,7 +109,6 @@ using content::OpenURLParams; using content::Referrer; using content::SSLStatus; using content::WebContents; -using web_modal::WebContentsModalDialogManager; namespace chrome { namespace { @@ -245,15 +244,21 @@ void ReloadInternal(Browser* browser, new_tab->GetController().Reload(true); } -bool IsShowingWebContentsModalDialog(const Browser* browser) { +bool IsShowingWebContentsModalDialog(Browser* browser) { WebContents* web_contents = browser->tab_strip_model()->GetActiveWebContents(); if (!web_contents) return false; - WebContentsModalDialogManager* web_contents_modal_dialog_manager = - WebContentsModalDialogManager::FromWebContents(web_contents); - return web_contents_modal_dialog_manager->IsDialogActive(); + // In test code we may not have a popup manager. + if (!browser->popup_manager()) + return false; + + // TODO(gbillock): This is currently called in production by the CanPrint + // method, and may be too restrictive if we allow print preview to overlap. + // Re-assess how to queue print preview after we know more about popup + // management policy. + return browser->popup_manager()->IsWebModalDialogActive(web_contents); } bool PrintPreviewShowing(const Browser* browser) { @@ -853,9 +858,13 @@ void Print(Browser* browser) { #endif // defined(ENABLE_PRINTING) } -bool CanPrint(const Browser* browser) { +bool CanPrint(Browser* browser) { // Do not print when printing is disabled via pref or policy. // Do not print when a constrained window is showing. It's confusing. + // TODO(gbillock): Need to re-assess the call to + // IsShowingWebContentsModalDialog after a popup management policy is + // refined -- we will probably want to just queue the print request, not + // block it. return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) && !(IsShowingWebContentsModalDialog(browser) || GetContentRestrictions(browser) & CONTENT_RESTRICTION_PRINT); @@ -870,7 +879,7 @@ void AdvancedPrint(Browser* browser) { #endif } -bool CanAdvancedPrint(const Browser* browser) { +bool CanAdvancedPrint(Browser* browser) { // If printing is not disabled via pref or policy, it is always possible to // advanced print when the print preview is visible. The exception to this // is under Win8 ash, since showing the advanced print dialog will open it diff --git a/chrome/browser/ui/browser_commands.h b/chrome/browser/ui/browser_commands.h index 1d032f8..2113e77 100644 --- a/chrome/browser/ui/browser_commands.h +++ b/chrome/browser/ui/browser_commands.h @@ -106,9 +106,9 @@ void ShowWebsiteSettings(Browser* browser, const GURL& url, const content::SSLStatus& ssl); void Print(Browser* browser); -bool CanPrint(const Browser* browser); +bool CanPrint(Browser* browser); void AdvancedPrint(Browser* browser); -bool CanAdvancedPrint(const Browser* browser); +bool CanAdvancedPrint(Browser* browser); void PrintToDestination(Browser* browser); void EmailPageLocation(Browser* browser); bool CanEmailPageLocation(const Browser* browser); diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm index 5f0a158..f45fe95 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller.mm @@ -84,6 +84,7 @@ #include "components/signin/core/common/profile_management_switches.h" #include "components/translate/core/browser/translate_manager.h" #include "components/translate/core/browser/translate_ui_delegate.h" +#include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" @@ -178,7 +179,6 @@ using content::OpenURLParams; using content::Referrer; using content::RenderWidgetHostView; using content::WebContents; -using web_modal::WebContentsModalDialogManager; @interface NSWindow (NSPrivateApis) // Note: These functions are private, use -[NSObject respondsToSelector:] @@ -1608,8 +1608,9 @@ using web_modal::WebContentsModalDialogManager; WebContents* contents = browser_->tab_strip_model()->GetWebContentsAt(index); if (!contents) return NO; - return !WebContentsModalDialogManager::FromWebContents(contents)-> - IsDialogActive(); + + return !web_modal::PopupManager::FromWebContents(contents)-> + IsWebModalDialogActive(contents); } // TabStripControllerDelegate protocol. diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm index 7e6031b..8fcdeeb 100644 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm +++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm @@ -11,6 +11,7 @@ #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h" +#include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" @@ -33,9 +34,10 @@ ConstrainedWindowMac::ConstrainedWindowMac( web_contents_ = web_view_guest && web_view_guest->embedder_web_contents() ? web_view_guest->embedder_web_contents() : web_contents; DCHECK(sheet_.get()); - WebContentsModalDialogManager* web_contents_modal_dialog_manager = - WebContentsModalDialogManager::FromWebContents(web_contents_); - web_contents_modal_dialog_manager->ShowModalDialog(this); + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(web_contents_); + if (popup_manager) + popup_manager->ShowModalDialog(this, web_contents_); } ConstrainedWindowMac::~ConstrainedWindowMac() { diff --git a/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm index cd7e579..1e88c84 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm @@ -14,10 +14,11 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/url_constants.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_finder.h" #import "chrome/browser/ui/cocoa/browser_window_cocoa.h" #import "chrome/browser/ui/cocoa/extensions/extension_view_mac.h" #import "chrome/browser/ui/cocoa/info_bubble_window.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "components/web_modal/popup_manager.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_manager.h" #include "content/public/browser/notification_details.h" @@ -213,11 +214,12 @@ class DevtoolsNotificationBridge : public content::NotificationObserver { - (void)close { // |windowWillClose:| could have already been called. http://crbug.com/279505 if (host_) { - web_modal::WebContentsModalDialogManager* modalDialogManager = - web_modal::WebContentsModalDialogManager::FromWebContents( - host_->host_contents()); - if (modalDialogManager && - modalDialogManager->IsDialogActive()) { + // TODO(gbillock): Change this API to say directly if the current popup + // should block tab close? This is a bit over-reaching. + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(host_->host_contents()); + if (popup_manager && popup_manager->IsWebModalDialogActive( + host_->host_contents())) { return; } } @@ -240,11 +242,11 @@ class DevtoolsNotificationBridge : public content::NotificationObserver { // it steals key-ness from the popup. Don't close the popup when this // happens. There's an extra windowDidResignKey: notification after the // modal dialog closes that should also be ignored. - web_modal::WebContentsModalDialogManager* modalDialogManager = - web_modal::WebContentsModalDialogManager::FromWebContents( + web_modal::PopupManager* popupManager = + web_modal::PopupManager::FromWebContents( host_->host_contents()); - if (modalDialogManager && - modalDialogManager->IsDialogActive()) { + if (popupManager && + popupManager->IsWebModalDialogActive(host_->host_contents())) { ignoreWindowDidResignKey_ = YES; return; } diff --git a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_browsertest.mm index f4b41c9..ab42719 100644 --- a/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_browsertest.mm +++ b/chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_browsertest.mm @@ -10,7 +10,7 @@ #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "components/web_modal/popup_manager.h" #include "content/public/test/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -19,7 +19,6 @@ using ::testing::AnyNumber; using ::testing::NiceMock; using ::testing::Return; using ::testing::ReturnRef; -using web_modal::WebContentsModalDialogManager; class MediaGalleriesDialogBrowserTest : public InProcessBrowserTest { }; @@ -49,10 +48,8 @@ IN_PROC_BROWSER_TEST_F(MediaGalleriesDialogBrowserTest, Close) { base::scoped_nsobject<NSWindow> window([[dialog->alert_ window] retain]); EXPECT_TRUE([window isVisible]); - WebContentsModalDialogManager* web_contents_modal_dialog_manager = - WebContentsModalDialogManager::FromWebContents(web_contents); - WebContentsModalDialogManager::TestApi test_api( - web_contents_modal_dialog_manager); - test_api.CloseAllDialogs(); + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(web_contents); + popup_manager->CloseAllDialogsForTesting(web_contents); EXPECT_FALSE([window isVisible]); } diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc index 098d89d..eeaf6cf 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.cc +++ b/chrome/browser/ui/tabs/tab_strip_model.cc @@ -21,7 +21,7 @@ #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h" #include "chrome/common/url_constants.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "components/web_modal/popup_manager.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/user_metrics.h" #include "content/public/browser/web_contents.h" @@ -315,10 +315,13 @@ void TabStripModel::InsertWebContentsAt(int index, data->set_opener(active_contents); } - web_modal::WebContentsModalDialogManager* modal_dialog_manager = - web_modal::WebContentsModalDialogManager::FromWebContents(contents); - if (modal_dialog_manager) - data->set_blocked(modal_dialog_manager->IsDialogActive()); + // TODO(gbillock): Ask the bubble manager whether the WebContents should be + // blocked, or just let the bubble manager make the blocking call directly + // and not use this at all. + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(contents); + if (popup_manager) + data->set_blocked(popup_manager->IsWebModalDialogActive(contents)); contents_data_.insert(contents_data_.begin() + index, data); diff --git a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc index 1bbfaea..445f2be 100644 --- a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc +++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc @@ -27,6 +27,7 @@ #include "chrome/common/url_constants.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" +#include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h" @@ -2563,8 +2564,8 @@ TEST_F(TabStripModelTest, TabBlockedState) { // Setup a SingleWebContentsDialogManager for tab |contents2|. web_modal::WebContentsModalDialogManager* modal_dialog_manager = web_modal::WebContentsModalDialogManager::FromWebContents(contents2); - web_modal::WebContentsModalDialogManager::TestApi test_api( - modal_dialog_manager); + web_modal::PopupManager popup_manager(NULL); + popup_manager.RegisterWith(contents2); // Show a dialog that blocks tab |contents2|. // DummySingleWebContentsDialogManager doesn't care about the diff --git a/chrome/browser/ui/views/constrained_window_views.cc b/chrome/browser/ui/views/constrained_window_views.cc index 5dde7612..86f1ec7 100644 --- a/chrome/browser/ui/views/constrained_window_views.cc +++ b/chrome/browser/ui/views/constrained_window_views.cc @@ -8,9 +8,8 @@ #include "chrome/browser/guest_view/web_view/web_view_guest.h" #include "chrome/browser/ui/browser_finder.h" +#include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_host.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" -#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" #include "ui/views/border.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_observer.h" @@ -132,21 +131,22 @@ views::Widget* ShowWebModalDialogViews( web_view_guest && web_view_guest->embedder_web_contents() ? web_view_guest->embedder_web_contents() : initiator_web_contents; views::Widget* widget = CreateWebModalDialogViews(dialog, web_contents); - web_modal::WebContentsModalDialogManager::FromWebContents(web_contents)-> - ShowModalDialog(widget->GetNativeWindow()); + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(web_contents); + popup_manager->ShowModalDialog(widget->GetNativeWindow(), web_contents); return widget; } views::Widget* CreateWebModalDialogViews(views::WidgetDelegate* dialog, content::WebContents* web_contents) { DCHECK_EQ(ui::MODAL_TYPE_CHILD, dialog->GetModalType()); - web_modal::WebContentsModalDialogManager* manager = - web_modal::WebContentsModalDialogManager::FromWebContents(web_contents); - const gfx::NativeWindow parent = - manager->delegate()->GetWebContentsModalDialogHost()->GetHostView(); + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(web_contents); + const gfx::NativeWindow parent = popup_manager->GetHostView(); return views::DialogDelegate::CreateDialogWidget(dialog, NULL, parent); } +// TODO(gbillock): Replace this with PopupManager calls. views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog, gfx::NativeWindow parent) { views::Widget* widget = diff --git a/chrome/browser/ui/views/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_media_picker_views.cc index 9e21558..f8d0ab9 100644 --- a/chrome/browser/ui/views/desktop_media_picker_views.cc +++ b/chrome/browser/ui/views/desktop_media_picker_views.cc @@ -9,7 +9,7 @@ #include "chrome/browser/media/desktop_media_list_observer.h" #include "chrome/browser/ui/ash/ash_util.h" #include "chrome/browser/ui/views/constrained_window_views.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "components/web_modal/popup_manager.h" #include "content/public/browser/browser_thread.h" #include "grit/generated_resources.h" #include "ui/aura/window_tree_host.h" @@ -587,10 +587,10 @@ DesktopMediaPickerDialogView::DesktopMediaPickerDialogView( list_view_->StartUpdating(dialog_window_id); if (parent_web_contents) { - web_modal::WebContentsModalDialogManager* manager = - web_modal::WebContentsModalDialogManager::FromWebContents( - parent_web_contents); - manager->ShowModalDialog(widget->GetNativeView()); + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(parent_web_contents); + popup_manager->ShowModalDialog(GetWidget()->GetNativeView(), + parent_web_contents); } else { widget->Show(); } diff --git a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc index e4cdf17..faa14bb 100644 --- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc +++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc @@ -7,7 +7,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/views/constrained_window_views.h" #include "chrome/browser/ui/views/extensions/media_gallery_checkbox_view.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "components/web_modal/popup_manager.h" #include "content/public/browser/web_contents.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" @@ -79,12 +79,10 @@ MediaGalleriesDialogViews::~MediaGalleriesDialogViews() { void MediaGalleriesDialogViews::AcceptDialogForTesting() { accepted_ = true; - web_modal::WebContentsModalDialogManager* web_contents_modal_dialog_manager = - web_modal::WebContentsModalDialogManager::FromWebContents( - controller_->WebContents()); - DCHECK(web_contents_modal_dialog_manager); - web_modal::WebContentsModalDialogManager::TestApi( - web_contents_modal_dialog_manager).CloseAllDialogs(); + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(controller_->WebContents()); + DCHECK(popup_manager); + popup_manager->CloseAllDialogsForTesting(controller_->WebContents()); } void MediaGalleriesDialogViews::InitChildViews() { diff --git a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc index 1b9d752..c223a90 100644 --- a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc +++ b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc @@ -6,12 +6,13 @@ #include "chrome/browser/browser_shutdown.h" #include "chrome/browser/ui/aura/tab_contents/web_drag_bookmark_handler_aura.h" +#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/sad_tab_helper.h" #include "chrome/browser/ui/tab_contents/chrome_web_contents_view_delegate.h" #include "chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.h" #include "chrome/browser/ui/views/sad_tab_view.h" #include "chrome/common/chrome_switches.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "components/web_modal/popup_manager.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" @@ -23,8 +24,6 @@ #include "ui/views/focus/view_storage.h" #include "ui/views/widget/widget.h" -using web_modal::WebContentsModalDialogManager; - ChromeWebContentsViewDelegateViews::ChromeWebContentsViewDelegateViews( content::WebContents* web_contents) : ContextMenuDelegate(web_contents), @@ -61,17 +60,10 @@ bool ChromeWebContentsViewDelegateViews::Focus() { } } - WebContentsModalDialogManager* web_contents_modal_dialog_manager = - WebContentsModalDialogManager::FromWebContents(web_contents_); - if (web_contents_modal_dialog_manager) { - // TODO(erg): WebContents used to own web contents modal dialogs, which is - // why this is here. Eventually this should be ported to a containing view - // specializing in web contents modal dialog management. - if (web_contents_modal_dialog_manager->IsDialogActive()) { - web_contents_modal_dialog_manager->FocusTopmostDialog(); - return true; - } - } + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(web_contents_); + if (popup_manager) + popup_manager->WasFocused(web_contents_); return false; } diff --git a/components/web_modal.gypi b/components/web_modal.gypi index 2502803..a0a6bc1 100644 --- a/components/web_modal.gypi +++ b/components/web_modal.gypi @@ -21,6 +21,9 @@ 'web_modal/modal_dialog_host.cc', 'web_modal/modal_dialog_host.h', 'web_modal/native_web_contents_modal_dialog.h', + 'web_modal/popup_manager.cc', + 'web_modal/popup_manager.h', + 'web_modal/single_popup_manager.h', 'web_modal/single_web_contents_dialog_manager.h', 'web_modal/web_contents_modal_dialog_host.cc', 'web_modal/web_contents_modal_dialog_host.h', diff --git a/components/web_modal/native_web_contents_modal_dialog.h b/components/web_modal/native_web_contents_modal_dialog.h index 266e073..4bb956a 100644 --- a/components/web_modal/native_web_contents_modal_dialog.h +++ b/components/web_modal/native_web_contents_modal_dialog.h @@ -9,6 +9,8 @@ namespace web_modal { +// TODO(gbillock): rename this file + #if defined(OS_MACOSX) // Use a void* since none of the gfx::Native* types are suitable for // representing the web contents modal dialog under Cocoa. @@ -17,6 +19,14 @@ typedef void* NativeWebContentsModalDialog; typedef gfx::NativeView NativeWebContentsModalDialog; #endif +#if defined(OS_MACOSX) +// Use a void* since none of the gfx::Native* types are suitable for +// representing a popup window under Cocoa. +typedef void* NativePopup; +#else +typedef gfx::NativeView NativePopup; +#endif + } // namespace web_modal #endif // COMPONENTS_WEB_MODAL_NATIVE_WEB_CONTENTS_MODAL_DIALOG_H_ diff --git a/components/web_modal/popup_manager.cc b/components/web_modal/popup_manager.cc new file mode 100644 index 0000000..215d4b8 --- /dev/null +++ b/components/web_modal/popup_manager.cc @@ -0,0 +1,129 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/web_modal/popup_manager.h" + +#include "components/web_modal/web_contents_modal_dialog_host.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_user_data.h" +#include "ui/gfx/geometry/size.h" + +using content::WebContents; + +namespace web_modal { + +namespace { + +const char kPopupManagerUserDataKey[] = "PopupManager"; + +// This class provides a hook to get a PopupManager from a WebContents. +// The PopupManager is browser-scoped, but will use a FromWebContents API +// to attach to each WebContents in that browser. +class PopupManagerRelay : public content::WebContentsUserData<PopupManager> { + public: + explicit PopupManagerRelay(base::WeakPtr<PopupManager> manager) + : manager_(manager) {} + + virtual ~PopupManagerRelay() {} + + base::WeakPtr<PopupManager> manager_; +}; + +} // namespace + +PopupManager::PopupManager(WebContentsModalDialogHost* host) + : host_(host), + weak_factory_(this) {} + +PopupManager::~PopupManager() { +} + +void PopupManager::ShowPopup(scoped_ptr<SinglePopupManager> manager) { + content::WebContents* web_contents = manager->GetBoundWebContents(); + // TODO(gbillock): get rid of this when we handle bubbles + DCHECK(web_contents); + + // TODO(gbillock): remove when we port the popup management logic to this + // class. + NativeWebContentsModalDialog dialog = + static_cast<NativeWebContentsModalDialog>(manager->popup()); + + WebContentsModalDialogManager* wm_manager = + WebContentsModalDialogManager::FromWebContents(web_contents); + DCHECK(wm_manager); + wm_manager->ShowModalDialog(dialog); +} + +void PopupManager::ShowModalDialog(NativePopup popup, + content::WebContents* web_contents) { + // TODO make a new native popup manager and call ShowPopup. + // For now just lay off to WCMDM. + WebContentsModalDialogManager* manager = + WebContentsModalDialogManager::FromWebContents(web_contents); + manager->ShowModalDialog(popup); +} + +bool PopupManager::IsWebModalDialogActive( + const content::WebContents* web_contents) const { + if (web_contents == NULL) + return false; + + const WebContentsModalDialogManager* manager = + WebContentsModalDialogManager::FromWebContents(web_contents); + return manager && manager->IsDialogActive(); +} + +void PopupManager::WasFocused(const content::WebContents* web_contents) { + if (!IsWebModalDialogActive(web_contents)) + return; + + const WebContentsModalDialogManager* manager = + WebContentsModalDialogManager::FromWebContents(web_contents); + if (manager) + manager->FocusTopmostDialog(); +} + +void PopupManager::WillClose(NativePopup popup) { +} + +void PopupManager::RegisterWith(content::WebContents* web_contents) { + web_contents->SetUserData(kPopupManagerUserDataKey, + new PopupManagerRelay(weak_factory_.GetWeakPtr())); + // TODO(gbillock): Need to do something more extreme here to manage changing + // popup managers with popups in-flight? +} + +void PopupManager::UnregisterWith(content::WebContents* web_contents) { + web_contents->RemoveUserData(kPopupManagerUserDataKey); + // TODO(gbillock): Need to do something more extreme here to manage changing + // popup managers with popups in-flight? +} + +PopupManager* PopupManager::FromWebContents( + content::WebContents* web_contents) { + PopupManagerRelay* relay = static_cast<PopupManagerRelay*>( + web_contents->GetUserData(kPopupManagerUserDataKey)); + if (!relay) + return NULL; + + return relay->manager_.get(); +} + +gfx::NativeView PopupManager::GetHostView() const { + // TODO(gbillock): replace this with a PopupManagerHost or something. + DCHECK(host_); + return host_->GetHostView(); +} + +void PopupManager::CloseAllDialogsForTesting( + content::WebContents* web_contents) { + // TODO: re-implement, probably in terms of something in the host_, + // or of owned WCMDMs. + WebContentsModalDialogManager* manager = + WebContentsModalDialogManager::FromWebContents(web_contents); + manager->CloseAllDialogs(); +} + +} // namespace web_modal diff --git a/components/web_modal/popup_manager.h b/components/web_modal/popup_manager.h new file mode 100644 index 0000000..cd4d2bb --- /dev/null +++ b/components/web_modal/popup_manager.h @@ -0,0 +1,83 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_WEB_MODAL_POPUP_MANAGER_H_ +#define COMPONENTS_WEB_MODAL_POPUP_MANAGER_H_ + +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "components/web_modal/single_popup_manager.h" + +namespace content { +class WebContents; +} + +namespace gfx { +class Size; +} + +namespace web_modal { + +class WebContentsModalDialogHost; + +// Per-Browser class to manage popups (bubbles, web-modal dialogs). +class PopupManager : public SinglePopupManagerDelegate { + public: + // |host| may be null. + PopupManager(WebContentsModalDialogHost* host); + + virtual ~PopupManager(); + + // Returns the native view which will be the parent of managed popups. + virtual gfx::NativeView GetHostView() const; + + // Schedules a popup governed by the |manager| to be shown. The popup + // may be shown inline with this call, at a later time, or not at all. + virtual void ShowPopup(scoped_ptr<SinglePopupManager> manager); + + // Temporary method: Provides compatibility with existing + // WebContentsModalDialogManager code. + virtual void ShowModalDialog(NativePopup popup, + content::WebContents* web_contents); + + // Returns true if a web modal dialog is active and not closed in the + // given |web_contents|. Note: this is intended for legacy use only; it will + // be deleted at some point -- new code shouldn't use it. + virtual bool IsWebModalDialogActive( + const content::WebContents* web_contents) const; + + // Called when a NativePopup we own is about to be closed. + virtual void WillClose(NativePopup popup) OVERRIDE; + + // Called by views code to re-activate popups anchored to a particular tab + // when that tab gets focus. Note that depending on the situation, more than + // one popup may actually be shown (depending on overlappability). The + // semantics are that the popups that would have been displayed had the tab + // never lost focus are re-focused when tab focus is regained. + virtual void WasFocused(const content::WebContents* web_contents); + + // WebContentsUserData-alike API for retrieving the associated window + // PopupManager from a |web_contents|. Any window which doesn't have a popup + // manager associated will return null -- popups should not be issued against + // that window. + static PopupManager* FromWebContents(content::WebContents* web_contents); + + // Should not be called except by WebContents-owning class; not by clients. + void RegisterWith(content::WebContents* web_contents); + void UnregisterWith(content::WebContents* web_contents); + + // DEPRECATED. + virtual void CloseAllDialogsForTesting(content::WebContents* web_contents); + + private: + WebContentsModalDialogHost* host_; + + base::WeakPtrFactory<PopupManager> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(PopupManager); +}; + +} // namespace web_modal + +#endif // COMPONENTS_WEB_MODAL_POPUP_MANAGER_H_ diff --git a/components/web_modal/single_popup_manager.h b/components/web_modal/single_popup_manager.h new file mode 100644 index 0000000..4ce762a --- /dev/null +++ b/components/web_modal/single_popup_manager.h @@ -0,0 +1,96 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_WEB_MODAL_SINGLE_POPUP_MANAGER_H_ +#define COMPONENTS_WEB_MODAL_SINGLE_POPUP_MANAGER_H_ + +#include "components/web_modal/native_web_contents_modal_dialog.h" + +namespace content { +class WebContents; +} + +namespace web_modal { + +// Interface from SinglePopupManager to PopupManager. +class SinglePopupManagerDelegate { + public: + SinglePopupManagerDelegate() {} + virtual ~SinglePopupManagerDelegate() {} + + // Notify the delegate that the dialog is closing. The + // calling SinglePopupManager will be deleted before the end of this call. + virtual void WillClose(NativePopup popup) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(SinglePopupManagerDelegate); +}; + +// Provides an interface for platform-specific UI implementation for popups. +// Each object will manage a single NativePopup window during its lifecycle. +// The rule of thumb is that only one popup will be shown at a time per tab. +// (Exceptions exist.) +// +// Implementation classes should accept a NativePopup at construction time +// and register to be notified when the dialog is closing, so that it can +// notify its delegate (WillClose method). +class SinglePopupManager { + public: + virtual ~SinglePopupManager() {} + + // If the manager returns non-null to this call, it is bound to a particular + // tab and will be hidden and shown if that tab visibility changes. + virtual content::WebContents* GetBoundWebContents() = 0; + + // Makes the popup visible. + virtual void Show() = 0; + + // Hides the popup without closing it. + virtual void Hide() = 0; + + // Closes the popup. + // This method must call WillClose() on the delegate. + // Important note: this object will be deleted at the close of that + // invocation. + virtual void Close() = 0; + + // Sets focus on the popup. + virtual void Focus() = 0; + + // Pulsates the popup to draw the user's attention to it. + virtual void Pulse() = 0; + + // Returns the popup under management by this object. + virtual NativePopup popup() = 0; + + // Returns true if the popup under management was initiated by a user + // gesture. When this is true, the popup manager will hide any existing + // popups and move the newly-created NativePopup to the top of the display + // queue. + virtual bool HasUserGesture() = 0; + + // Returns true if the popup under management is tolerant of being overlapped + // by other popups. This may be true for large web-modals which cover most of + // the window real estate (e.g. print preview). + virtual bool MayBeOverlapped() = 0; + + // Returns true if the popup under management should close if there is a + // navigation underneath it, including the showing of any interstitial + // content. Popups which relate to the web content being displayed will + // ordinarily set this to true. + // TODO(gbillock): should be generalized in code location or by splitting + // the API to support the same-origin logic in WCMDM::DidNavigateMainFrame. + // TBD right now because we're not sure which knobs need to be set here. + virtual bool ShouldCloseOnNavigation() = 0; + + protected: + SinglePopupManager() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SinglePopupManager); +}; + +} // namespace web_modal + +#endif // COMPONENTS_WEB_MODAL_SINGLE_POPUP_MANAGER_H_ diff --git a/components/web_modal/web_contents_modal_dialog_manager.cc b/components/web_modal/web_contents_modal_dialog_manager.cc index 415926e..f81a9d7 100644 --- a/components/web_modal/web_contents_modal_dialog_manager.cc +++ b/components/web_modal/web_contents_modal_dialog_manager.cc @@ -58,7 +58,7 @@ bool WebContentsModalDialogManager::IsDialogActive() const { return !child_dialogs_.empty(); } -void WebContentsModalDialogManager::FocusTopmostDialog() { +void WebContentsModalDialogManager::FocusTopmostDialog() const { DCHECK(!child_dialogs_.empty()); child_dialogs_.front()->manager->Focus(); } diff --git a/components/web_modal/web_contents_modal_dialog_manager.h b/components/web_modal/web_contents_modal_dialog_manager.h index 7531301..19d844c 100644 --- a/components/web_modal/web_contents_modal_dialog_manager.h +++ b/components/web_modal/web_contents_modal_dialog_manager.h @@ -47,11 +47,10 @@ class WebContentsModalDialogManager // Focus the topmost modal dialog. IsDialogActive() must be true when calling // this function. - void FocusTopmostDialog(); + void FocusTopmostDialog() const; - // Overriden from SingleWebContentsDialogManagerDelegate: + // SingleWebContentsDialogManagerDelegate: virtual content::WebContents* GetWebContents() const OVERRIDE; - // Called when a WebContentsModalDialogs we own is about to be closed. virtual void WillClose(NativeWebContentsModalDialog dialog) OVERRIDE; // For testing. @@ -74,6 +73,7 @@ class WebContentsModalDialogManager private: explicit WebContentsModalDialogManager(content::WebContents* web_contents); friend class content::WebContentsUserData<WebContentsModalDialogManager>; + friend class PopupManager; struct DialogState { DialogState(NativeWebContentsModalDialog dialog, |