alloy: Use Chrome JS dialogs on Windows/Linux (fixes issue #3316)

This commit is contained in:
Marshall Greenblatt
2022-06-02 12:49:50 +03:00
parent b5eba89598
commit 35654cd709
53 changed files with 945 additions and 667 deletions

View File

@ -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",
]

View File

@ -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);

View File

@ -118,7 +118,7 @@ class CefJSDialogHandler : public virtual CefBaseRefCounted {
virtual void OnResetDialogState(CefRefPtr<CefBrowser> browser) {}
///
// Called when the default implementation dialog is closed.
// Called when the dialog is closed.
///
/*--cef()--*/
virtual void OnDialogClosed(CefRefPtr<CefBrowser> browser) {}

View File

@ -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();
}

View File

@ -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;

View File

@ -8,6 +8,7 @@
#include <string>
#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() {

View File

@ -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()) {
javascript_dialogs::TabModalDialogManager::CreateForWebContents(
web_contents_,
CreateAlloyJavaScriptTabModalDialogManagerDelegateDesktop(web_contents_));
// Used for print preview and JavaScript dialogs.
web_contents_dialog_helper_.reset(
new CefWebContentsDialogHelper(web_contents_, this));
}
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;

View File

@ -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<content::WebContents> owned_web_contents_;
// Used for the print preview dialog.
std::unique_ptr<CefWebContentsDialogHelper> web_contents_dialog_helper_;
std::unique_ptr<AlloyWebContentsDialogHelper> web_contents_dialog_helper_;
// The last find result. This object contains details about the number of
// matches, the find selection rectangle, etc.

View File

@ -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<CefBrowserHostBase> GetPreferredBrowser(
gfx::NativeWindow parent) {
CefRefPtr<CefBrowserHostBase> 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<constrained_window::ConstrainedWindowViewsClient>
CreateAlloyConstrainedWindowViewsClient() {
return std::make_unique<AlloyConstrainedWindowViewsClient>();
}

View File

@ -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 <memory>
#include "components/constrained_window/constrained_window_views_client.h"
// Creates a ConstrainedWindowViewsClient for the Chrome environment.
std::unique_ptr<constrained_window::ConstrainedWindowViewsClient>
CreateAlloyConstrainedWindowViewsClient();
#endif // CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_CONSTRAINED_WINDOW_VIEWS_CLIENT_H_

View File

@ -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 <webview>s.
raw_ptr<content::WebContents> web_contents_;
};
} // namespace
std::unique_ptr<JavaScriptTabModalDialogManagerDelegateDesktop>
CreateAlloyJavaScriptTabModalDialogManagerDelegateDesktop(
content::WebContents* web_contents) {
return std::make_unique<AlloyJavaScriptTabModalDialogManagerDelegateDesktop>(
web_contents);
}

View File

@ -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 <memory>
#include "chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_desktop.h"
// Creates a JavaScriptTabModalDialogManagerDelegateDesktop for the Chrome
// environment.
std::unique_ptr<JavaScriptTabModalDialogManagerDelegateDesktop>
CreateAlloyJavaScriptTabModalDialogManagerDelegateDesktop(
content::WebContents* web_contents);
#endif // CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_JAVASCRIPT_DIALOG_MANAGER_DELEGATE_H_

View File

@ -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();
}

View File

@ -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,11 +15,11 @@
class CefBrowserPlatformDelegate;
class CefWebContentsDialogHelper
class AlloyWebContentsDialogHelper
: public web_modal::WebContentsModalDialogManagerDelegate,
public web_modal::WebContentsModalDialogHost {
public:
CefWebContentsDialogHelper(content::WebContents* web_contents,
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<web_modal::ModalDialogHostObserver>::Unchecked
observer_list_;
base::WeakPtrFactory<CefWebContentsDialogHelper> weak_factory_;
base::WeakPtrFactory<AlloyWebContentsDialogHelper> weak_factory_;
};
#endif // CEF_LIBCEF_BROWSER_WEB_CONTENTS_DIALOG_HELPER_H_
#endif // CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_WEB_CONTENTS_DIALOG_HELPER_H_

View File

@ -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> CefBrowserHostBase::GetBrowserForGlobalId(
}
}
// static
CefRefPtr<CefBrowserHostBase>
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> 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<CefClient> 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())

