diff --git a/BUILD.gn b/BUILD.gn index 773cd9efe..0f17661bb 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -420,6 +420,12 @@ static_library("libcef_static") { "libcef/browser/alloy/alloy_web_contents_view_delegate.h", "libcef/browser/alloy/browser_platform_delegate_alloy.cc", "libcef/browser/alloy/browser_platform_delegate_alloy.h", + "libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.cc", + "libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h", + "libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.cc", + "libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h", + "libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.cc", + "libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h", "libcef/browser/alloy/chrome_browser_process_alloy.cc", "libcef/browser/alloy/chrome_browser_process_alloy.h", "libcef/browser/alloy/chrome_profile_manager_alloy.cc", @@ -655,8 +661,6 @@ static_library("libcef_static") { "libcef/browser/prefs/renderer_prefs.h", "libcef/browser/print_settings_impl.cc", "libcef/browser/print_settings_impl.h", - "libcef/browser/printing/constrained_window_views_client.cc", - "libcef/browser/printing/constrained_window_views_client.h", "libcef/browser/printing/print_view_manager.cc", "libcef/browser/printing/print_view_manager.h", "libcef/browser/process_util_impl.cc", @@ -740,8 +744,6 @@ static_library("libcef_static") { "libcef/browser/views/window_impl.h", "libcef/browser/views/window_view.cc", "libcef/browser/views/window_view.h", - "libcef/browser/web_contents_dialog_helper.cc", - "libcef/browser/web_contents_dialog_helper.h", "libcef/browser/x509_certificate_impl.cc", "libcef/browser/x509_certificate_impl.h", "libcef/browser/x509_cert_principal_impl.cc", @@ -1026,8 +1028,6 @@ static_library("libcef_static") { "libcef/browser/native/browser_platform_delegate_native_win.cc", "libcef/browser/native/browser_platform_delegate_native_win.h", "libcef/browser/native/cursor_util_win.cc", - "libcef/browser/native/javascript_dialog_runner_win.cc", - "libcef/browser/native/javascript_dialog_runner_win.h", "libcef/browser/osr/browser_platform_delegate_osr_win.cc", "libcef/browser/osr/browser_platform_delegate_osr_win.h", ] diff --git a/include/capi/cef_jsdialog_handler_capi.h b/include/capi/cef_jsdialog_handler_capi.h index c0ab4497e..ad63db23c 100644 --- a/include/capi/cef_jsdialog_handler_capi.h +++ b/include/capi/cef_jsdialog_handler_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=c68332a779bab425aa2e6a858d20a43448631890$ +// $hash=942579315e4b8c0819cd2b06becb93670310cd09$ // #ifndef CEF_INCLUDE_CAPI_CEF_JSDIALOG_HANDLER_CAPI_H_ @@ -127,7 +127,7 @@ typedef struct _cef_jsdialog_handler_t { struct _cef_browser_t* browser); /// - // Called when the default implementation dialog is closed. + // Called when the dialog is closed. /// void(CEF_CALLBACK* on_dialog_closed)(struct _cef_jsdialog_handler_t* self, struct _cef_browser_t* browser); diff --git a/include/cef_jsdialog_handler.h b/include/cef_jsdialog_handler.h index b7e094505..17fb8dbe8 100644 --- a/include/cef_jsdialog_handler.h +++ b/include/cef_jsdialog_handler.h @@ -118,7 +118,7 @@ class CefJSDialogHandler : public virtual CefBaseRefCounted { virtual void OnResetDialogState(CefRefPtr browser) {} /// - // Called when the default implementation dialog is closed. + // Called when the dialog is closed. /// /*--cef()--*/ virtual void OnDialogClosed(CefRefPtr browser) {} diff --git a/libcef/browser/alloy/alloy_browser_host_impl.cc b/libcef/browser/alloy/alloy_browser_host_impl.cc index 68ef3d9e4..3f8d5d409 100644 --- a/libcef/browser/alloy/alloy_browser_host_impl.cc +++ b/libcef/browser/alloy/alloy_browser_host_impl.cc @@ -618,6 +618,14 @@ bool AlloyBrowserHostImpl::IsWindowless() const { return is_windowless_; } +bool AlloyBrowserHostImpl::IsVisible() const { + CEF_REQUIRE_UIT(); + if (IsWindowless() && platform_delegate_) { + return !platform_delegate_->IsHidden(); + } + return CefBrowserHostBase::IsVisible(); +} + bool AlloyBrowserHostImpl::IsPictureInPictureSupported() const { // Not currently supported with OSR. return !IsWindowless(); @@ -630,6 +638,11 @@ void AlloyBrowserHostImpl::WindowDestroyed() { CloseBrowser(true); } +bool AlloyBrowserHostImpl::WillBeDestroyed() const { + CEF_REQUIRE_UIT(); + return destruction_state_ >= DESTRUCTION_STATE_ACCEPTED; +} + void AlloyBrowserHostImpl::DestroyBrowser() { CEF_REQUIRE_UIT(); @@ -1233,9 +1246,8 @@ void AlloyBrowserHostImpl::DidNavigatePrimaryMainFramePostCommit( content::JavaScriptDialogManager* AlloyBrowserHostImpl::GetJavaScriptDialogManager(content::WebContents* source) { - if (!javascript_dialog_manager_.get() && platform_delegate_) { - javascript_dialog_manager_.reset(new CefJavaScriptDialogManager( - this, platform_delegate_->CreateJavaScriptDialogRunner())); + if (!javascript_dialog_manager_) { + javascript_dialog_manager_.reset(new CefJavaScriptDialogManager(this)); } return javascript_dialog_manager_.get(); } diff --git a/libcef/browser/alloy/alloy_browser_host_impl.h b/libcef/browser/alloy/alloy_browser_host_impl.h index c1ba3049e..5d5070691 100644 --- a/libcef/browser/alloy/alloy_browser_host_impl.h +++ b/libcef/browser/alloy/alloy_browser_host_impl.h @@ -137,12 +137,16 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase, // Returns true if windowless rendering is enabled. bool IsWindowless() const override; + bool IsVisible() const override; + // Returns true if this browser supports picture-in-picture. bool IsPictureInPictureSupported() const; // Called when the OS window hosting the browser is destroyed. void WindowDestroyed() override; + bool WillBeDestroyed() const override; + // Destroy the browser members. This method should only be called after the // native browser window is not longer processing messages. void DestroyBrowser() override; diff --git a/libcef/browser/alloy/alloy_browser_main.cc b/libcef/browser/alloy/alloy_browser_main.cc index 59deae205..29e54dbc4 100644 --- a/libcef/browser/alloy/alloy_browser_main.cc +++ b/libcef/browser/alloy/alloy_browser_main.cc @@ -8,6 +8,7 @@ #include +#include "libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h" #include "libcef/browser/browser_context.h" #include "libcef/browser/browser_context_keyed_service_factories.h" #include "libcef/browser/context.h" @@ -15,19 +16,21 @@ #include "libcef/browser/extensions/extension_system_factory.h" #include "libcef/browser/file_dialog_runner.h" #include "libcef/browser/net/chrome_scheme_handler.h" -#include "libcef/browser/printing/constrained_window_views_client.h" #include "libcef/browser/thread_util.h" #include "libcef/common/app_manager.h" #include "libcef/common/extensions/extensions_util.h" #include "libcef/common/net/net_resource_provider.h" #include "base/bind.h" +#include "base/feature_list.h" #include "base/strings/string_number_conversions.h" #include "base/task/thread_pool.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/media/router/chrome_media_router_factory.h" #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/plugins/plugin_finder.h" +#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_app_modal_dialog_view_factory.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/common/chrome_switches.h" #include "components/constrained_window/constrained_window_views.h" #include "content/public/browser/gpu_data_manager.h" @@ -170,7 +173,7 @@ AlloyBrowserMainParts::~AlloyBrowserMainParts() { } void AlloyBrowserMainParts::ToolkitInitialized() { - SetConstrainedWindowViewsClient(CreateCefConstrainedWindowViewsClient()); + SetConstrainedWindowViewsClient(CreateAlloyConstrainedWindowViewsClient()); #if defined(USE_AURA) CHECK(aura::Env::GetInstance()); @@ -187,6 +190,15 @@ void AlloyBrowserMainParts::ToolkitInitialized() { #if BUILDFLAG(IS_LINUX) ToolkitInitializedLinux(); #endif + +#if BUILDFLAG(IS_MAC) + if (base::FeatureList::IsEnabled(features::kViewsJSAppModalDialog)) + InstallChromeJavaScriptAppModalDialogViewFactory(); + else + InstallChromeJavaScriptAppModalDialogViewCocoaFactory(); +#else + InstallChromeJavaScriptAppModalDialogViewFactory(); +#endif } void AlloyBrowserMainParts::PreCreateMainMessageLoop() { diff --git a/libcef/browser/alloy/browser_platform_delegate_alloy.cc b/libcef/browser/alloy/browser_platform_delegate_alloy.cc index d79faea40..8e5e79857 100644 --- a/libcef/browser/alloy/browser_platform_delegate_alloy.cc +++ b/libcef/browser/alloy/browser_platform_delegate_alloy.cc @@ -5,6 +5,7 @@ #include "libcef/browser/alloy/browser_platform_delegate_alloy.h" #include "libcef/browser/alloy/alloy_browser_host_impl.h" +#include "libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h" #include "libcef/browser/extensions/browser_extensions_util.h" #include "libcef/browser/extensions/extension_background_host.h" #include "libcef/browser/extensions/extension_system.h" @@ -21,6 +22,7 @@ #include "chrome/browser/ui/prefs/prefs_tab_helper.h" #include "components/find_in_page/find_tab_helper.h" #include "components/find_in_page/find_types.h" +#include "components/javascript_dialogs/tab_modal_dialog_manager.h" #include "components/zoom/zoom_controller.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" @@ -184,10 +186,13 @@ void CefBrowserPlatformDelegateAlloy::BrowserCreated( zoom::ZoomController::CreateForWebContents(web_contents_); } - if (IsPrintPreviewSupported()) { - web_contents_dialog_helper_.reset( - new CefWebContentsDialogHelper(web_contents_, this)); - } + javascript_dialogs::TabModalDialogManager::CreateForWebContents( + web_contents_, + CreateAlloyJavaScriptTabModalDialogManagerDelegateDesktop(web_contents_)); + + // Used for print preview and JavaScript dialogs. + web_contents_dialog_helper_.reset( + new AlloyWebContentsDialogHelper(web_contents_, this)); } void CefBrowserPlatformDelegateAlloy::CreateExtensionHost( @@ -242,6 +247,11 @@ void CefBrowserPlatformDelegateAlloy::BrowserDestroyed( CefBrowserPlatformDelegate::BrowserDestroyed(browser); } +web_modal::WebContentsModalDialogHost* +CefBrowserPlatformDelegateAlloy::GetWebContentsModalDialogHost() const { + return web_contents_dialog_helper_.get(); +} + void CefBrowserPlatformDelegateAlloy::SendCaptureLostEvent() { if (!web_contents_) return; diff --git a/libcef/browser/alloy/browser_platform_delegate_alloy.h b/libcef/browser/alloy/browser_platform_delegate_alloy.h index 914d35e8d..db1060cc8 100644 --- a/libcef/browser/alloy/browser_platform_delegate_alloy.h +++ b/libcef/browser/alloy/browser_platform_delegate_alloy.h @@ -6,8 +6,8 @@ #ifndef CEF_LIBCEF_BROWSER_ALLOY_BROWSER_PLATFORM_DELEGATE_ALLOY_H_ #define CEF_LIBCEF_BROWSER_ALLOY_BROWSER_PLATFORM_DELEGATE_ALLOY_H_ +#include "libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h" #include "libcef/browser/browser_platform_delegate.h" -#include "libcef/browser/web_contents_dialog_helper.h" #include "base/memory/weak_ptr.h" #include "components/find_in_page/find_notification_details.h" @@ -42,6 +42,8 @@ class CefBrowserPlatformDelegateAlloy : public CefBrowserPlatformDelegate { extensions::mojom::ViewType host_type) override; extensions::ExtensionHost* GetExtensionHost() const override; void BrowserDestroyed(CefBrowserHostBase* browser) override; + web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost() + const override; void SendCaptureLostEvent() override; #if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)) void NotifyMoveOrResizeStarted() override; @@ -98,7 +100,7 @@ class CefBrowserPlatformDelegateAlloy : public CefBrowserPlatformDelegate { std::unique_ptr owned_web_contents_; // Used for the print preview dialog. - std::unique_ptr web_contents_dialog_helper_; + std::unique_ptr web_contents_dialog_helper_; // The last find result. This object contains details about the number of // matches, the find selection rectangle, etc. diff --git a/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.cc b/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.cc new file mode 100644 index 000000000..0b0d371cb --- /dev/null +++ b/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.cc @@ -0,0 +1,76 @@ +// Copyright 2022 The Chromium Embedded Framework Authors. +// Portions 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 "libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h" + +#include "libcef/browser/browser_host_base.h" + +#include "base/notreached.h" +#include "components/web_modal/web_contents_modal_dialog_host.h" + +namespace { + +class AlloyConstrainedWindowViewsClient + : public constrained_window::ConstrainedWindowViewsClient { + public: + AlloyConstrainedWindowViewsClient() = default; + + AlloyConstrainedWindowViewsClient(const AlloyConstrainedWindowViewsClient&) = + delete; + AlloyConstrainedWindowViewsClient& operator=( + const AlloyConstrainedWindowViewsClient&) = delete; + + private: + // ConstrainedWindowViewsClient methods: + web_modal::ModalDialogHost* GetModalDialogHost( + gfx::NativeWindow parent) override { + if (auto browser = GetPreferredBrowser(parent)) { + return browser->platform_delegate()->GetWebContentsModalDialogHost(); + } + NOTREACHED(); + return nullptr; + } + + gfx::NativeView GetDialogHostView(gfx::NativeWindow parent) override { + if (auto dialog_host = GetModalDialogHost(parent)) { + return dialog_host->GetHostView(); + } + return gfx::NativeView(); + } + + static CefRefPtr GetPreferredBrowser( + gfx::NativeWindow parent) { + CefRefPtr browser; + + // 1. Browser associated with the top-level native window (owning_window). + // This should be reliable with windowed browsers. However, |parent| will + // always be nullptr with windowless browsers. + if (parent) { + browser = CefBrowserHostBase::GetBrowserForTopLevelNativeWindow(parent); + if (!browser) { + LOG(WARNING) << "No browser associated with top-level native window"; + } + } + + // 2. Browser most likely to be focused. This may be somewhat iffy with + // windowless browsers as there is no guarantee that the client has only + // one browser focused at a time. + if (!browser) { + browser = CefBrowserHostBase::GetLikelyFocusedBrowser(); + if (!browser) { + LOG(WARNING) << "No likely focused browser"; + } + } + + return browser; + } +}; + +} // namespace + +std::unique_ptr +CreateAlloyConstrainedWindowViewsClient() { + return std::make_unique(); +} \ No newline at end of file diff --git a/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h b/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h new file mode 100644 index 000000000..c33a38cc8 --- /dev/null +++ b/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h @@ -0,0 +1,17 @@ +// Copyright 2022 The Chromium Embedded Framework Authors. +// Portions 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 CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_CONSTRAINED_WINDOW_VIEWS_CLIENT_H_ +#define CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_CONSTRAINED_WINDOW_VIEWS_CLIENT_H_ + +#include + +#include "components/constrained_window/constrained_window_views_client.h" + +// Creates a ConstrainedWindowViewsClient for the Chrome environment. +std::unique_ptr +CreateAlloyConstrainedWindowViewsClient(); + +#endif // CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_CONSTRAINED_WINDOW_VIEWS_CLIENT_H_ \ No newline at end of file diff --git a/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.cc b/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.cc new file mode 100644 index 000000000..bb7647bb2 --- /dev/null +++ b/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.cc @@ -0,0 +1,58 @@ +// Copyright 2022 The Chromium Embedded Framework Authors. +// Portions copyright 2020 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 "libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h" + +#include "libcef/browser/browser_host_base.h" + +#include "base/logging.h" + +namespace { + +class AlloyJavaScriptTabModalDialogManagerDelegateDesktop + : public JavaScriptTabModalDialogManagerDelegateDesktop { + public: + explicit AlloyJavaScriptTabModalDialogManagerDelegateDesktop( + content::WebContents* web_contents) + : JavaScriptTabModalDialogManagerDelegateDesktop(web_contents), + web_contents_(web_contents) {} + + AlloyJavaScriptTabModalDialogManagerDelegateDesktop( + const AlloyJavaScriptTabModalDialogManagerDelegateDesktop&) = delete; + AlloyJavaScriptTabModalDialogManagerDelegateDesktop& operator=( + const AlloyJavaScriptTabModalDialogManagerDelegateDesktop&) = delete; + + // javascript_dialogs::TabModalDialogManagerDelegate methods: + void WillRunDialog() override {} + + void DidCloseDialog() override {} + + void SetTabNeedsAttention(bool attention) override {} + + bool IsWebContentsForemost() override { + if (auto browser = + CefBrowserHostBase::GetBrowserForContents(web_contents_)) { + return browser->IsVisible(); + } + return false; + } + + bool IsApp() override { return false; } + + private: + // The WebContents for the tab over which the dialog will be modal. This may + // be different from the WebContents that requested the dialog, such as with + // Chrome app s. + raw_ptr web_contents_; +}; + +} // namespace + +std::unique_ptr +CreateAlloyJavaScriptTabModalDialogManagerDelegateDesktop( + content::WebContents* web_contents) { + return std::make_unique( + web_contents); +} diff --git a/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h b/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h new file mode 100644 index 000000000..4d3df0da1 --- /dev/null +++ b/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h @@ -0,0 +1,18 @@ +// Copyright 2022 The Chromium Embedded Framework 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 CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_JAVASCRIPT_DIALOG_MANAGER_DELEGATE_H_ +#define CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_JAVASCRIPT_DIALOG_MANAGER_DELEGATE_H_ + +#include + +#include "chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_desktop.h" + +// Creates a JavaScriptTabModalDialogManagerDelegateDesktop for the Chrome +// environment. +std::unique_ptr +CreateAlloyJavaScriptTabModalDialogManagerDelegateDesktop( + content::WebContents* web_contents); + +#endif // CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_JAVASCRIPT_DIALOG_MANAGER_DELEGATE_H_ \ No newline at end of file diff --git a/libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.cc b/libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.cc new file mode 100644 index 000000000..3ba919907 --- /dev/null +++ b/libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.cc @@ -0,0 +1,96 @@ +// Copyright (c) 2019 The Chromium Embedded Framework 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 "libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h" + +#include "libcef/browser/browser_platform_delegate.h" + +#include "base/notreached.h" +#include "chrome/browser/platform_util.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "ui/views/widget/widget.h" + +AlloyWebContentsDialogHelper::AlloyWebContentsDialogHelper( + content::WebContents* web_contents, + CefBrowserPlatformDelegate* browser_delegate) + : browser_delegate_(browser_delegate), weak_factory_(this) { + web_modal::WebContentsModalDialogManager::CreateForWebContents(web_contents); + web_modal::WebContentsModalDialogManager::FromWebContents(web_contents) + ->SetDelegate(this); +} + +base::RepeatingClosure +AlloyWebContentsDialogHelper::GetBoundsChangedCallback() { + return base::BindRepeating(&AlloyWebContentsDialogHelper::OnBoundsChanged, + weak_factory_.GetWeakPtr()); +} + +bool AlloyWebContentsDialogHelper::IsWebContentsVisible( + content::WebContents* web_contents) { + if (browser_delegate_->IsWindowless()) { + return !browser_delegate_->IsHidden(); + } else if (auto native_view = web_contents->GetNativeView()) { + return platform_util::IsVisible(native_view); + } + NOTREACHED(); + return false; +} + +web_modal::WebContentsModalDialogHost* +AlloyWebContentsDialogHelper::GetWebContentsModalDialogHost() { + return this; +} + +gfx::NativeView AlloyWebContentsDialogHelper::GetHostView() const { + // Windowless rendering uses GetHostWidget() instead. + if (browser_delegate_->IsWindowless()) { + return gfx::NativeView(); + } + + if (auto widget = browser_delegate_->GetWindowWidget()) { + return widget->GetNativeView(); + } + NOTREACHED(); + return gfx::NativeView(); +} + +gfx::AcceleratedWidget AlloyWebContentsDialogHelper::GetHostWidget() const { +#if defined(USE_AURA) + // Windowed rendering uses GetHostView() instead. + if (!browser_delegate_->IsWindowless()) { + return gfx::kNullAcceleratedWidget; + } + + if (auto parent_widget = browser_delegate_->GetHostWindowHandle()) { + return parent_widget; + } +#endif // defined(USE_AURA) + NOTREACHED(); + return gfx::kNullAcceleratedWidget; +} + +gfx::Point AlloyWebContentsDialogHelper::GetDialogPosition( + const gfx::Size& size) { + return browser_delegate_->GetDialogPosition(size); +} + +gfx::Size AlloyWebContentsDialogHelper::GetMaximumDialogSize() { + return browser_delegate_->GetMaximumDialogSize(); +} + +void AlloyWebContentsDialogHelper::AddObserver( + web_modal::ModalDialogHostObserver* observer) { + if (observer && !observer_list_.HasObserver(observer)) + observer_list_.AddObserver(observer); +} + +void AlloyWebContentsDialogHelper::RemoveObserver( + web_modal::ModalDialogHostObserver* observer) { + observer_list_.RemoveObserver(observer); +} + +void AlloyWebContentsDialogHelper::OnBoundsChanged() { + for (auto& observer : observer_list_) + observer.OnPositionRequiresUpdate(); +} diff --git a/libcef/browser/web_contents_dialog_helper.h b/libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h similarity index 74% rename from libcef/browser/web_contents_dialog_helper.h rename to libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h index 39be126bf..3b765a112 100644 --- a/libcef/browser/web_contents_dialog_helper.h +++ b/libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h @@ -2,8 +2,8 @@ // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. -#ifndef CEF_LIBCEF_BROWSER_WEB_CONTENTS_DIALOG_HELPER_H_ -#define CEF_LIBCEF_BROWSER_WEB_CONTENTS_DIALOG_HELPER_H_ +#ifndef CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_WEB_CONTENTS_DIALOG_HELPER_H_ +#define CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_WEB_CONTENTS_DIALOG_HELPER_H_ #pragma once #include "base/callback_forward.h" @@ -15,12 +15,12 @@ class CefBrowserPlatformDelegate; -class CefWebContentsDialogHelper +class AlloyWebContentsDialogHelper : public web_modal::WebContentsModalDialogManagerDelegate, public web_modal::WebContentsModalDialogHost { public: - CefWebContentsDialogHelper(content::WebContents* web_contents, - CefBrowserPlatformDelegate* browser_delegate); + AlloyWebContentsDialogHelper(content::WebContents* web_contents, + CefBrowserPlatformDelegate* browser_delegate); base::RepeatingClosure GetBoundsChangedCallback(); @@ -31,6 +31,7 @@ class CefWebContentsDialogHelper // web_modal::WebContentsModalDialogHost methods: gfx::NativeView GetHostView() const override; + gfx::AcceleratedWidget GetHostWidget() const override; gfx::Point GetDialogPosition(const gfx::Size& size) override; gfx::Size GetMaximumDialogSize() override; void AddObserver(web_modal::ModalDialogHostObserver* observer) override; @@ -45,7 +46,7 @@ class CefWebContentsDialogHelper base::ObserverList::Unchecked observer_list_; - base::WeakPtrFactory weak_factory_; + base::WeakPtrFactory weak_factory_; }; -#endif // CEF_LIBCEF_BROWSER_WEB_CONTENTS_DIALOG_HELPER_H_ +#endif // CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_WEB_CONTENTS_DIALOG_HELPER_H_ diff --git a/libcef/browser/browser_host_base.cc b/libcef/browser/browser_host_base.cc index bbb782f79..c855fe8c4 100644 --- a/libcef/browser/browser_host_base.cc +++ b/libcef/browser/browser_host_base.cc @@ -16,6 +16,7 @@ #include "libcef/common/net/url_util.h" #include "base/logging.h" +#include "chrome/browser/platform_util.h" #include "chrome/browser/spellchecker/spellcheck_factory.h" #include "chrome/browser/spellchecker/spellcheck_service.h" #include "components/favicon/core/favicon_url.h" @@ -138,6 +139,39 @@ CefRefPtr CefBrowserHostBase::GetBrowserForGlobalId( } } +// static +CefRefPtr +CefBrowserHostBase::GetBrowserForTopLevelNativeWindow( + gfx::NativeWindow owning_window) { + DCHECK(owning_window); + CEF_REQUIRE_UIT(); + + for (const auto& browser_info : + CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) { + if (auto browser = browser_info->browser()) { + if (browser->GetTopLevelNativeWindow() == owning_window) + return browser; + } + } + + return nullptr; +} + +// static +CefRefPtr CefBrowserHostBase::GetLikelyFocusedBrowser() { + CEF_REQUIRE_UIT(); + + for (const auto& browser_info : + CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) { + if (auto browser = browser_info->browser()) { + if (browser->IsFocused()) + return browser; + } + } + + return nullptr; +} + CefBrowserHostBase::CefBrowserHostBase( const CefBrowserSettings& settings, CefRefPtr client, @@ -975,6 +1009,18 @@ bool CefBrowserHostBase::IsFocused() const { return false; } +bool CefBrowserHostBase::IsVisible() const { + CEF_REQUIRE_UIT(); + // Windowless browsers always return nullptr from GetNativeView(). + if (!IsWindowless()) { + auto web_contents = GetWebContents(); + if (web_contents) { + return platform_util::IsVisible(web_contents->GetNativeView()); + } + } + return false; +} + bool CefBrowserHostBase::EnsureDevToolsManager() { CEF_REQUIRE_UIT(); if (!contents_delegate_->web_contents()) diff --git a/libcef/browser/browser_host_base.h b/libcef/browser/browser_host_base.h index 016bfb040..d1bd9aee7 100644 --- a/libcef/browser/browser_host_base.h +++ b/libcef/browser/browser_host_base.h @@ -128,6 +128,14 @@ class CefBrowserHostBase : public CefBrowserHost, // Returns the browser associated with the specified global ID. static CefRefPtr GetBrowserForGlobalId( const content::GlobalRenderFrameHostId& global_id); + // Returns the browser associated with the specified top-level window. + static CefRefPtr GetBrowserForTopLevelNativeWindow( + gfx::NativeWindow owning_window); + + // Returns the browser most likely to be focused. This may be somewhat iffy + // with windowless browsers as there is no guarantee that the client has only + // one browser focused at a time. + static CefRefPtr GetLikelyFocusedBrowser(); CefBrowserHostBase( const CefBrowserSettings& settings, @@ -146,6 +154,10 @@ class CefBrowserHostBase : public CefBrowserHost, // destroyed. virtual void WindowDestroyed() = 0; + // Returns true if the browser is in the process of being destroyed. Called on + // the UI thread only. + virtual bool WillBeDestroyed() const = 0; + // Called on the UI thread after the associated WebContents is destroyed. // Also called from CefBrowserInfoManager::DestroyAllBrowsers if the browser // was not properly shut down. @@ -312,6 +324,9 @@ class CefBrowserHostBase : public CefBrowserHost, // on the client to properly configure focus state. bool IsFocused() const; + // Returns true if this browser is currently visible. + virtual bool IsVisible() const; + protected: bool EnsureDevToolsManager(); void InitializeDevToolsRegistrationOnUIThread( diff --git a/libcef/browser/browser_platform_delegate.cc b/libcef/browser/browser_platform_delegate.cc index 06432603c..cbaede478 100644 --- a/libcef/browser/browser_platform_delegate.cc +++ b/libcef/browser/browser_platform_delegate.cc @@ -131,6 +131,12 @@ CefRefPtr CefBrowserPlatformDelegate::GetBrowserView() const { return nullptr; } +web_modal::WebContentsModalDialogHost* +CefBrowserPlatformDelegate::GetWebContentsModalDialogHost() const { + NOTREACHED(); + return nullptr; +} + void CefBrowserPlatformDelegate::PopupWebContentsCreated( const CefBrowserSettings& settings, CefRefPtr client, @@ -226,7 +232,6 @@ CefEventHandle CefBrowserPlatformDelegate::GetEventHandle( std::unique_ptr CefBrowserPlatformDelegate::CreateJavaScriptDialogRunner() { - NOTIMPLEMENTED(); return nullptr; } @@ -253,6 +258,11 @@ void CefBrowserPlatformDelegate::WasHidden(bool hidden) { NOTREACHED(); } +bool CefBrowserPlatformDelegate::IsHidden() const { + NOTREACHED(); + return false; +} + void CefBrowserPlatformDelegate::NotifyScreenInfoChanged() { NOTREACHED(); } @@ -351,13 +361,18 @@ void CefBrowserPlatformDelegate::AccessibilityLocationChangesReceived( gfx::Point CefBrowserPlatformDelegate::GetDialogPosition( const gfx::Size& size) { - NOTREACHED(); - return gfx::Point(); + const gfx::Size& max_size = GetMaximumDialogSize(); + return gfx::Point((max_size.width() - size.width()) / 2, + (max_size.height() - size.height()) / 2); } gfx::Size CefBrowserPlatformDelegate::GetMaximumDialogSize() { - NOTREACHED(); - return gfx::Size(); + if (!web_contents_) + return gfx::Size(); + + // The dialog should try to fit within the overlay for the web contents. + // Note that, for things like print preview, this is just a suggested maximum. + return web_contents_->GetContainerBounds().size(); } void CefBrowserPlatformDelegate::SetAutoResizeEnabled(bool enabled, diff --git a/libcef/browser/browser_platform_delegate.h b/libcef/browser/browser_platform_delegate.h index 09b09e4c4..d6b840409 100644 --- a/libcef/browser/browser_platform_delegate.h +++ b/libcef/browser/browser_platform_delegate.h @@ -61,6 +61,10 @@ namespace views { class Widget; } +namespace web_modal { +class WebContentsModalDialogHost; +} + struct CefBrowserCreateParams; class CefBrowserHostBase; class CefJavaScriptDialogRunner; @@ -178,6 +182,10 @@ class CefBrowserPlatformDelegate { // based browsers. virtual CefRefPtr GetBrowserView() const; + // Returns the WebContentsModalDialogHost associated with this browser. + virtual web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost() + const; + // Called after the WebContents have been created for a new popup browser // parented to this browser but before the AlloyBrowserHostImpl is created for // the popup. |is_devtools| will be true if the popup will host DevTools. This @@ -289,6 +297,10 @@ class CefBrowserPlatformDelegate { // Notify the browser that it was hidden. Only used with windowless rendering. virtual void WasHidden(bool hidden); + // Returns true if the browser is currently hidden. Only used with windowless + // rendering. + virtual bool IsHidden() const; + // Notify the browser that screen information has changed. Only used with // windowless rendering. virtual void NotifyScreenInfoChanged(); diff --git a/libcef/browser/chrome/browser_platform_delegate_chrome.cc b/libcef/browser/chrome/browser_platform_delegate_chrome.cc index a3fc15ed0..83820643d 100644 --- a/libcef/browser/chrome/browser_platform_delegate_chrome.cc +++ b/libcef/browser/chrome/browser_platform_delegate_chrome.cc @@ -8,6 +8,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/gfx/geometry/point.h" @@ -47,6 +48,16 @@ CefWindowHandle CefBrowserPlatformDelegateChrome::GetHostWindowHandle() const { return view_util::GetWindowHandle(GetNativeWindow()); } +web_modal::WebContentsModalDialogHost* +CefBrowserPlatformDelegateChrome::GetWebContentsModalDialogHost() const { + if (chrome_browser_) { + ChromeWebModalDialogManagerDelegate* manager = chrome_browser_; + return manager->GetWebContentsModalDialogHost(); + } + NOTREACHED(); + return nullptr; +} + SkColor CefBrowserPlatformDelegateChrome::GetBackgroundColor() const { return native_delegate_->GetBackgroundColor(); } @@ -124,5 +135,6 @@ void CefBrowserPlatformDelegateChrome::set_chrome_browser(Browser* browser) { gfx::NativeWindow CefBrowserPlatformDelegateChrome::GetNativeWindow() const { if (chrome_browser_ && chrome_browser_->window()) return chrome_browser_->window()->GetNativeWindow(); + NOTREACHED(); return gfx::NativeWindow(); } diff --git a/libcef/browser/chrome/browser_platform_delegate_chrome.h b/libcef/browser/chrome/browser_platform_delegate_chrome.h index e237db82e..238f30c52 100644 --- a/libcef/browser/chrome/browser_platform_delegate_chrome.h +++ b/libcef/browser/chrome/browser_platform_delegate_chrome.h @@ -25,6 +25,8 @@ class CefBrowserPlatformDelegateChrome void BrowserCreated(CefBrowserHostBase* browser) override; void BrowserDestroyed(CefBrowserHostBase* browser) override; CefWindowHandle GetHostWindowHandle() const override; + web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost() + const override; SkColor GetBackgroundColor() const override; void SendKeyEvent(const CefKeyEvent& event) override; void SendMouseClickEvent(const CefMouseEvent& event, diff --git a/libcef/browser/chrome/chrome_browser_host_impl.cc b/libcef/browser/chrome/chrome_browser_host_impl.cc index 256131364..910f55e3e 100644 --- a/libcef/browser/chrome/chrome_browser_host_impl.cc +++ b/libcef/browser/chrome/chrome_browser_host_impl.cc @@ -538,6 +538,12 @@ void ChromeBrowserHostImpl::WindowDestroyed() { platform_delegate_->CloseHostWindow(); } +bool ChromeBrowserHostImpl::WillBeDestroyed() const { + CEF_REQUIRE_UIT(); + // TODO(chrome): Modify this to support DoClose(), see issue #3294. + return !!browser_; +} + void ChromeBrowserHostImpl::DestroyBrowser() { CEF_REQUIRE_UIT(); browser_ = nullptr; diff --git a/libcef/browser/chrome/chrome_browser_host_impl.h b/libcef/browser/chrome/chrome_browser_host_impl.h index c532d89d6..167cbc7a1 100644 --- a/libcef/browser/chrome/chrome_browser_host_impl.h +++ b/libcef/browser/chrome/chrome_browser_host_impl.h @@ -150,6 +150,7 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase { // CefBrowserHostBase methods: void WindowDestroyed() override; + bool WillBeDestroyed() const override; void DestroyBrowser() override; void DoCloseBrowser(bool force_close); diff --git a/libcef/browser/extensions/browser_platform_delegate_background.cc b/libcef/browser/extensions/browser_platform_delegate_background.cc index 198dca0b5..949f3470b 100644 --- a/libcef/browser/extensions/browser_platform_delegate_background.cc +++ b/libcef/browser/extensions/browser_platform_delegate_background.cc @@ -103,11 +103,6 @@ CefEventHandle CefBrowserPlatformDelegateBackground::GetEventHandle( return native_delegate_->GetEventHandle(event); } -std::unique_ptr -CefBrowserPlatformDelegateBackground::CreateJavaScriptDialogRunner() { - return native_delegate_->CreateJavaScriptDialogRunner(); -} - std::unique_ptr CefBrowserPlatformDelegateBackground::CreateMenuRunner() { // No default menu implementation for background browsers. diff --git a/libcef/browser/extensions/browser_platform_delegate_background.h b/libcef/browser/extensions/browser_platform_delegate_background.h index ab44eb544..39ae59f2f 100644 --- a/libcef/browser/extensions/browser_platform_delegate_background.h +++ b/libcef/browser/extensions/browser_platform_delegate_background.h @@ -41,8 +41,6 @@ class CefBrowserPlatformDelegateBackground const content::NativeWebKeyboardEvent& event) override; CefEventHandle GetEventHandle( const content::NativeWebKeyboardEvent& event) const override; - std::unique_ptr CreateJavaScriptDialogRunner() - override; std::unique_ptr CreateMenuRunner() override; // CefBrowserPlatformDelegateNative::WindowlessHandler methods: diff --git a/libcef/browser/file_dialog_runner.cc b/libcef/browser/file_dialog_runner.cc index effc1cd35..ccb842eae 100644 --- a/libcef/browser/file_dialog_runner.cc +++ b/libcef/browser/file_dialog_runner.cc @@ -6,7 +6,6 @@ #include "libcef/browser/file_dialog_runner.h" #include "libcef/browser/browser_host_base.h" -#include "libcef/browser/browser_info_manager.h" #include "libcef/browser/extensions/browser_extensions_util.h" #include "base/memory/singleton.h" @@ -50,32 +49,6 @@ class CefSelectFileDialogFactory final : public ui::SelectFileDialogFactory { CefSelectFileDialogFactory() { ui::SelectFileDialog::SetFactory(this); } }; -CefRefPtr GetBrowserForTopLevelNativeWindow( - gfx::NativeWindow owning_window) { - DCHECK(owning_window); - for (const auto& browser_info : - CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) { - if (auto browser = browser_info->browser()) { - if (browser->GetTopLevelNativeWindow() == owning_window) - return browser; - } - } - - return nullptr; -} - -CefRefPtr GetLikelyFocusedBrowser() { - for (const auto& browser_info : - CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) { - if (auto browser = browser_info->browser()) { - if (browser->IsFocused()) - return browser; - } - } - - return nullptr; -} - // Delegates the running of the dialog to CefFileDialogManager. class CefSelectFileDialog final : public ui::SelectFileDialog { public: @@ -118,7 +91,8 @@ class CefSelectFileDialog final : public ui::SelectFileDialog { // This should be reliable with windowed browsers. However, |owning_window| // will always be nullptr with windowless browsers. if (!browser_ && owning_window) { - browser_ = GetBrowserForTopLevelNativeWindow(owning_window); + browser_ = + CefBrowserHostBase::GetBrowserForTopLevelNativeWindow(owning_window); if (!browser_) { LOG(WARNING) << "No browser associated with top-level native window"; } @@ -128,7 +102,7 @@ class CefSelectFileDialog final : public ui::SelectFileDialog { // windowless browsers as there is no guarantee that the client has only // one browser focused at a time. if (!browser_) { - browser_ = GetLikelyFocusedBrowser(); + browser_ = CefBrowserHostBase::GetLikelyFocusedBrowser(); if (!browser_) { LOG(WARNING) << "No likely focused browser"; } diff --git a/libcef/browser/javascript_dialog_manager.cc b/libcef/browser/javascript_dialog_manager.cc index 8b7bdbca6..8365c06c2 100644 --- a/libcef/browser/javascript_dialog_manager.cc +++ b/libcef/browser/javascript_dialog_manager.cc @@ -7,13 +7,13 @@ #include -#include "libcef/browser/alloy/alloy_browser_host_impl.h" +#include "libcef/browser/browser_host_base.h" #include "libcef/browser/thread_util.h" #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "components/url_formatter/elide_url.h" +#include "components/javascript_dialogs/tab_modal_dialog_manager.h" namespace { @@ -60,21 +60,26 @@ class CefJSDialogCallbackImpl : public CefJSDialogCallback { IMPLEMENT_REFCOUNTING(CefJSDialogCallbackImpl); }; +javascript_dialogs::TabModalDialogManager* GetTabModalDialogManager( + content::WebContents* web_contents) { + return javascript_dialogs::TabModalDialogManager::FromWebContents( + web_contents); +} + } // namespace CefJavaScriptDialogManager::CefJavaScriptDialogManager( - AlloyBrowserHostImpl* browser, - std::unique_ptr runner) - : browser_(browser), - runner_(std::move(runner)), - dialog_running_(false), - weak_ptr_factory_(this) {} + CefBrowserHostBase* browser) + : browser_(browser), weak_ptr_factory_(this) {} CefJavaScriptDialogManager::~CefJavaScriptDialogManager() {} void CefJavaScriptDialogManager::Destroy() { - if (runner_.get()) { - runner_.reset(nullptr); + if (handler_) { + CancelDialogs(nullptr, false); + } + if (runner_) { + runner_.reset(); } } @@ -86,13 +91,19 @@ void CefJavaScriptDialogManager::RunJavaScriptDialog( const std::u16string& default_prompt_text, DialogClosedCallback callback, bool* did_suppress_message) { + *did_suppress_message = false; + const GURL& origin_url = render_frame_host->GetLastCommittedURL(); - CefRefPtr client = browser_->GetClient(); - if (client.get()) { - CefRefPtr handler = client->GetJSDialogHandler(); - if (handler.get()) { - *did_suppress_message = false; + // Always call DialogClosed(). + callback = + base::BindOnce(&CefJavaScriptDialogManager::DialogClosed, + weak_ptr_factory_.GetWeakPtr(), std::move(callback)); + + if (auto client = browser_->GetClient()) { + if (auto handler = client->GetJSDialogHandler()) { + // If the dialog is handled this will be cleared in DialogClosed(). + handler_ = handler; CefRefPtr callbackPtr( new CefJSDialogCallbackImpl(std::move(callback))); @@ -110,32 +121,40 @@ void CefJavaScriptDialogManager::RunJavaScriptDialog( // |callback| may be null if the user executed it despite returning false. callback = callbackPtr->Disconnect(); - if (callback.is_null() || *did_suppress_message) + if (callback.is_null()) { + LOG(WARNING) + << "OnJSDialog should return true when executing the callback"; return; + } + + if (*did_suppress_message) { + // Call OnResetDialogState but don't execute |callback|. + CancelDialogs(web_contents, /*reset_state=*/true); + return; + } + + handler_ = nullptr; } } - *did_suppress_message = false; + DCHECK(!handler_); - if (!runner_.get() || dialog_running_) { - // Suppress the dialog if there is no platform runner or if the dialog is - // currently running. - if (!runner_.get()) - LOG(WARNING) << "No javascript dialog runner available for this platform"; - *did_suppress_message = true; + if (InitializeRunner()) { + runner_->Run(browser_, message_type, origin_url, message_text, + default_prompt_text, std::move(callback)); return; } - dialog_running_ = true; + if (!CanUseChromeDialogs()) { + // Dismiss the dialog. + std::move(callback).Run(false, std::u16string()); + return; + } - const std::u16string& display_url = - url_formatter::FormatUrlForSecurityDisplay(origin_url); - - DCHECK(!callback.is_null()); - runner_->Run( - browser_, message_type, display_url, message_text, default_prompt_text, - base::BindOnce(&CefJavaScriptDialogManager::DialogClosed, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + auto manager = GetTabModalDialogManager(web_contents); + manager->RunJavaScriptDialog(web_contents, render_frame_host, message_type, + message_text, default_prompt_text, + std::move(callback), did_suppress_message); } void CefJavaScriptDialogManager::RunBeforeUnloadDialog( @@ -143,8 +162,7 @@ void CefJavaScriptDialogManager::RunBeforeUnloadDialog( content::RenderFrameHost* render_frame_host, bool is_reload, DialogClosedCallback callback) { - if (browser_->destruction_state() >= - AlloyBrowserHostImpl::DESTRUCTION_STATE_ACCEPTED) { + if (browser_->WillBeDestroyed()) { // Currently destroying the browser. Accept the unload without showing // the prompt. std::move(callback).Run(true, std::u16string()); @@ -153,80 +171,138 @@ void CefJavaScriptDialogManager::RunBeforeUnloadDialog( const std::u16string& message_text = u"Is it OK to leave/reload this page?"; - CefRefPtr client = browser_->GetClient(); - if (client.get()) { - CefRefPtr handler = client->GetJSDialogHandler(); - if (handler.get()) { + // Always call DialogClosed(). + callback = + base::BindOnce(&CefJavaScriptDialogManager::DialogClosed, + weak_ptr_factory_.GetWeakPtr(), std::move(callback)); + + if (auto client = browser_->GetClient()) { + if (auto handler = client->GetJSDialogHandler()) { + // If the dialog is handled this will be cleared in DialogClosed(). + handler_ = handler; + CefRefPtr callbackPtr( new CefJSDialogCallbackImpl(std::move(callback))); // Execute the user callback. bool handled = handler->OnBeforeUnloadDialog( browser_, message_text, is_reload, callbackPtr.get()); - if (handled) + if (handled) { return; + } // |callback| may be null if the user executed it despite returning false. callback = callbackPtr->Disconnect(); - if (callback.is_null()) + if (callback.is_null()) { + LOG(WARNING) << "OnBeforeUnloadDialog should return true when " + "executing the callback"; return; + } + + handler_ = nullptr; } } - if (!runner_.get() || dialog_running_) { - if (!runner_.get()) - LOG(WARNING) << "No javascript dialog runner available for this platform"; - // Suppress the dialog if there is no platform runner or if the dialog is - // currently running. + DCHECK(!handler_); + + if (InitializeRunner()) { + runner_->Run(browser_, content::JAVASCRIPT_DIALOG_TYPE_CONFIRM, + /*origin_url=*/GURL(), message_text, + /*default_prompt_text=*/std::u16string(), std::move(callback)); + return; + } + + if (!CanUseChromeDialogs()) { + // Accept the unload without showing the prompt. std::move(callback).Run(true, std::u16string()); return; } - dialog_running_ = true; + auto manager = GetTabModalDialogManager(web_contents); + manager->RunBeforeUnloadDialog(web_contents, render_frame_host, is_reload, + std::move(callback)); +} - DCHECK(!callback.is_null()); - runner_->Run( - browser_, content::JAVASCRIPT_DIALOG_TYPE_CONFIRM, - std::u16string(), // display_url - message_text, - std::u16string(), // default_prompt_text - base::BindOnce(&CefJavaScriptDialogManager::DialogClosed, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +bool CefJavaScriptDialogManager::HandleJavaScriptDialog( + content::WebContents* web_contents, + bool accept, + const std::u16string* prompt_override) { + if (handler_) { + DialogClosed(base::NullCallback(), accept, + prompt_override ? *prompt_override : std::u16string()); + return true; + } + + if (runner_) { + runner_->Handle(accept, prompt_override); + return true; + } + + if (!CanUseChromeDialogs()) + return true; + + auto manager = GetTabModalDialogManager(web_contents); + return manager->HandleJavaScriptDialog(web_contents, accept, prompt_override); } void CefJavaScriptDialogManager::CancelDialogs( content::WebContents* web_contents, bool reset_state) { - CefRefPtr client = browser_->GetClient(); - if (client.get()) { - CefRefPtr handler = client->GetJSDialogHandler(); - if (handler.get()) { - // Execute the user callback. - handler->OnResetDialogState(browser_); + if (handler_) { + if (reset_state) { + handler_->OnResetDialogState(browser_); } + handler_ = nullptr; + return; } - if (runner_.get() && dialog_running_) { + if (runner_) { runner_->Cancel(); - dialog_running_ = false; + return; } + + // Null when called from DialogClosed() or Destroy(). + if (!web_contents) + return; + + if (!CanUseChromeDialogs()) + return; + + auto manager = GetTabModalDialogManager(web_contents); + manager->CancelDialogs(web_contents, reset_state); } void CefJavaScriptDialogManager::DialogClosed( DialogClosedCallback callback, bool success, const std::u16string& user_input) { - CefRefPtr client = browser_->GetClient(); - if (client.get()) { - CefRefPtr handler = client->GetJSDialogHandler(); - if (handler.get()) - handler->OnDialogClosed(browser_); + if (handler_) { + handler_->OnDialogClosed(browser_); + // Call OnResetDialogState. + CancelDialogs(/*web_contents=*/nullptr, /*reset_state=*/true); } - DCHECK(runner_.get()); - DCHECK(dialog_running_); - - dialog_running_ = false; - - std::move(callback).Run(success, user_input); + // Null when called from HandleJavaScriptDialog(). + if (!callback.is_null()) { + std::move(callback).Run(success, user_input); + } } + +bool CefJavaScriptDialogManager::InitializeRunner() { + if (!runner_initialized_) { + runner_ = browser_->platform_delegate()->CreateJavaScriptDialogRunner(); + runner_initialized_ = true; + } + return !!runner_.get(); +} + +bool CefJavaScriptDialogManager::CanUseChromeDialogs() const { + if (browser_->IsWindowless() && + browser_->GetWindowHandle() == kNullWindowHandle) { + LOG(ERROR) << "Default dialog implementation requires a parent window " + "handle; canceling the JS dialog"; + return false; + } + + return true; +} \ No newline at end of file diff --git a/libcef/browser/javascript_dialog_manager.h b/libcef/browser/javascript_dialog_manager.h index 07bb9e6f6..241b4c1b2 100644 --- a/libcef/browser/javascript_dialog_manager.h +++ b/libcef/browser/javascript_dialog_manager.h @@ -7,20 +7,21 @@ #define CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_MANAGER_H_ #pragma once +#include #include +#include "include/cef_jsdialog_handler.h" #include "libcef/browser/javascript_dialog_runner.h" #include "base/memory/weak_ptr.h" #include "content/public/browser/javascript_dialog_manager.h" -class AlloyBrowserHostImpl; +class CefBrowserHostBase; class CefJavaScriptDialogManager : public content::JavaScriptDialogManager { public: // |runner| may be NULL if the platform doesn't implement dialogs. - CefJavaScriptDialogManager(AlloyBrowserHostImpl* browser, - std::unique_ptr runner); + explicit CefJavaScriptDialogManager(CefBrowserHostBase* browser); CefJavaScriptDialogManager(const CefJavaScriptDialogManager&) = delete; CefJavaScriptDialogManager& operator=(const CefJavaScriptDialogManager&) = @@ -43,6 +44,9 @@ class CefJavaScriptDialogManager : public content::JavaScriptDialogManager { content::RenderFrameHost* render_frame_host, bool is_reload, DialogClosedCallback callback) override; + bool HandleJavaScriptDialog(content::WebContents* web_contents, + bool accept, + const std::u16string* prompt_override) override; void CancelDialogs(content::WebContents* web_contents, bool reset_state) override; @@ -52,13 +56,17 @@ class CefJavaScriptDialogManager : public content::JavaScriptDialogManager { bool success, const std::u16string& user_input); - // AlloyBrowserHostImpl pointer is guaranteed to outlive this object. - AlloyBrowserHostImpl* browser_; + bool InitializeRunner(); + + bool CanUseChromeDialogs() const; + + // CefBrowserHostBase pointer is guaranteed to outlive this object. + CefBrowserHostBase* const browser_; + + CefRefPtr handler_; std::unique_ptr runner_; - - // True if a dialog is currently running. - bool dialog_running_; + bool runner_initialized_ = false; // Must be the last member. base::WeakPtrFactory weak_ptr_factory_; diff --git a/libcef/browser/javascript_dialog_runner.h b/libcef/browser/javascript_dialog_runner.h index d9e2488e7..bbceece2d 100644 --- a/libcef/browser/javascript_dialog_runner.h +++ b/libcef/browser/javascript_dialog_runner.h @@ -7,10 +7,10 @@ #define CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_RUNNER_H_ #pragma once -#include "base/callback.h" +#include "content/public/browser/javascript_dialog_manager.h" #include "content/public/common/javascript_dialog_type.h" -class AlloyBrowserHostImpl; +class CefBrowserHostBase; class CefJavaScriptDialogRunner { public: @@ -19,17 +19,19 @@ class CefJavaScriptDialogRunner { delete; using DialogClosedCallback = - base::OnceCallback; + content::JavaScriptDialogManager::DialogClosedCallback; // Run the dialog. Execute |callback| on completion. - virtual void Run(AlloyBrowserHostImpl* browser, + virtual void Run(CefBrowserHostBase* browser, content::JavaScriptDialogType message_type, - const std::u16string& display_url, + const GURL& origin_url, const std::u16string& message_text, const std::u16string& default_prompt_text, DialogClosedCallback callback) = 0; + // Dismiss the dialog with the specified results. + virtual void Handle(bool accept, const std::u16string* prompt_override) = 0; + // Cancel a dialog mid-flight. virtual void Cancel() = 0; diff --git a/libcef/browser/native/browser_platform_delegate_native_linux.cc b/libcef/browser/native/browser_platform_delegate_native_linux.cc index 238302a69..5972a3134 100644 --- a/libcef/browser/native/browser_platform_delegate_native_linux.cc +++ b/libcef/browser/native/browser_platform_delegate_native_linux.cc @@ -233,17 +233,6 @@ CefEventHandle CefBrowserPlatformDelegateNativeLinux::GetEventHandle( return nullptr; } -gfx::Point CefBrowserPlatformDelegateNativeLinux::GetDialogPosition( - const gfx::Size& size) { - const gfx::Size& max_size = GetMaximumDialogSize(); - return gfx::Point((max_size.width() - size.width()) / 2, - (max_size.height() - size.height()) / 2); -} - -gfx::Size CefBrowserPlatformDelegateNativeLinux::GetMaximumDialogSize() { - return GetWindowWidget()->GetWindowBoundsInScreen().size(); -} - ui::KeyEvent CefBrowserPlatformDelegateNativeLinux::TranslateUiKeyEvent( const CefKeyEvent& key_event) const { int flags = TranslateUiEventModifiers(key_event.modifiers); diff --git a/libcef/browser/native/browser_platform_delegate_native_linux.h b/libcef/browser/native/browser_platform_delegate_native_linux.h index 05be1f4cb..0da0cc830 100644 --- a/libcef/browser/native/browser_platform_delegate_native_linux.h +++ b/libcef/browser/native/browser_platform_delegate_native_linux.h @@ -34,8 +34,6 @@ class CefBrowserPlatformDelegateNativeLinux const content::NativeWebKeyboardEvent& event) override; CefEventHandle GetEventHandle( const content::NativeWebKeyboardEvent& event) const override; - gfx::Point GetDialogPosition(const gfx::Size& size) override; - gfx::Size GetMaximumDialogSize() override; // CefBrowserPlatformDelegateNativeAura methods: ui::KeyEvent TranslateUiKeyEvent(const CefKeyEvent& key_event) const override; diff --git a/libcef/browser/native/browser_platform_delegate_native_mac.h b/libcef/browser/native/browser_platform_delegate_native_mac.h index 55c529bf0..ba7211df3 100644 --- a/libcef/browser/native/browser_platform_delegate_native_mac.h +++ b/libcef/browser/native/browser_platform_delegate_native_mac.h @@ -44,8 +44,6 @@ class CefBrowserPlatformDelegateNativeMac std::unique_ptr CreateJavaScriptDialogRunner() override; std::unique_ptr CreateMenuRunner() override; - gfx::Point GetDialogPosition(const gfx::Size& size) override; - gfx::Size GetMaximumDialogSize() override; // CefBrowserPlatformDelegateNative methods: content::NativeWebKeyboardEvent TranslateWebKeyEvent( diff --git a/libcef/browser/native/browser_platform_delegate_native_mac.mm b/libcef/browser/native/browser_platform_delegate_native_mac.mm index d8ff19987..0cba9e994 100644 --- a/libcef/browser/native/browser_platform_delegate_native_mac.mm +++ b/libcef/browser/native/browser_platform_delegate_native_mac.mm @@ -374,22 +374,6 @@ CefBrowserPlatformDelegateNativeMac::CreateMenuRunner() { return base::WrapUnique(new CefMenuRunnerMac); } -gfx::Point CefBrowserPlatformDelegateNativeMac::GetDialogPosition( - const gfx::Size& size) { - // Dialogs are always re-positioned by the constrained window sheet controller - // so nothing interesting to return yet. - return gfx::Point(); -} - -gfx::Size CefBrowserPlatformDelegateNativeMac::GetMaximumDialogSize() { - if (!web_contents_) - return gfx::Size(); - - // The dialog should try to fit within the overlay for the web contents. - // Note that, for things like print preview, this is just a suggested maximum. - return web_contents_->GetContainerBounds().size(); -} - content::NativeWebKeyboardEvent CefBrowserPlatformDelegateNativeMac::TranslateWebKeyEvent( const CefKeyEvent& key_event) const { diff --git a/libcef/browser/native/browser_platform_delegate_native_win.cc b/libcef/browser/native/browser_platform_delegate_native_win.cc index a345a6afe..f9a164d24 100644 --- a/libcef/browser/native/browser_platform_delegate_native_win.cc +++ b/libcef/browser/native/browser_platform_delegate_native_win.cc @@ -10,7 +10,6 @@ #include "libcef/browser/alloy/alloy_browser_host_impl.h" #include "libcef/browser/context.h" -#include "libcef/browser/native/javascript_dialog_runner_win.h" #include "libcef/browser/native/window_delegate_view.h" #include "libcef/browser/thread_util.h" @@ -425,22 +424,6 @@ CefEventHandle CefBrowserPlatformDelegateNativeWin::GetEventHandle( const_cast(&event.os_event->native_event())); } -std::unique_ptr -CefBrowserPlatformDelegateNativeWin::CreateJavaScriptDialogRunner() { - return base::WrapUnique(new CefJavaScriptDialogRunnerWin); -} - -gfx::Point CefBrowserPlatformDelegateNativeWin::GetDialogPosition( - const gfx::Size& size) { - const gfx::Size& max_size = GetMaximumDialogSize(); - return gfx::Point((max_size.width() - size.width()) / 2, - (max_size.height() - size.height()) / 2); -} - -gfx::Size CefBrowserPlatformDelegateNativeWin::GetMaximumDialogSize() { - return GetWindowWidget()->GetWindowBoundsInScreen().size(); -} - ui::KeyEvent CefBrowserPlatformDelegateNativeWin::TranslateUiKeyEvent( const CefKeyEvent& key_event) const { int flags = TranslateUiEventModifiers(key_event.modifiers); diff --git a/libcef/browser/native/browser_platform_delegate_native_win.h b/libcef/browser/native/browser_platform_delegate_native_win.h index fd1ccc7dd..6d26b5a3d 100644 --- a/libcef/browser/native/browser_platform_delegate_native_win.h +++ b/libcef/browser/native/browser_platform_delegate_native_win.h @@ -33,10 +33,6 @@ class CefBrowserPlatformDelegateNativeWin const content::NativeWebKeyboardEvent& event) override; CefEventHandle GetEventHandle( const content::NativeWebKeyboardEvent& event) const override; - std::unique_ptr CreateJavaScriptDialogRunner() - override; - gfx::Point GetDialogPosition(const gfx::Size& size) override; - gfx::Size GetMaximumDialogSize() override; // CefBrowserPlatformDelegateNativeAura methods: ui::KeyEvent TranslateUiKeyEvent(const CefKeyEvent& key_event) const override; diff --git a/libcef/browser/native/javascript_dialog_runner_mac.h b/libcef/browser/native/javascript_dialog_runner_mac.h index 193f2d694..9f8c783b5 100644 --- a/libcef/browser/native/javascript_dialog_runner_mac.h +++ b/libcef/browser/native/javascript_dialog_runner_mac.h @@ -9,6 +9,7 @@ #include "libcef/browser/javascript_dialog_runner.h" +#include "base/callback.h" #include "base/mac/scoped_nsobject.h" #include "base/memory/weak_ptr.h" @@ -24,12 +25,13 @@ class CefJavaScriptDialogRunnerMac : public CefJavaScriptDialogRunner { ~CefJavaScriptDialogRunnerMac() override; // CefJavaScriptDialogRunner methods: - void Run(AlloyBrowserHostImpl* browser, + void Run(CefBrowserHostBase* browser, content::JavaScriptDialogType message_type, - const std::u16string& display_url, + const GURL& origin_url, const std::u16string& message_text, const std::u16string& default_prompt_text, DialogClosedCallback callback) override; + void Handle(bool accept, const std::u16string* prompt_override) override; void Cancel() override; // Callback from CefJavaScriptDialogHelper when the dialog is closed. diff --git a/libcef/browser/native/javascript_dialog_runner_mac.mm b/libcef/browser/native/javascript_dialog_runner_mac.mm index 4d6572d83..cead4fb2d 100644 --- a/libcef/browser/native/javascript_dialog_runner_mac.mm +++ b/libcef/browser/native/javascript_dialog_runner_mac.mm @@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "components/url_formatter/elide_url.h" // Helper object that receives the notification that the dialog/sheet is // going away. Is responsible for cleaning itself up. @@ -87,9 +88,9 @@ CefJavaScriptDialogRunnerMac::~CefJavaScriptDialogRunnerMac() { } void CefJavaScriptDialogRunnerMac::Run( - AlloyBrowserHostImpl* browser, + CefBrowserHostBase* browser, content::JavaScriptDialogType message_type, - const std::u16string& display_url, + const GURL& origin_url, const std::u16string& message_text, const std::u16string& default_prompt_text, DialogClosedCallback callback) { @@ -126,6 +127,9 @@ void CefJavaScriptDialogRunnerMac::Run( label = u"JavaScript Confirm"; break; } + + const std::u16string& display_url = + url_formatter::FormatUrlForSecurityDisplay(origin_url); if (!display_url.empty()) label += u" - " + display_url; @@ -156,6 +160,14 @@ void CefJavaScriptDialogRunnerMac::Run( [[alert window] makeFirstResponder:[alert accessoryView]]; } +void CefJavaScriptDialogRunnerMac::Handle( + bool accept, + const std::u16string* prompt_override) { + if (helper_.get()) { + DialogClosed(accept, prompt_override ? *prompt_override : std::u16string()); + } +} + void CefJavaScriptDialogRunnerMac::Cancel() { if (helper_.get()) { [helper_ cancel]; diff --git a/libcef/browser/native/javascript_dialog_runner_win.cc b/libcef/browser/native/javascript_dialog_runner_win.cc deleted file mode 100644 index 94af08562..000000000 --- a/libcef/browser/native/javascript_dialog_runner_win.cc +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright (c) 2012 The Chromium Embedded Framework Authors. -// Portions copyright (c) 2012 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 "libcef/browser/native/javascript_dialog_runner_win.h" - -#include "libcef/browser/alloy/alloy_browser_host_impl.h" -#include "libcef_dll/resource.h" - -#include "base/files/file_path.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" - -class CefJavaScriptDialogRunnerWin; - -HHOOK CefJavaScriptDialogRunnerWin::msg_hook_ = NULL; -int CefJavaScriptDialogRunnerWin::msg_hook_user_count_ = 0; - -INT_PTR CALLBACK CefJavaScriptDialogRunnerWin::DialogProc(HWND dialog, - UINT message, - WPARAM wparam, - LPARAM lparam) { - switch (message) { - case WM_INITDIALOG: { - SetWindowLongPtr(dialog, DWLP_USER, static_cast(lparam)); - CefJavaScriptDialogRunnerWin* owner = - reinterpret_cast(lparam); - owner->dialog_win_ = dialog; - SetDlgItemText(dialog, IDC_DIALOGTEXT, owner->message_text_.c_str()); - if (owner->message_type_ == content::JAVASCRIPT_DIALOG_TYPE_PROMPT) - SetDlgItemText(dialog, IDC_PROMPTEDIT, - owner->default_prompt_text_.c_str()); - break; - } - case WM_CLOSE: { - CefJavaScriptDialogRunnerWin* owner = - reinterpret_cast( - GetWindowLongPtr(dialog, DWLP_USER)); - if (owner) { - owner->CloseDialog(false, std::wstring()); - - // No need for the system to call DestroyWindow() because it will be - // called by the Cancel() method. - return 0; - } - break; - } - case WM_COMMAND: { - CefJavaScriptDialogRunnerWin* owner = - reinterpret_cast( - GetWindowLongPtr(dialog, DWLP_USER)); - std::wstring user_input; - bool finish = false; - bool result = false; - switch (LOWORD(wparam)) { - case IDOK: - finish = true; - result = true; - if (owner->message_type_ == content::JAVASCRIPT_DIALOG_TYPE_PROMPT) { - size_t length = - GetWindowTextLength(GetDlgItem(dialog, IDC_PROMPTEDIT)) + 1; - if (length > 1) { - user_input.reserve(length); - user_input.resize(length - 1); - GetDlgItemText(dialog, IDC_PROMPTEDIT, &user_input[0], length); - } - } - break; - case IDCANCEL: - finish = true; - result = false; - break; - } - if (finish) { - owner->CloseDialog(result, user_input); - } - break; - } - default: - break; - } - return 0; -} - -CefJavaScriptDialogRunnerWin::CefJavaScriptDialogRunnerWin() - : dialog_win_(NULL), parent_win_(NULL), hook_installed_(false) {} - -CefJavaScriptDialogRunnerWin::~CefJavaScriptDialogRunnerWin() { - Cancel(); -} - -void CefJavaScriptDialogRunnerWin::Run( - AlloyBrowserHostImpl* browser, - content::JavaScriptDialogType message_type, - const std::u16string& display_url, - const std::u16string& message_text, - const std::u16string& default_prompt_text, - DialogClosedCallback callback) { - DCHECK(!dialog_win_); - - message_type_ = message_type; - message_text_ = base::UTF16ToWide(message_text); - default_prompt_text_ = base::UTF16ToWide(default_prompt_text); - callback_ = std::move(callback); - - InstallMessageHook(); - hook_installed_ = true; - - int dialog_type; - if (message_type == content::JAVASCRIPT_DIALOG_TYPE_ALERT) - dialog_type = IDD_ALERT; - else if (message_type == content::JAVASCRIPT_DIALOG_TYPE_CONFIRM) - dialog_type = IDD_CONFIRM; - else // JAVASCRIPT_DIALOG_TYPE_PROMPT - dialog_type = IDD_PROMPT; - - base::FilePath file_path; - HMODULE hModule = NULL; - - // Try to load the dialog from the DLL. - if (base::PathService::Get(base::DIR_MODULE, &file_path)) { - file_path = file_path.Append(L"libcef.dll"); - hModule = ::GetModuleHandle(file_path.value().c_str()); - } - if (!hModule) - hModule = ::GetModuleHandle(NULL); - DCHECK(hModule); - - parent_win_ = GetAncestor(browser->GetWindowHandle(), GA_ROOT); - dialog_win_ = - CreateDialogParam(hModule, MAKEINTRESOURCE(dialog_type), parent_win_, - DialogProc, reinterpret_cast(this)); - DCHECK(dialog_win_); - - if (!display_url.empty()) { - // Add the display URL to the window title. - wchar_t text[64]; - GetWindowText(dialog_win_, text, sizeof(text) / sizeof(wchar_t)); - - std::wstring new_window_text = - std::wstring(text) + L" - " + base::UTF16ToWide(display_url); - SetWindowText(dialog_win_, new_window_text.c_str()); - } - - // Disable the parent window so the user can't interact with it. - if (IsWindowEnabled(parent_win_)) - EnableWindow(parent_win_, FALSE); - - ShowWindow(dialog_win_, SW_SHOWNORMAL); -} - -void CefJavaScriptDialogRunnerWin::Cancel() { - // Re-enable the parent before closing the popup to avoid focus/activation/ - // z-order issues. - if (parent_win_ && IsWindow(parent_win_) && !IsWindowEnabled(parent_win_)) { - EnableWindow(parent_win_, TRUE); - parent_win_ = NULL; - } - - if (dialog_win_ && IsWindow(dialog_win_)) { - SetWindowLongPtr(dialog_win_, DWLP_USER, NULL); - DestroyWindow(dialog_win_); - dialog_win_ = NULL; - } - - if (hook_installed_) { - UninstallMessageHook(); - hook_installed_ = false; - } -} - -void CefJavaScriptDialogRunnerWin::CloseDialog(bool success, - const std::wstring& user_input) { - // Run the callback first so that RenderProcessHostImpl::IsBlocked is - // cleared. Otherwise, RenderWidgetHostImpl::IsIgnoringInputEvents will - // return true and RenderWidgetHostViewAura::OnWindowFocused will fail to - // re-assign browser focus. - std::move(callback_).Run(success, base::WideToUTF16(user_input)); - Cancel(); -} - -// static -LRESULT CALLBACK CefJavaScriptDialogRunnerWin::GetMsgProc(int code, - WPARAM wparam, - LPARAM lparam) { - // Mostly borrowed from http://support.microsoft.com/kb/q187988/ - // and http://www.codeproject.com/KB/atl/cdialogmessagehook.aspx. - LPMSG msg = reinterpret_cast(lparam); - if (code >= 0 && wparam == PM_REMOVE && msg->message >= WM_KEYFIRST && - msg->message <= WM_KEYLAST) { - HWND hwnd = GetActiveWindow(); - if (::IsWindow(hwnd) && ::IsDialogMessage(hwnd, msg)) { - // The value returned from this hookproc is ignored, and it cannot - // be used to tell Windows the message has been handled. To avoid - // further processing, convert the message to WM_NULL before - // returning. - msg->hwnd = NULL; - msg->message = WM_NULL; - msg->lParam = 0L; - msg->wParam = 0; - } - } - - // Passes the hook information to the next hook procedure in - // the current hook chain. - return ::CallNextHookEx(msg_hook_, code, wparam, lparam); -} - -// static -bool CefJavaScriptDialogRunnerWin::InstallMessageHook() { - msg_hook_user_count_++; - - // Make sure we only call this once. - if (msg_hook_ != NULL) - return true; - - msg_hook_ = ::SetWindowsHookEx(WH_GETMESSAGE, - &CefJavaScriptDialogRunnerWin::GetMsgProc, - NULL, GetCurrentThreadId()); - DCHECK(msg_hook_ != NULL); - return msg_hook_ != NULL; -} - -// static -bool CefJavaScriptDialogRunnerWin::UninstallMessageHook() { - msg_hook_user_count_--; - DCHECK_GE(msg_hook_user_count_, 0); - - if (msg_hook_user_count_ > 0) - return true; - - DCHECK(msg_hook_ != NULL); - BOOL result = ::UnhookWindowsHookEx(msg_hook_); - DCHECK(result); - msg_hook_ = NULL; - - return result != FALSE; -} diff --git a/libcef/browser/native/javascript_dialog_runner_win.h b/libcef/browser/native/javascript_dialog_runner_win.h deleted file mode 100644 index ae2d86548..000000000 --- a/libcef/browser/native/javascript_dialog_runner_win.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2012 The Chromium Embedded Framework Authors. -// Portions copyright (c) 2012 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 CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_WIN_H_ -#define CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_WIN_H_ -#pragma once - -#include - -#include "libcef/browser/javascript_dialog_runner.h" - -class CefJavaScriptDialogRunnerWin : public CefJavaScriptDialogRunner { - public: - CefJavaScriptDialogRunnerWin(); - ~CefJavaScriptDialogRunnerWin() override; - - // CefJavaScriptDialogRunner methods: - void Run(AlloyBrowserHostImpl* browser, - content::JavaScriptDialogType message_type, - const std::u16string& display_url, - const std::u16string& message_text, - const std::u16string& default_prompt_text, - DialogClosedCallback callback) override; - void Cancel() override; - - private: - void CloseDialog(bool success, const std::wstring& user_input); - - HWND dialog_win_; - HWND parent_win_; - - content::JavaScriptDialogType message_type_; - std::wstring message_text_; - std::wstring default_prompt_text_; - DialogClosedCallback callback_; - - bool hook_installed_; - - static INT_PTR CALLBACK DialogProc(HWND dialog, - UINT message, - WPARAM wparam, - LPARAM lparam); - - // Since the message loop we expect to run in isn't going to be nicely - // calling IsDialogMessage(), we need to hook the wnd proc and call it - // ourselves. See http://support.microsoft.com/kb/q187988/ - static bool InstallMessageHook(); - static bool UninstallMessageHook(); - static LRESULT CALLBACK GetMsgProc(int code, WPARAM wparam, LPARAM lparam); - static HHOOK msg_hook_; - static int msg_hook_user_count_; -}; - -#endif // CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_WIN_H_ diff --git a/libcef/browser/osr/browser_platform_delegate_osr.cc b/libcef/browser/osr/browser_platform_delegate_osr.cc index 106969dcb..624b4becd 100644 --- a/libcef/browser/osr/browser_platform_delegate_osr.cc +++ b/libcef/browser/osr/browser_platform_delegate_osr.cc @@ -235,6 +235,13 @@ void CefBrowserPlatformDelegateOsr::WasHidden(bool hidden) { } } +bool CefBrowserPlatformDelegateOsr::IsHidden() const { + CefRenderWidgetHostViewOSR* view = GetOSRHostView(); + if (view) + return view->is_hidden(); + return true; +} + void CefBrowserPlatformDelegateOsr::NotifyScreenInfoChanged() { CefRenderWidgetHostViewOSR* view = GetOSRHostView(); if (view) diff --git a/libcef/browser/osr/browser_platform_delegate_osr.h b/libcef/browser/osr/browser_platform_delegate_osr.h index c28019c1b..dac931343 100644 --- a/libcef/browser/osr/browser_platform_delegate_osr.h +++ b/libcef/browser/osr/browser_platform_delegate_osr.h @@ -55,6 +55,7 @@ class CefBrowserPlatformDelegateOsr std::unique_ptr CreateMenuRunner() override; bool IsWindowless() const override; void WasHidden(bool hidden) override; + bool IsHidden() const override; void NotifyScreenInfoChanged() override; void Invalidate(cef_paint_element_type_t type) override; void SendExternalBeginFrame() override; diff --git a/libcef/browser/osr/render_widget_host_view_osr.h b/libcef/browser/osr/render_widget_host_view_osr.h index 945441cf9..21d67dc34 100644 --- a/libcef/browser/osr/render_widget_host_view_osr.h +++ b/libcef/browser/osr/render_widget_host_view_osr.h @@ -308,6 +308,8 @@ class CefRenderWidgetHostViewOSR ui::TextInputType GetTextInputType(); + bool is_hidden() const { return !is_showing_; } + private: void SetFrameRate(); bool SetScreenInfo(); diff --git a/libcef/browser/printing/constrained_window_views_client.cc b/libcef/browser/printing/constrained_window_views_client.cc deleted file mode 100644 index 78ee5c1af..000000000 --- a/libcef/browser/printing/constrained_window_views_client.cc +++ /dev/null @@ -1,46 +0,0 @@ -// 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 "libcef/browser/printing/constrained_window_views_client.h" - -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/notreached.h" -#include "chrome/browser/platform_util.h" -#include "chrome/browser/ui/browser_finder.h" -#include "components/web_modal/web_contents_modal_dialog_host.h" - -namespace { - -class CefConstrainedWindowViewsClient - : public constrained_window::ConstrainedWindowViewsClient { - public: - CefConstrainedWindowViewsClient() {} - - CefConstrainedWindowViewsClient(const CefConstrainedWindowViewsClient&) = - delete; - CefConstrainedWindowViewsClient& operator=( - const CefConstrainedWindowViewsClient&) = delete; - - ~CefConstrainedWindowViewsClient() override {} - - private: - // ConstrainedWindowViewsClient: - web_modal::ModalDialogHost* GetModalDialogHost( - gfx::NativeWindow parent) override { - NOTREACHED(); - return nullptr; - } - gfx::NativeView GetDialogHostView(gfx::NativeWindow parent) override { - NOTREACHED(); - return gfx::NativeView(); - } -}; - -} // namespace - -std::unique_ptr -CreateCefConstrainedWindowViewsClient() { - return base::WrapUnique(new CefConstrainedWindowViewsClient); -} \ No newline at end of file diff --git a/libcef/browser/printing/constrained_window_views_client.h b/libcef/browser/printing/constrained_window_views_client.h deleted file mode 100644 index 0f1878482..000000000 --- a/libcef/browser/printing/constrained_window_views_client.h +++ /dev/null @@ -1,16 +0,0 @@ -// 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 CEF_LIBCEF_BROWSER_PRINTING_CONSTRAINED_WINDOW_VIEWS_CLIENT_H_ -#define CEF_LIBCEF_BROWSER_PRINTING_CONSTRAINED_WINDOW_VIEWS_CLIENT_H_ - -#include - -#include "components/constrained_window/constrained_window_views_client.h" - -// Creates a ConstrainedWindowViewsClient for the Chrome environment. -std::unique_ptr -CreateCefConstrainedWindowViewsClient(); - -#endif // CEF_LIBCEF_BROWSER_PRINTING_CONSTRAINED_WINDOW_VIEWS_CLIENT_H_ \ No newline at end of file diff --git a/libcef/browser/views/browser_platform_delegate_views.cc b/libcef/browser/views/browser_platform_delegate_views.cc index 9f9a2accd..ffaef8818 100644 --- a/libcef/browser/views/browser_platform_delegate_views.cc +++ b/libcef/browser/views/browser_platform_delegate_views.cc @@ -258,11 +258,6 @@ CefEventHandle CefBrowserPlatformDelegateViews::GetEventHandle( return native_delegate_->GetEventHandle(event); } -std::unique_ptr -CefBrowserPlatformDelegateViews::CreateJavaScriptDialogRunner() { - return native_delegate_->CreateJavaScriptDialogRunner(); -} - std::unique_ptr CefBrowserPlatformDelegateViews::CreateMenuRunner() { return base::WrapUnique(new CefMenuRunnerViews(browser_view_.get())); diff --git a/libcef/browser/views/browser_platform_delegate_views.h b/libcef/browser/views/browser_platform_delegate_views.h index dd27f6903..fb2714b98 100644 --- a/libcef/browser/views/browser_platform_delegate_views.h +++ b/libcef/browser/views/browser_platform_delegate_views.h @@ -61,8 +61,6 @@ class CefBrowserPlatformDelegateViews const content::NativeWebKeyboardEvent& event) override; CefEventHandle GetEventHandle( const content::NativeWebKeyboardEvent& event) const override; - std::unique_ptr CreateJavaScriptDialogRunner() - override; std::unique_ptr CreateMenuRunner() override; bool IsViewsHosted() const override; gfx::Point GetDialogPosition(const gfx::Size& size) override; diff --git a/libcef/browser/web_contents_dialog_helper.cc b/libcef/browser/web_contents_dialog_helper.cc deleted file mode 100644 index 0d11842b4..000000000 --- a/libcef/browser/web_contents_dialog_helper.cc +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2019 The Chromium Embedded Framework 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 "libcef/browser/web_contents_dialog_helper.h" - -#include "libcef/browser/browser_platform_delegate.h" - -#include "chrome/browser/platform_util.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" -#include "ui/views/widget/widget.h" - -CefWebContentsDialogHelper::CefWebContentsDialogHelper( - content::WebContents* web_contents, - CefBrowserPlatformDelegate* browser_delegate) - : browser_delegate_(browser_delegate), weak_factory_(this) { - web_modal::WebContentsModalDialogManager::CreateForWebContents(web_contents); - web_modal::WebContentsModalDialogManager::FromWebContents(web_contents) - ->SetDelegate(this); -} - -base::RepeatingClosure CefWebContentsDialogHelper::GetBoundsChangedCallback() { - return base::BindRepeating(&CefWebContentsDialogHelper::OnBoundsChanged, - weak_factory_.GetWeakPtr()); -} - -bool CefWebContentsDialogHelper::IsWebContentsVisible( - content::WebContents* web_contents) { - return platform_util::IsVisible(web_contents->GetNativeView()); -} - -web_modal::WebContentsModalDialogHost* -CefWebContentsDialogHelper::GetWebContentsModalDialogHost() { - return this; -} - -gfx::NativeView CefWebContentsDialogHelper::GetHostView() const { - return browser_delegate_->GetWindowWidget()->GetNativeView(); -} - -gfx::Point CefWebContentsDialogHelper::GetDialogPosition( - const gfx::Size& size) { - return browser_delegate_->GetDialogPosition(size); -} - -gfx::Size CefWebContentsDialogHelper::GetMaximumDialogSize() { - return browser_delegate_->GetMaximumDialogSize(); -} - -void CefWebContentsDialogHelper::AddObserver( - web_modal::ModalDialogHostObserver* observer) { - if (observer && !observer_list_.HasObserver(observer)) - observer_list_.AddObserver(observer); -} - -void CefWebContentsDialogHelper::RemoveObserver( - web_modal::ModalDialogHostObserver* observer) { - observer_list_.RemoveObserver(observer); -} - -void CefWebContentsDialogHelper::OnBoundsChanged() { - for (auto& observer : observer_list_) - observer.OnPositionRequiresUpdate(); -} diff --git a/patch/patch.cfg b/patch/patch.cfg index 593b992f1..7df0d5875 100644 --- a/patch/patch.cfg +++ b/patch/patch.cfg @@ -91,6 +91,7 @@ patches = [ # https://bitbucket.org/chromiumembedded/cef/issues/1677 # https://bitbucket.org/chromiumembedded/cef/issues/1679 # https://bitbucket.org/chromiumembedded/cef/issues/1700 + # https://bitbucket.org/chromiumembedded/cef/issues/3316 # # Support creation of captionless windows with resizable borders. # https://bitbucket.org/chromiumembedded/cef/issues/1749 @@ -225,12 +226,21 @@ patches = [ 'name': 'chrome_browser_context_menus', }, { - # Support use of chrome dialogs with CEF runtimes. + # Support use of chrome native dialogs with CEF runtimes. # - Adds support for FileSelectHelper and SelectFileDialog interception. # - Adds additional type filters for dialogs created via FileSelectHelper. # - Adds support for chaining PrintingContextLinux callbacks. # https://bitbucket.org/chromiumembedded/cef/issues/3314 - 'name': 'chrome_browser_dialogs', + 'name': 'chrome_browser_dialogs_native', + }, + { + # Support use of chrome Widget dialogs with CEF runtimes. + # - Add gfx::AcceleratedWidget dialog parent argument to + # DialogDelegate::CreateDialogWidget for CEF windowless rendering. + # - Support nullptr gfx::NativeWindow/gfx::NativeView dialog parent for CEF + # windowless rendering. + # https://bitbucket.org/chromiumembedded/cef/issues/3316 + 'name': 'chrome_browser_dialogs_widget', }, { # chrome: Support override of ChromeMimeHandlerViewGuestDelegate. diff --git a/patch/patches/chrome_browser_dialogs.patch b/patch/patches/chrome_browser_dialogs_native.patch similarity index 100% rename from patch/patches/chrome_browser_dialogs.patch rename to patch/patches/chrome_browser_dialogs_native.patch diff --git a/patch/patches/chrome_browser_dialogs_widget.patch b/patch/patches/chrome_browser_dialogs_widget.patch new file mode 100644 index 000000000..ed78e7c3d --- /dev/null +++ b/patch/patches/chrome_browser_dialogs_widget.patch @@ -0,0 +1,225 @@ +diff --git chrome/browser/ui/views/chrome_javascript_app_modal_view_factory_views.cc chrome/browser/ui/views/chrome_javascript_app_modal_view_factory_views.cc +index a15902b583edc..2501a2d8ead5f 100644 +--- chrome/browser/ui/views/chrome_javascript_app_modal_view_factory_views.cc ++++ chrome/browser/ui/views/chrome_javascript_app_modal_view_factory_views.cc +@@ -97,7 +97,7 @@ javascript_dialogs::AppModalDialogView* CreateViewsJavaScriptDialog( + gfx::NativeWindow parent_window = + controller->web_contents()->GetTopLevelNativeWindow(); + #if defined(USE_AURA) +- if (!parent_window->GetRootWindow()) { ++ if (parent_window && !parent_window->GetRootWindow()) { + // When we are part of a WebContents that isn't actually being displayed + // on the screen, we can't actually attach to it. + parent_window = nullptr; +diff --git components/constrained_window/constrained_window_views.cc components/constrained_window/constrained_window_views.cc +index d662221bcc6f7..8b139e1935e29 100644 +--- components/constrained_window/constrained_window_views.cc ++++ components/constrained_window/constrained_window_views.cc +@@ -100,15 +100,24 @@ void UpdateModalDialogPosition(views::Widget* widget, + if (widget->HasCapture()) + return; + ++ // |host_view| will be nullptr with CEF windowless rendering. ++ auto host_view = dialog_host->GetHostView(); + views::Widget* host_widget = +- views::Widget::GetWidgetForNativeView(dialog_host->GetHostView()); ++ host_view ? views::Widget::GetWidgetForNativeView(host_view) : nullptr; + + // If the host view is not backed by a Views::Widget, just update the widget + // size. This can happen on MacViews under the Cocoa browser where the window + // modal dialogs are displayed as sheets, and their position is managed by a + // ConstrainedWindowSheetController instance. + if (!host_widget) { ++#if BUILDFLAG(IS_MAC) + widget->SetSize(size); ++#elif BUILDFLAG(IS_POSIX) ++ // Set the bounds here instead of relying on the default behavior of ++ // DesktopWindowTreeHostPlatform::CenterWindow which incorrectly centers ++ // the window on the screen. ++ widget->SetBounds(gfx::Rect(dialog_host->GetDialogPosition(size), size)); ++#endif + return; + } + +@@ -207,7 +216,8 @@ views::Widget* CreateWebModalDialogViews(views::WidgetDelegate* dialog, + + return views::DialogDelegate::CreateDialogWidget( + dialog, nullptr, +- manager->delegate()->GetWebContentsModalDialogHost()->GetHostView()); ++ manager->delegate()->GetWebContentsModalDialogHost()->GetHostView(), ++ manager->delegate()->GetWebContentsModalDialogHost()->GetHostWidget()); + } + + views::Widget* CreateBrowserModalDialogViews( +@@ -224,8 +234,13 @@ views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog, + + gfx::NativeView parent_view = + parent ? CurrentClient()->GetDialogHostView(parent) : nullptr; ++ // Use with CEF windowless rendering. ++ gfx::AcceleratedWidget parent_widget = ++ parent ? gfx::kNullAcceleratedWidget : ++ CurrentClient()->GetModalDialogHost(parent)->GetHostWidget(); + views::Widget* widget = +- views::DialogDelegate::CreateDialogWidget(dialog, nullptr, parent_view); ++ views::DialogDelegate::CreateDialogWidget(dialog, nullptr, parent_view, ++ parent_widget); + + bool requires_positioning = dialog->use_custom_frame(); + +@@ -238,8 +253,7 @@ views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog, + if (!requires_positioning) + return widget; + +- ModalDialogHost* host = +- parent ? CurrentClient()->GetModalDialogHost(parent) : nullptr; ++ ModalDialogHost* host = CurrentClient()->GetModalDialogHost(parent); + if (host) { + DCHECK_EQ(parent_view, host->GetHostView()); + ModalDialogHostObserver* dialog_host_observer = +diff --git components/constrained_window/native_web_contents_modal_dialog_manager_views.cc components/constrained_window/native_web_contents_modal_dialog_manager_views.cc +index ac015f82f720d..80d11897e5d6d 100644 +--- components/constrained_window/native_web_contents_modal_dialog_manager_views.cc ++++ components/constrained_window/native_web_contents_modal_dialog_manager_views.cc +@@ -184,9 +184,12 @@ void NativeWebContentsModalDialogManagerViews::HostChanged( + if (host_) { + host_->AddObserver(this); + +- for (auto* widget : observed_widgets_) { +- views::Widget::ReparentNativeView(widget->GetNativeView(), +- host_->GetHostView()); ++ // |host_view| will be nullptr with CEF windowless rendering. ++ if (auto host_view = host_->GetHostView()) { ++ for (auto* widget : observed_widgets_) { ++ views::Widget::ReparentNativeView(widget->GetNativeView(), ++ host_view); ++ } + } + + OnPositionRequiresUpdate(); +diff --git components/web_modal/modal_dialog_host.h components/web_modal/modal_dialog_host.h +index b220ddc72bab2..2a9a35b97f189 100644 +--- components/web_modal/modal_dialog_host.h ++++ components/web_modal/modal_dialog_host.h +@@ -34,6 +34,10 @@ class WEB_MODAL_EXPORT ModalDialogHost { + + // Returns the view against which the dialog is positioned and parented. + virtual gfx::NativeView GetHostView() const = 0; ++ // Returns the widget against which the dialog is positioned and parented. ++ // Used with CEF windowless rendering. ++ virtual gfx::AcceleratedWidget GetHostWidget() const { ++ return gfx::kNullAcceleratedWidget; } + // Gets the position for the dialog in coordinates relative to the host view. + virtual gfx::Point GetDialogPosition(const gfx::Size& size) = 0; + // Returns whether a dialog currently about to be shown should be activated. +diff --git ui/views/window/dialog_delegate.cc ui/views/window/dialog_delegate.cc +index fcf0b05964557..3cac0c96d7ca7 100644 +--- ui/views/window/dialog_delegate.cc ++++ ui/views/window/dialog_delegate.cc +@@ -60,10 +60,12 @@ DialogDelegate::DialogDelegate() { + // static + Widget* DialogDelegate::CreateDialogWidget(WidgetDelegate* delegate, + gfx::NativeWindow context, +- gfx::NativeView parent) { ++ gfx::NativeView parent, ++ gfx::AcceleratedWidget parent_widget) { + views::Widget* widget = new views::Widget; + views::Widget::InitParams params = +- GetDialogWidgetInitParams(delegate, context, parent, gfx::Rect()); ++ GetDialogWidgetInitParams(delegate, context, parent, gfx::Rect(), ++ parent_widget); + widget->Init(std::move(params)); + return widget; + } +@@ -72,22 +74,24 @@ Widget* DialogDelegate::CreateDialogWidget(WidgetDelegate* delegate, + Widget* DialogDelegate::CreateDialogWidget( + std::unique_ptr delegate, + gfx::NativeWindow context, +- gfx::NativeView parent) { ++ gfx::NativeView parent, ++ gfx::AcceleratedWidget parent_widget) { + DCHECK(delegate->owned_by_widget()); +- return CreateDialogWidget(delegate.release(), context, parent); ++ return CreateDialogWidget(delegate.release(), context, parent, parent_widget); + } + + // static +-bool DialogDelegate::CanSupportCustomFrame(gfx::NativeView parent) { ++bool DialogDelegate::CanSupportCustomFrame(gfx::NativeView parent, ++ gfx::AcceleratedWidget parent_widget) { + #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && \ + BUILDFLAG(ENABLE_DESKTOP_AURA) + // The new style doesn't support unparented dialogs on Linux desktop. +- return parent != nullptr; ++ return parent != nullptr || parent_widget != gfx::kNullAcceleratedWidget; + #else + #if BUILDFLAG(IS_WIN) + // The new style doesn't support unparented dialogs on Windows Classic themes. + if (!ui::win::IsAeroGlassEnabled()) +- return parent != nullptr; ++ return parent != nullptr || parent_widget != gfx::kNullAcceleratedWidget; + #endif + return true; + #endif +@@ -98,14 +102,15 @@ Widget::InitParams DialogDelegate::GetDialogWidgetInitParams( + WidgetDelegate* delegate, + gfx::NativeWindow context, + gfx::NativeView parent, +- const gfx::Rect& bounds) { ++ const gfx::Rect& bounds, ++ gfx::AcceleratedWidget parent_widget) { + views::Widget::InitParams params; + params.delegate = delegate; + params.bounds = bounds; + DialogDelegate* dialog = delegate->AsDialogDelegate(); + + if (dialog) +- dialog->params_.custom_frame &= CanSupportCustomFrame(parent); ++ dialog->params_.custom_frame &= CanSupportCustomFrame(parent, parent_widget); + + if (!dialog || dialog->use_custom_frame()) { + params.opacity = Widget::InitParams::WindowOpacity::kTranslucent; +@@ -118,6 +123,7 @@ Widget::InitParams DialogDelegate::GetDialogWidgetInitParams( + } + params.context = context; + params.parent = parent; ++ params.parent_widget = parent_widget; + #if !BUILDFLAG(IS_APPLE) + // Web-modal (ui::MODAL_TYPE_CHILD) dialogs with parents are marked as child + // widgets to prevent top-level window behavior (independent movement, etc). +diff --git ui/views/window/dialog_delegate.h ui/views/window/dialog_delegate.h +index 2575e99e67586..29fc582388bbd 100644 +--- ui/views/window/dialog_delegate.h ++++ ui/views/window/dialog_delegate.h +@@ -94,13 +94,18 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate { + // your use case. + static Widget* CreateDialogWidget(std::unique_ptr delegate, + gfx::NativeWindow context, +- gfx::NativeView parent); ++ gfx::NativeView parent, ++ gfx::AcceleratedWidget parent_widget = ++ gfx::kNullAcceleratedWidget); + static Widget* CreateDialogWidget(WidgetDelegate* delegate, + gfx::NativeWindow context, +- gfx::NativeView parent); ++ gfx::NativeView parent, ++ gfx::AcceleratedWidget parent_widget = ++ gfx::kNullAcceleratedWidget); + + // Whether using custom dialog frame is supported for this dialog. +- static bool CanSupportCustomFrame(gfx::NativeView parent); ++ static bool CanSupportCustomFrame(gfx::NativeView parent, ++ gfx::AcceleratedWidget parent_widget); + + // Returns the dialog widget InitParams for a given |context| or |parent|. + // If |bounds| is not empty, used to initially place the dialog, otherwise +@@ -108,7 +113,9 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate { + static Widget::InitParams GetDialogWidgetInitParams(WidgetDelegate* delegate, + gfx::NativeWindow context, + gfx::NativeView parent, +- const gfx::Rect& bounds); ++ const gfx::Rect& bounds, ++ gfx::AcceleratedWidget parent_widget = ++ gfx::kNullAcceleratedWidget); + + // Returns a mask specifying which of the available DialogButtons are visible + // for the dialog. diff --git a/patch/patches/views_widget.patch b/patch/patches/views_widget.patch index 93bdffab7..55711ab55 100644 --- a/patch/patches/views_widget.patch +++ b/patch/patches/views_widget.patch @@ -404,10 +404,23 @@ index b3a3efd0e526f..8590a98eaf0b2 100644 if (native_widget_delegate->IsDialogBox()) { *style |= DS_MODALFRAME; diff --git ui/views/win/hwnd_message_handler.cc ui/views/win/hwnd_message_handler.cc -index 0a34478e9cb44..bf9059edbd634 100644 +index 0a34478e9cb44..e61fca5b6e525 100644 --- ui/views/win/hwnd_message_handler.cc +++ ui/views/win/hwnd_message_handler.cc -@@ -3176,10 +3176,13 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message, +@@ -796,7 +796,11 @@ bool HWNDMessageHandler::IsVisible() const { + } + + bool HWNDMessageHandler::IsActive() const { +- return GetActiveWindow() == hwnd(); ++ // This active state is checked via FocusManager::SetFocusedViewWithReason. ++ // With CEF external parent hwnd() may be a child window, whereas ++ // GetActiveWindow() will return the root window, so make sure that we always ++ // compare root windows. ++ return GetActiveWindow() == GetAncestor(hwnd(), GA_ROOT); + } + + bool HWNDMessageHandler::IsMinimized() const { +@@ -3176,10 +3180,13 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message, } else if (event.type() == ui::ET_MOUSEWHEEL) { ui::MouseWheelEvent mouse_wheel_event(msg); // Reroute the mouse wheel to the window under the pointer if applicable. diff --git a/tests/cefclient/browser/client_handler.cc b/tests/cefclient/browser/client_handler.cc index b5915c2c0..a6d89bd3f 100644 --- a/tests/cefclient/browser/client_handler.cc +++ b/tests/cefclient/browser/client_handler.cc @@ -271,30 +271,44 @@ ClientHandler::ClientHandler(Delegate* delegate, offline_ = command_line->HasSwitch(switches::kOffline); #if defined(OS_LINUX) - // Optionally use the client-provided dialog implementation. - bool use_client_dialogs = + // Optionally use the client-provided GTK dialogs. + const bool use_client_dialogs = command_line->HasSwitch(switches::kUseClientDialogs); - if (!use_client_dialogs && - command_line->HasSwitch(switches::kMultiThreadedMessageLoop)) { - // Default dialogs are not supported in combination with - // multi-threaded-message-loop because Chromium doesn't support GDK threads - // internally. - LOG(WARNING) << "Client dialogs must be used in combination with " - "multi-threaded-message-loop."; - use_client_dialogs = true; + // Determine if the client-provided GTK dialogs can/should be used. + bool require_client_dialogs = false; + bool support_client_dialogs = true; + + if (command_line->HasSwitch(switches::kMultiThreadedMessageLoop)) { + // Default/internal GTK dialogs are not supported in combination with + // multi-threaded-message-loop because Chromium doesn't support GDK threads. + // This does not apply to the JS dialogs which use Views instead of GTK. + if (!use_client_dialogs) { + LOG(WARNING) << "Client dialogs must be used in combination with " + "multi-threaded-message-loop."; + } + require_client_dialogs = true; } - if (use_client_dialogs && MainContext::Get()->UseViews()) { - // Client dialogs cannot be used in combination with Views because the - // implementation of ClientDialogHandlerGtk requires a top-level GtkWindow. - LOG(ERROR) << "Client dialogs cannot be used in combination with Views."; - use_client_dialogs = false; + if (MainContext::Get()->UseViews()) { + // Client-provided GTK dialogs cannot be used in combination with Views + // because the implementation of ClientDialogHandlerGtk requires a top-level + // GtkWindow. + if (use_client_dialogs) { + LOG(ERROR) << "Client dialogs cannot be used in combination with Views."; + } + support_client_dialogs = false; } - if (use_client_dialogs) { - dialog_handler_ = new ClientDialogHandlerGtk(); - print_handler_ = new ClientPrintHandlerGtk(); + if (support_client_dialogs) { + if (use_client_dialogs) { + js_dialog_handler_ = new ClientDialogHandlerGtk(); + } + if (use_client_dialogs || require_client_dialogs) { + file_dialog_handler_ = js_dialog_handler_ ? js_dialog_handler_ + : new ClientDialogHandlerGtk(); + print_handler_ = new ClientPrintHandlerGtk(); + } } #endif // defined(OS_LINUX) } diff --git a/tests/cefclient/browser/client_handler.h b/tests/cefclient/browser/client_handler.h index e58b01786..f422b1314 100644 --- a/tests/cefclient/browser/client_handler.h +++ b/tests/cefclient/browser/client_handler.h @@ -121,10 +121,10 @@ class ClientHandler : public CefClient, #if defined(OS_LINUX) CefRefPtr GetDialogHandler() override { - return dialog_handler_; + return file_dialog_handler_; } CefRefPtr GetJSDialogHandler() override { - return dialog_handler_; + return js_dialog_handler_; } CefRefPtr GetPrintHandler() override { return print_handler_; @@ -389,8 +389,9 @@ class ClientHandler : public CefClient, bool download_favicon_images_; #if defined(OS_LINUX) - // Custom dialog handler for GTK. - CefRefPtr dialog_handler_; + // Custom dialog handlers for GTK. + CefRefPtr file_dialog_handler_; + CefRefPtr js_dialog_handler_; CefRefPtr print_handler_; #endif diff --git a/tests/cefclient/browser/root_window_views.cc b/tests/cefclient/browser/root_window_views.cc index 73a5b1947..563633fda 100644 --- a/tests/cefclient/browser/root_window_views.cc +++ b/tests/cefclient/browser/root_window_views.cc @@ -529,6 +529,10 @@ void RootWindowViews::NotifyViewsWindowActivated() { void RootWindowViews::NotifyDestroyedIfDone() { // Notify once both the window and the browser have been destroyed. if (window_destroyed_ && browser_destroyed_) { + // The delegate may be holding the last reference to |this|, so take a + // reference here to keep |this| alive until after the method completes. + scoped_refptr self = this; + delegate_->OnRootWindowDestroyed(this); if (!config_->close_callback.is_null()) std::move(config_->close_callback).Run();