mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
chrome: win/linux: Add support for browser with native parent (see issue #3294)
This change adds Chrome runtime support on Windows and Linux for creating a browser parented to a native window supplied by the client application. Expected API usage and window behavior is similar to what already exists with the Alloy runtime. The parent window handle should be specified by using CefWindowInfo::SetAsChild in combination with the CefBrowserHost::CreateBrowser and CefLifeSpanHandler::OnBeforePopup callbacks. The previously existing behavior of creating a fully-featured Chrome browser window when empty CefWindowInfo is used with CreateBrowser remains unchanged and Views is still the preferred API for creating top-level Chrome windows with custom styling (e.g. title bar only, frameless, etc). The cefclient Popup Window test with a native parent window continues to crash on Linux with both the Alloy and Chrome runtimes (see issue #3165). Also adds Chrome runtime support for CefDisplayHandler::OnCursorChange. To test: - Run `cefclient --enable-chrome-runtime [--use-views]` for the default (and previously existing) Views-based behavior. - Run `cefclient --enable-chrome-runtime --use-native` for the new native parent window behavior. - Run `cefclient --enable-chrome-runtime --use-native --no-activate` and the window will not be activated (take input focus) on launch (Windows only). - Run `cefclient --enable-chrome-runtime [--use-views|--use-native] --mouse-cursor-change-disabled` and the mouse cursor will not change on mouseover of DOM elements.
This commit is contained in:
@@ -45,6 +45,10 @@ class CefBrowserPlatformDelegateChrome
|
||||
|
||||
void set_chrome_browser(Browser* browser);
|
||||
|
||||
CefBrowserPlatformDelegateNative* native_delegate() const {
|
||||
return native_delegate_.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate_;
|
||||
|
||||
|
@@ -341,6 +341,7 @@ std::unique_ptr<BrowserDelegate> BrowserDelegate::Create(
|
||||
create_params = params->create_params_;
|
||||
|
||||
// Clear these values so they're not persisted to additional Browsers.
|
||||
params->create_params_.window_info.reset();
|
||||
#if defined(TOOLKIT_VIEWS)
|
||||
params->create_params_.browser_view = nullptr;
|
||||
#endif
|
||||
|
@@ -143,6 +143,9 @@ void ChromeBrowserHostImpl::OnSetFocus(cef_focus_source_t source) {
|
||||
if (contents_delegate_->OnSetFocus(source))
|
||||
return;
|
||||
|
||||
if (platform_delegate_)
|
||||
platform_delegate_->SetFocus(true);
|
||||
|
||||
if (browser_) {
|
||||
const int tab_index = GetCurrentTabIndex();
|
||||
if (tab_index != TabStripModel::kNoTab) {
|
||||
@@ -163,13 +166,13 @@ bool ChromeBrowserHostImpl::TryCloseBrowser() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChromeBrowserHostImpl::SetFocus(bool focus) {
|
||||
if (focus) {
|
||||
OnSetFocus(FOCUS_SOURCE_SYSTEM);
|
||||
}
|
||||
}
|
||||
|
||||
CefWindowHandle ChromeBrowserHostImpl::GetWindowHandle() {
|
||||
if (CEF_CURRENTLY_ON_UIT()) {
|
||||
// Always return the most up-to-date window handle for a views-hosted
|
||||
// browser since it may change if the view is re-parented.
|
||||
if (platform_delegate_)
|
||||
return platform_delegate_->GetHostWindowHandle();
|
||||
}
|
||||
NOTIMPLEMENTED();
|
||||
return kNullWindowHandle;
|
||||
}
|
||||
@@ -282,10 +285,6 @@ void ChromeBrowserHostImpl::SendCaptureLostEvent() {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void ChromeBrowserHostImpl::NotifyMoveOrResizeStarted() {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
int ChromeBrowserHostImpl::GetWindowlessFrameRate() {
|
||||
return 0;
|
||||
}
|
||||
@@ -513,7 +512,20 @@ void ChromeBrowserHostImpl::Attach(content::WebContents* web_contents,
|
||||
// Notify that the browser has been created. These must be delivered in the
|
||||
// expected order.
|
||||
|
||||
// 1. Notify the browser's LifeSpanHandler. This must always be the first
|
||||
if (opener && opener->platform_delegate_) {
|
||||
// 1. Notify the opener browser's platform delegate. With Views this will
|
||||
// result in a call to CefBrowserViewDelegate::OnPopupBrowserViewCreated().
|
||||
// We want to call this method first because the implementation will often
|
||||
// create the Widget for the new popup browser. Without that Widget
|
||||
// CefBrowserHost::GetWindowHandle() will return kNullWindowHandle in
|
||||
// OnAfterCreated(), which breaks client expectations (e.g. clients expect
|
||||
// everything about the browser to be valid at that time).
|
||||
opener->platform_delegate_->PopupBrowserCreated(
|
||||
this,
|
||||
/*is_devtools_popup=*/false);
|
||||
}
|
||||
|
||||
// 2. Notify the browser's LifeSpanHandler. This must always be the first
|
||||
// notification for the browser.
|
||||
{
|
||||
// The WebContents won't be added to the Browser's TabStripModel until later
|
||||
@@ -522,17 +534,9 @@ void ChromeBrowserHostImpl::Attach(content::WebContents* web_contents,
|
||||
OnAfterCreated();
|
||||
}
|
||||
|
||||
// 2. Notify the platform delegate. With Views this will result in a call to
|
||||
// 3. Notify the platform delegate. With Views this will result in a call to
|
||||
// CefBrowserViewDelegate::OnBrowserCreated().
|
||||
platform_delegate_->NotifyBrowserCreated();
|
||||
|
||||
if (opener && opener->platform_delegate_) {
|
||||
// 3. Notify the opener browser's platform delegate. With Views this will
|
||||
// result in a call to CefBrowserViewDelegate::OnPopupBrowserViewCreated().
|
||||
opener->platform_delegate_->PopupBrowserCreated(
|
||||
this,
|
||||
/*is_devtools_popup=*/false);
|
||||
}
|
||||
}
|
||||
|
||||
void ChromeBrowserHostImpl::SetBrowser(Browser* browser) {
|
||||
|
@@ -62,7 +62,6 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
|
||||
// CefBrowserHost methods:
|
||||
void CloseBrowser(bool force_close) override;
|
||||
bool TryCloseBrowser() override;
|
||||
void SetFocus(bool focus) override;
|
||||
CefWindowHandle GetWindowHandle() override;
|
||||
CefWindowHandle GetOpenerWindowHandle() override;
|
||||
double GetZoomLevel() override;
|
||||
@@ -96,7 +95,6 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
|
||||
void SendExternalBeginFrame() override;
|
||||
void SendTouchEvent(const CefTouchEvent& event) override;
|
||||
void SendCaptureLostEvent() override;
|
||||
void NotifyMoveOrResizeStarted() override;
|
||||
int GetWindowlessFrameRate() override;
|
||||
void SetWindowlessFrameRate(int frame_rate) override;
|
||||
void ImeSetComposition(const CefString& text,
|
||||
|
@@ -0,0 +1,38 @@
|
||||
// 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.
|
||||
|
||||
#include "libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.h"
|
||||
|
||||
#include "include/views/cef_browser_view.h"
|
||||
#include "libcef/browser/chrome/views/chrome_child_window.h"
|
||||
|
||||
CefBrowserPlatformDelegateChromeChildWindow::
|
||||
CefBrowserPlatformDelegateChromeChildWindow(
|
||||
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
|
||||
CefRefPtr<CefBrowserViewImpl> browser_view)
|
||||
: CefBrowserPlatformDelegateChromeViews(std::move(native_delegate),
|
||||
browser_view) {}
|
||||
|
||||
void CefBrowserPlatformDelegateChromeChildWindow::RenderViewCreated(
|
||||
content::RenderViewHost* render_view_host) {
|
||||
CefBrowserPlatformDelegateChromeViews::RenderViewCreated(render_view_host);
|
||||
|
||||
// Calls SetHasExternalParent(true). This setting is required for proper
|
||||
// focus handling on Windows and Linux.
|
||||
native_delegate_->RenderViewCreated(render_view_host);
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegateChromeChildWindow::CloseHostWindow() {
|
||||
native_delegate_->CloseHostWindow();
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegateChromeChildWindow::SetFocus(bool focus) {
|
||||
native_delegate_->SetFocus(focus);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
|
||||
void CefBrowserPlatformDelegateChromeChildWindow::NotifyMoveOrResizeStarted() {
|
||||
native_delegate_->NotifyMoveOrResizeStarted();
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,28 @@
|
||||
// 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_CHROME_VIEWS_BROWSER_PLATFORM_DELEGATE_CHROME_CHILD_WINDOW_H_
|
||||
#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_BROWSER_PLATFORM_DELEGATE_CHROME_CHILD_WINDOW_H_
|
||||
|
||||
#include "libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h"
|
||||
|
||||
// Implementation of Chrome-based browser functionality.
|
||||
class CefBrowserPlatformDelegateChromeChildWindow
|
||||
: public CefBrowserPlatformDelegateChromeViews {
|
||||
public:
|
||||
CefBrowserPlatformDelegateChromeChildWindow(
|
||||
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
|
||||
CefRefPtr<CefBrowserViewImpl> browser_view);
|
||||
|
||||
// CefBrowserPlatformDelegate overrides.
|
||||
void RenderViewCreated(content::RenderViewHost* render_view_host) override;
|
||||
void CloseHostWindow() override;
|
||||
void SetFocus(bool focus) override;
|
||||
|
||||
#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
|
||||
void NotifyMoveOrResizeStarted() override;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_BROWSER_PLATFORM_DELEGATE_CHROME_CHILD_WINDOW_H_
|
@@ -95,6 +95,11 @@ void CefBrowserPlatformDelegateChromeViews::CloseHostWindow() {
|
||||
widget->Close();
|
||||
}
|
||||
|
||||
CefWindowHandle CefBrowserPlatformDelegateChromeViews::GetHostWindowHandle()
|
||||
const {
|
||||
return view_util::GetWindowHandle(GetWindowWidget());
|
||||
}
|
||||
|
||||
views::Widget* CefBrowserPlatformDelegateChromeViews::GetWindowWidget() const {
|
||||
if (browser_view_->root_view())
|
||||
return browser_view_->root_view()->GetWidget();
|
||||
|
@@ -24,6 +24,7 @@ class CefBrowserPlatformDelegateChromeViews
|
||||
void NotifyBrowserDestroyed() override;
|
||||
void BrowserDestroyed(CefBrowserHostBase* browser) override;
|
||||
void CloseHostWindow() override;
|
||||
CefWindowHandle GetHostWindowHandle() const override;
|
||||
views::Widget* GetWindowWidget() const override;
|
||||
CefRefPtr<CefBrowserView> GetBrowserView() const override;
|
||||
void PopupWebContentsCreated(
|
||||
@@ -36,6 +37,8 @@ class CefBrowserPlatformDelegateChromeViews
|
||||
bool is_devtools) override;
|
||||
bool IsViewsHosted() const override;
|
||||
|
||||
CefRefPtr<CefBrowserViewImpl> browser_view() const { return browser_view_; }
|
||||
|
||||
private:
|
||||
void SetBrowserView(CefRefPtr<CefBrowserViewImpl> browser_view);
|
||||
|
||||
|
199
libcef/browser/chrome/views/chrome_child_window.cc
Normal file
199
libcef/browser/chrome/views/chrome_child_window.cc
Normal file
@@ -0,0 +1,199 @@
|
||||
// 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.
|
||||
|
||||
#include "libcef/browser/chrome/views/chrome_child_window.h"
|
||||
|
||||
#include "libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h"
|
||||
#include "libcef/browser/views/browser_view_impl.h"
|
||||
#include "libcef/browser/views/window_impl.h"
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
#include "libcef/browser/native/browser_platform_delegate_native_win.h"
|
||||
#include "ui/views/win/hwnd_util.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
class ChildWindowDelegate : public CefWindowDelegate {
|
||||
public:
|
||||
ChildWindowDelegate(const ChildWindowDelegate&) = delete;
|
||||
ChildWindowDelegate& operator=(const ChildWindowDelegate&) = delete;
|
||||
|
||||
static void Create(CefRefPtr<CefBrowserView> browser_view,
|
||||
const CefWindowInfo& window_info,
|
||||
gfx::AcceleratedWidget parent_handle) {
|
||||
DCHECK(parent_handle != gfx::kNullAcceleratedWidget);
|
||||
|
||||
// Create the Window. It will show itself after creation.
|
||||
CefWindowImpl::Create(new ChildWindowDelegate(browser_view, window_info),
|
||||
parent_handle);
|
||||
}
|
||||
|
||||
void OnWindowCreated(CefRefPtr<CefWindow> window) override {
|
||||
DCHECK(!window_);
|
||||
window_ = window;
|
||||
|
||||
// Add the browser view. It will now have an associated Widget.
|
||||
window_->AddChildView(browser_view_);
|
||||
|
||||
ShowWindow();
|
||||
}
|
||||
|
||||
void OnWindowDestroyed(CefRefPtr<CefWindow> window) override {
|
||||
browser_view_ = nullptr;
|
||||
window_ = nullptr;
|
||||
}
|
||||
|
||||
CefRect GetInitialBounds(CefRefPtr<CefWindow> window) override {
|
||||
CefRect initial_bounds(window_info_.bounds);
|
||||
if (initial_bounds.IsEmpty())
|
||||
return CefRect(0, 0, 800, 600);
|
||||
return initial_bounds;
|
||||
}
|
||||
|
||||
void ShowWindow() {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
auto widget = static_cast<CefWindowImpl*>(window_.get())->widget();
|
||||
DCHECK(widget);
|
||||
const HWND widget_hwnd = HWNDForWidget(widget);
|
||||
DCHECK(widget_hwnd);
|
||||
|
||||
// The native delegate needs state to perform some actions.
|
||||
auto browser =
|
||||
static_cast<CefBrowserHostBase*>(browser_view_->GetBrowser().get());
|
||||
auto platform_delegate = browser->platform_delegate();
|
||||
DCHECK(platform_delegate->IsViewsHosted());
|
||||
auto chrome_delegate =
|
||||
static_cast<CefBrowserPlatformDelegateChromeViews*>(platform_delegate);
|
||||
auto native_delegate = static_cast<CefBrowserPlatformDelegateNativeWin*>(
|
||||
chrome_delegate->native_delegate());
|
||||
native_delegate->set_widget(widget, widget_hwnd);
|
||||
|
||||
if (window_info_.ex_style & WS_EX_NOACTIVATE) {
|
||||
const DWORD widget_ex_styles = GetWindowLongPtr(widget_hwnd, GWL_EXSTYLE);
|
||||
|
||||
// Add the WS_EX_NOACTIVATE style on the DesktopWindowTreeHostWin HWND
|
||||
// so that HWNDMessageHandler::Show() called via Widget::Show() does not
|
||||
// activate the window.
|
||||
SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE,
|
||||
widget_ex_styles | WS_EX_NOACTIVATE);
|
||||
|
||||
window_->Show();
|
||||
|
||||
// Remove the WS_EX_NOACTIVATE style so that future mouse clicks inside
|
||||
// the browser correctly activate and focus the window.
|
||||
SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE, widget_ex_styles);
|
||||
return;
|
||||
}
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
|
||||
window_->Show();
|
||||
|
||||
// Give keyboard focus to the browser view.
|
||||
browser_view_->RequestFocus();
|
||||
}
|
||||
|
||||
private:
|
||||
ChildWindowDelegate(CefRefPtr<CefBrowserView> browser_view,
|
||||
const CefWindowInfo& window_info)
|
||||
: browser_view_(browser_view), window_info_(window_info) {}
|
||||
|
||||
CefRefPtr<CefBrowserView> browser_view_;
|
||||
const CefWindowInfo window_info_;
|
||||
|
||||
CefRefPtr<CefWindow> window_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ChildWindowDelegate);
|
||||
};
|
||||
|
||||
class ChildBrowserViewDelegate : public CefBrowserViewDelegate {
|
||||
public:
|
||||
ChildBrowserViewDelegate() = default;
|
||||
|
||||
ChildBrowserViewDelegate(const ChildBrowserViewDelegate&) = delete;
|
||||
ChildBrowserViewDelegate& operator=(const ChildBrowserViewDelegate&) = delete;
|
||||
|
||||
CefRefPtr<CefBrowserViewDelegate> GetDelegateForPopupBrowserView(
|
||||
CefRefPtr<CefBrowserView> browser_view,
|
||||
const CefBrowserSettings& settings,
|
||||
CefRefPtr<CefClient> client,
|
||||
bool is_devtools) override {
|
||||
return new ChildBrowserViewDelegate();
|
||||
}
|
||||
|
||||
bool OnPopupBrowserViewCreated(CefRefPtr<CefBrowserView> browser_view,
|
||||
CefRefPtr<CefBrowserView> popup_browser_view,
|
||||
bool is_devtools) override {
|
||||
DCHECK(!is_devtools);
|
||||
|
||||
auto new_browser = static_cast<CefBrowserHostBase*>(
|
||||
popup_browser_view->GetBrowser().get());
|
||||
auto new_platform_delegate = new_browser->platform_delegate();
|
||||
DCHECK(new_platform_delegate->IsViewsHosted());
|
||||
auto new_platform_delegate_impl =
|
||||
static_cast<CefBrowserPlatformDelegateChromeViews*>(
|
||||
new_platform_delegate);
|
||||
|
||||
const auto& window_info =
|
||||
new_platform_delegate_impl->native_delegate()->window_info();
|
||||
const auto parent_handle =
|
||||
chrome_child_window::GetParentHandle(window_info);
|
||||
if (parent_handle != gfx::kNullAcceleratedWidget) {
|
||||
ChildWindowDelegate::Create(popup_browser_view, window_info,
|
||||
parent_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use the default implementation that creates a new Views-hosted top-level
|
||||
// window.
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
IMPLEMENT_REFCOUNTING(ChildBrowserViewDelegate);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace chrome_child_window {
|
||||
|
||||
bool HasParentHandle(const CefWindowInfo& window_info) {
|
||||
return GetParentHandle(window_info) != gfx::kNullAcceleratedWidget;
|
||||
}
|
||||
|
||||
gfx::AcceleratedWidget GetParentHandle(const CefWindowInfo& window_info) {
|
||||
#if !BUILDFLAG(IS_MAC)
|
||||
return window_info.parent_window;
|
||||
#else
|
||||
return gfx::kNullAcceleratedWidget;
|
||||
#endif
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowserHostBase> MaybeCreateChildBrowser(
|
||||
const CefBrowserCreateParams& create_params) {
|
||||
// If the BrowserView already exists it means that we're dealing with a popup
|
||||
// and we'll instead create the Window in OnPopupBrowserViewCreated.
|
||||
if (create_params.browser_view)
|
||||
return nullptr;
|
||||
|
||||
if (!create_params.window_info)
|
||||
return nullptr;
|
||||
|
||||
const auto parent_handle = GetParentHandle(*create_params.window_info);
|
||||
if (parent_handle == gfx::kNullAcceleratedWidget)
|
||||
return nullptr;
|
||||
|
||||
// Create the BrowserView.
|
||||
auto browser_view = CefBrowserViewImpl::Create(
|
||||
*create_params.window_info, create_params.client, create_params.url,
|
||||
create_params.settings, create_params.extra_info,
|
||||
create_params.request_context, new ChildBrowserViewDelegate());
|
||||
|
||||
ChildWindowDelegate::Create(browser_view, *create_params.window_info,
|
||||
parent_handle);
|
||||
|
||||
return static_cast<CefBrowserHostBase*>(browser_view->GetBrowser().get());
|
||||
}
|
||||
|
||||
} // namespace chrome_child_window
|
24
libcef/browser/chrome/views/chrome_child_window.h
Normal file
24
libcef/browser/chrome/views/chrome_child_window.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// 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_CHROME_VIEWS_CHROME_CHILD_WINDOW_H_
|
||||
#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_CHILD_WINDOW_H_
|
||||
#pragma once
|
||||
|
||||
#include "libcef/browser/browser_host_base.h"
|
||||
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
|
||||
namespace chrome_child_window {
|
||||
|
||||
bool HasParentHandle(const CefWindowInfo& window_info);
|
||||
gfx::AcceleratedWidget GetParentHandle(const CefWindowInfo& window_info);
|
||||
|
||||
// Called from CefBrowserHostBase::Create.
|
||||
CefRefPtr<CefBrowserHostBase> MaybeCreateChildBrowser(
|
||||
const CefBrowserCreateParams& create_params);
|
||||
|
||||
} // namespace chrome_child_window
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_CHILD_WINDOW_H_
|
Reference in New Issue
Block a user