View File

@ -128,6 +128,14 @@ class CefBrowserHostBase : public CefBrowserHost,
// Returns the browser associated with the specified global ID.
static CefRefPtr<CefBrowserHostBase> GetBrowserForGlobalId(
const content::GlobalRenderFrameHostId& global_id);
// Returns the browser associated with the specified top-level window.
static CefRefPtr<CefBrowserHostBase> 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<CefBrowserHostBase> 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(

View File

@ -131,6 +131,12 @@ CefRefPtr<CefBrowserView> CefBrowserPlatformDelegate::GetBrowserView() const {
return nullptr;
}
web_modal::WebContentsModalDialogHost*
CefBrowserPlatformDelegate::GetWebContentsModalDialogHost() const {
NOTREACHED();
return nullptr;
}
void CefBrowserPlatformDelegate::PopupWebContentsCreated(
const CefBrowserSettings& settings,
CefRefPtr<CefClient> client,
@ -226,7 +232,6 @@ CefEventHandle CefBrowserPlatformDelegate::GetEventHandle(
std::unique_ptr<CefJavaScriptDialogRunner>
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();
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,

View File

@ -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<CefBrowserView> 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();

View File

@ -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();
}

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -103,11 +103,6 @@ CefEventHandle CefBrowserPlatformDelegateBackground::GetEventHandle(
return native_delegate_->GetEventHandle(event);
}
std::unique_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateBackground::CreateJavaScriptDialogRunner() {
return native_delegate_->CreateJavaScriptDialogRunner();
}
std::unique_ptr<CefMenuRunner>
CefBrowserPlatformDelegateBackground::CreateMenuRunner() {
// No default menu implementation for background browsers.

View File

@ -41,8 +41,6 @@ class CefBrowserPlatformDelegateBackground
const content::NativeWebKeyboardEvent& event) override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
override;
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
// CefBrowserPlatformDelegateNative::WindowlessHandler methods:

View File

@ -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<CefBrowserHostBase> 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<CefBrowserHostBase> 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";
}

View File

@ -7,13 +7,13 @@
#include <utility>
#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<CefJavaScriptDialogRunner> 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<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefJSDialogHandler> 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<CefJSDialogCallbackImpl> 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)
return;
}
}
*did_suppress_message = false;
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 (callback.is_null()) {
LOG(WARNING)
<< "OnJSDialog should return true when executing the callback";
return;
}
dialog_running_ = true;
if (*did_suppress_message) {
// Call OnResetDialogState but don't execute |callback|.
CancelDialogs(web_contents, /*reset_state=*/true);
return;
}
const std::u16string& display_url =
url_formatter::FormatUrlForSecurityDisplay(origin_url);
handler_ = nullptr;
}
}
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)));
DCHECK(!handler_);
if (InitializeRunner()) {
runner_->Run(browser_, message_type, origin_url, message_text,
default_prompt_text, std::move(callback));
return;
}
if (!CanUseChromeDialogs()) {
// Dismiss the dialog.
std::move(callback).Run(false, std::u16string());
return;
}
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<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefJSDialogHandler> 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<CefJSDialogCallbackImpl> 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<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefJSDialogHandler> 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<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefJSDialogHandler> 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;
// 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;
}

View File

@ -7,20 +7,21 @@
#define CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_MANAGER_H_
#pragma once
#include <memory>
#include <string>
#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<CefJavaScriptDialogRunner> 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<CefJSDialogHandler> handler_;
std::unique_ptr<CefJavaScriptDialogRunner> runner_;
// True if a dialog is currently running.
bool dialog_running_;
bool runner_initialized_ = false;
// Must be the last member.
base::WeakPtrFactory<CefJavaScriptDialogManager> weak_ptr_factory_;

View File

@ -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<void(bool /* success */,
const std::u16string& /* user_input */)>;
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;

View File

@ -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);

View File

@ -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;

View File

@ -44,8 +44,6 @@ class CefBrowserPlatformDelegateNativeMac
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
override;
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
gfx::Point GetDialogPosition(const gfx::Size& size) override;
gfx::Size GetMaximumDialogSize() override;
// CefBrowserPlatformDelegateNative methods:
content::NativeWebKeyboardEvent TranslateWebKeyEvent(

View File

@ -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 {

View File

@ -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<CHROME_MSG*>(&event.os_event->native_event()));
}
std::unique_ptr<CefJavaScriptDialogRunner>
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);

View File

@ -33,10 +33,6 @@ class CefBrowserPlatformDelegateNativeWin
const content::NativeWebKeyboardEvent& event) override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
std::unique_ptr<CefJavaScriptDialogRunner> 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;

View File

@ -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.

View File

@ -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];

View File

@ -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<LONG_PTR>(lparam));
CefJavaScriptDialogRunnerWin* owner =
reinterpret_cast<CefJavaScriptDialogRunnerWin*>(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<CefJavaScriptDialogRunnerWin*>(
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<CefJavaScriptDialogRunnerWin*>(
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<LPARAM>(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<LPMSG>(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;
}

View File

@ -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 <windows.h>
#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_

View File

@ -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)

View File

@ -55,6 +55,7 @@ class CefBrowserPlatformDelegateOsr
std::unique_ptr<CefMenuRunner> 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;

View File

@ -308,6 +308,8 @@ class CefRenderWidgetHostViewOSR
ui::TextInputType GetTextInputType();
bool is_hidden() const { return !is_showing_; }
private:
void SetFrameRate();
bool SetScreenInfo();

View File

@ -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<constrained_window::ConstrainedWindowViewsClient>
CreateCefConstrainedWindowViewsClient() {
return base::WrapUnique(new CefConstrainedWindowViewsClient);
}

View File

@ -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 <memory>
#include "components/constrained_window/constrained_window_views_client.h"
// Creates a ConstrainedWindowViewsClient for the Chrome environment.
std::unique_ptr<constrained_window::ConstrainedWindowViewsClient>
CreateCefConstrainedWindowViewsClient();
#endif // CEF_LIBCEF_BROWSER_PRINTING_CONSTRAINED_WINDOW_VIEWS_CLIENT_H_

View File

@ -258,11 +258,6 @@ CefEventHandle CefBrowserPlatformDelegateViews::GetEventHandle(
return native_delegate_->GetEventHandle(event);
}
std::unique_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateViews::CreateJavaScriptDialogRunner() {
return native_delegate_->CreateJavaScriptDialogRunner();
}
std::unique_ptr<CefMenuRunner>
CefBrowserPlatformDelegateViews::CreateMenuRunner() {
return base::WrapUnique(new CefMenuRunnerViews(browser_view_.get()));

View File

@ -61,8 +61,6 @@ class CefBrowserPlatformDelegateViews
const content::NativeWebKeyboardEvent& event) override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
override;
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
bool IsViewsHosted() const override;
gfx::Point GetDialogPosition(const gfx::Size& size) override;

View File

@ -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();
}

View File

@ -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.

View File

@ -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<WidgetDelegate> 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<WidgetDelegate> 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.

View File

@ -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.

View File

@ -271,31 +271,45 @@ 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.
// 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.";
use_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;
}
require_client_dialogs = true;
}
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) {
dialog_handler_ = new ClientDialogHandlerGtk();
LOG(ERROR) << "Client dialogs cannot be used in combination with Views.";
}
support_client_dialogs = false;
}
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)
}

View File

@ -121,10 +121,10 @@ class ClientHandler : public CefClient,
#if defined(OS_LINUX)
CefRefPtr<CefDialogHandler> GetDialogHandler() override {
return dialog_handler_;
return file_dialog_handler_;
}
CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() override {
return dialog_handler_;
return js_dialog_handler_;
}
CefRefPtr<CefPrintHandler> 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<ClientDialogHandlerGtk> dialog_handler_;
// Custom dialog handlers for GTK.
CefRefPtr<ClientDialogHandlerGtk> file_dialog_handler_;
CefRefPtr<ClientDialogHandlerGtk> js_dialog_handler_;
CefRefPtr<ClientPrintHandlerGtk> print_handler_;
#endif

View File

@ -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<RootWindow> self = this;
delegate_->OnRootWindowDestroyed(this);
if (!config_->close_callback.is_null())
std::move(config_->close_callback).Run();