mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Support JavaScript window.moveTo/By() and resizeTo/By() (fixes #698)
Adds new CefDisplayHandler::OnContentsBoundsChange and CefDisplayHandler::GetRootWindowScreenRect callbacks. cefclient: Implement the above callbacks and call CefBrowserHost::NotifyScreenInfoChanged when the root window bounds change. cefclient: osr: Use real screen bounds by default. Pass `--fake-screen-bounds` for the old default behavior. Load https://tests/window in cefclient for additional implementation details and usage examples.
This commit is contained in:
@ -410,6 +410,8 @@
|
||||
'tests/cefclient/browser/temp_window_mac.mm',
|
||||
'tests/cefclient/browser/text_input_client_osr_mac.h',
|
||||
'tests/cefclient/browser/text_input_client_osr_mac.mm',
|
||||
'tests/cefclient/browser/util_mac.h',
|
||||
'tests/cefclient/browser/util_mac.mm',
|
||||
'tests/cefclient/browser/views_window_mac.mm',
|
||||
'tests/cefclient/browser/window_test_runner_mac.h',
|
||||
'tests/cefclient/browser/window_test_runner_mac.mm',
|
||||
|
@ -707,12 +707,24 @@ class CefBrowserHost : public virtual CefBaseRefCounted {
|
||||
virtual void WasHidden(bool hidden) = 0;
|
||||
|
||||
///
|
||||
/// Send a notification to the browser that the screen info has changed. The
|
||||
/// browser will then call CefRenderHandler::GetScreenInfo to update the
|
||||
/// screen information with the new values. This simulates moving the webview
|
||||
/// window from one display to another, or changing the properties of the
|
||||
/// current display. This method is only used when window rendering is
|
||||
/// disabled.
|
||||
/// Notify the browser that screen information has changed. Updated
|
||||
/// information will be sent to the renderer process to configure screen size
|
||||
/// and position values used by CSS and JavaScript (window.deviceScaleFactor,
|
||||
/// window.screenX/Y, window.outerWidth/Height, etc.). For background see
|
||||
/// https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-coordinate-systems
|
||||
///
|
||||
/// This method is used with (a) windowless rendering and (b) windowed
|
||||
/// rendering with external (client-provided) root window.
|
||||
///
|
||||
/// With windowless rendering the browser will call
|
||||
/// CefRenderHandler::GetScreenInfo, CefRenderHandler::GetRootScreenRect and
|
||||
/// CefRenderHandler::GetViewRect. This simulates moving or resizing the root
|
||||
/// window in the current display, moving the root window from one display to
|
||||
/// another, or changing the properties of the current display.
|
||||
///
|
||||
/// With windowed rendering the browser will call
|
||||
/// CefDisplayHandler::GetRootWindowScreenRect and use the associated
|
||||
/// display properties.
|
||||
///
|
||||
/*--cef()--*/
|
||||
virtual void NotifyScreenInfoChanged() = 0;
|
||||
|
@ -38,6 +38,7 @@
|
||||
#define CEF_INCLUDE_CEF_DISPLAY_HANDLER_H_
|
||||
#pragma once
|
||||
|
||||
#include "include/cef_api_hash.h"
|
||||
#include "include/cef_base.h"
|
||||
#include "include/cef_browser.h"
|
||||
#include "include/cef_frame.h"
|
||||
@ -123,7 +124,7 @@ class CefDisplayHandler : public virtual CefBaseRefCounted {
|
||||
///
|
||||
/// Called when auto-resize is enabled via
|
||||
/// CefBrowserHost::SetAutoResizeEnabled and the contents have auto-resized.
|
||||
/// |new_size| will be the desired size in view coordinates. Return true if
|
||||
/// |new_size| will be the desired size in DIP coordinates. Return true if
|
||||
/// the resize was handled or false for default handling.
|
||||
///
|
||||
/*--cef()--*/
|
||||
@ -162,6 +163,46 @@ class CefDisplayHandler : public virtual CefBaseRefCounted {
|
||||
virtual void OnMediaAccessChange(CefRefPtr<CefBrowser> browser,
|
||||
bool has_video_access,
|
||||
bool has_audio_access) {}
|
||||
|
||||
#if CEF_API_ADDED(CEF_NEXT)
|
||||
///
|
||||
/// Called when JavaScript is requesting new bounds via window.moveTo/By() or
|
||||
/// window.resizeTo/By(). |new_bounds| are in DIP screen coordinates.
|
||||
///
|
||||
/// With Views-hosted browsers |new_bounds| are the desired bounds for
|
||||
/// the containing CefWindow and may be passed directly to
|
||||
/// CefWindow::SetBounds. With external (client-provided) parent on macOS and
|
||||
/// Windows |new_bounds| are the desired frame bounds for the containing root
|
||||
/// window. With other non-Views browsers |new_bounds| are the desired bounds
|
||||
/// for the browser content only unless the client implements either
|
||||
/// CefDisplayHandler::GetRootWindowScreenRect for windowed browsers or
|
||||
/// CefRenderHandler::GetWindowScreenRect for windowless browsers. Clients may
|
||||
/// expand browser content bounds to window bounds using OS-specific or
|
||||
/// CefDisplay methods.
|
||||
///
|
||||
/// Return true if this method was handled or false for default handling.
|
||||
/// Default move/resize behavior is only provided with Views-hosted Chrome
|
||||
/// style browsers.
|
||||
///
|
||||
/*--cef(added=next)--*/
|
||||
virtual bool OnContentsBoundsChange(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& new_bounds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
///
|
||||
/// Called to retrieve the external (client-provided) root window rectangle in
|
||||
/// screen DIP coordinates. Only called for windowed browsers on Windows and
|
||||
/// Linux. Return true if the rectangle was provided. Return false to use the
|
||||
/// root window bounds on Windows or the browser content bounds on Linux. For
|
||||
/// additional usage details see CefBrowserHost::NotifyScreenInfoChanged.
|
||||
///
|
||||
/*--cef(added=next)--*/
|
||||
virtual bool GetRootWindowScreenRect(CefRefPtr<CefBrowser> browser,
|
||||
CefRect& rect) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // CEF_INCLUDE_CEF_DISPLAY_HANDLER_H_
|
||||
|
@ -50,6 +50,9 @@
|
||||
/// indicated. Methods must be called on the browser process UI thread unless
|
||||
/// otherwise indicated.
|
||||
///
|
||||
/// For details on coordinate systems and usage see
|
||||
/// https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-coordinate-systems
|
||||
///
|
||||
/*--cef(source=library)--*/
|
||||
class CefDisplay : public CefBaseRefCounted {
|
||||
public:
|
||||
@ -129,7 +132,9 @@ class CefDisplay : public CefBaseRefCounted {
|
||||
/// Returns this Display's device pixel scale factor. This specifies how much
|
||||
/// the UI should be scaled when the actual output has more pixels than
|
||||
/// standard displays (which is around 100~120dpi). The potential return
|
||||
/// values differ by platform.
|
||||
/// values differ by platform. Windowed browsers with 1.0 zoom will have a
|
||||
/// JavaScript `window.devicePixelRatio` value matching the associated
|
||||
/// Display's GetDeviceScaleFactor() value.
|
||||
///
|
||||
/*--cef()--*/
|
||||
virtual float GetDeviceScaleFactor() = 0;
|
||||
|
@ -416,24 +416,6 @@ void AlloyBrowserHostImpl::WasHidden(bool hidden) {
|
||||
}
|
||||
}
|
||||
|
||||
void AlloyBrowserHostImpl::NotifyScreenInfoChanged() {
|
||||
if (!IsWindowless()) {
|
||||
DCHECK(false) << "Window rendering is not disabled";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
CEF_POST_TASK(
|
||||
CEF_UIT,
|
||||
base::BindOnce(&AlloyBrowserHostImpl::NotifyScreenInfoChanged, this));
|
||||
return;
|
||||
}
|
||||
|
||||
if (platform_delegate_) {
|
||||
platform_delegate_->NotifyScreenInfoChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AlloyBrowserHostImpl::Invalidate(PaintElementType type) {
|
||||
if (!IsWindowless()) {
|
||||
DCHECK(false) << "Window rendering is not disabled";
|
||||
@ -998,6 +980,11 @@ void AlloyBrowserHostImpl::CloseContents(content::WebContents* source) {
|
||||
}
|
||||
}
|
||||
|
||||
void AlloyBrowserHostImpl::SetContentsBounds(content::WebContents* source,
|
||||
const gfx::Rect& bounds) {
|
||||
contents_delegate_.SetContentsBoundsEx(source, bounds);
|
||||
}
|
||||
|
||||
void AlloyBrowserHostImpl::UpdateTargetURL(content::WebContents* source,
|
||||
const GURL& url) {
|
||||
contents_delegate_.UpdateTargetURL(source, url);
|
||||
|
@ -90,7 +90,6 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
|
||||
bool IsWindowRenderingDisabled() override;
|
||||
void WasResized() override;
|
||||
void WasHidden(bool hidden) override;
|
||||
void NotifyScreenInfoChanged() override;
|
||||
void Invalidate(PaintElementType type) override;
|
||||
void SendExternalBeginFrame() override;
|
||||
void SendTouchEvent(const CefTouchEvent& event) override;
|
||||
@ -193,6 +192,8 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
|
||||
void LoadingStateChanged(content::WebContents* source,
|
||||
bool should_show_loading_ui) override;
|
||||
void CloseContents(content::WebContents* source) override;
|
||||
void SetContentsBounds(content::WebContents* source,
|
||||
const gfx::Rect& bounds) override;
|
||||
void UpdateTargetURL(content::WebContents* source, const GURL& url) override;
|
||||
bool DidAddMessageToConsole(content::WebContents* source,
|
||||
blink::mojom::ConsoleMessageLevel log_level,
|
||||
|
@ -142,6 +142,18 @@ content::WebContents* CefBrowserContentsDelegate::OpenURLFromTabEx(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CefBrowserContentsDelegate::SetContentsBoundsEx(
|
||||
content::WebContents* source,
|
||||
const gfx::Rect& bounds) {
|
||||
if (auto c = client()) {
|
||||
if (auto handler = c->GetDisplayHandler()) {
|
||||
return handler->OnContentsBoundsChange(
|
||||
browser(), {bounds.x(), bounds.y(), bounds.width(), bounds.height()});
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CefBrowserContentsDelegate::LoadingStateChanged(
|
||||
content::WebContents* source,
|
||||
bool should_show_loading_ui) {
|
||||
|
@ -87,6 +87,10 @@ class CefBrowserContentsDelegate : public content::WebContentsDelegate,
|
||||
base::OnceCallback<void(content::NavigationHandle&)>&
|
||||
navigation_handle_callback);
|
||||
|
||||
// Same as SetContentsBounds but returning false if unhandled.
|
||||
bool SetContentsBoundsEx(content::WebContents* source,
|
||||
const gfx::Rect& bounds);
|
||||
|
||||
// WebContentsDelegate methods:
|
||||
void LoadingStateChanged(content::WebContents* source,
|
||||
bool should_show_loading_ui) override;
|
||||
|
@ -817,9 +817,30 @@ void CefBrowserHostBase::NotifyMoveOrResizeStarted() {
|
||||
if (platform_delegate_) {
|
||||
platform_delegate_->NotifyMoveOrResizeStarted();
|
||||
}
|
||||
#else
|
||||
LOG(WARNING)
|
||||
<< "Incorrect usage of CefBrowserHost::NotifyMoveOrResizeStarted";
|
||||
#endif
|
||||
}
|
||||
|
||||
void CefBrowserHostBase::NotifyScreenInfoChanged() {
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
CEF_POST_TASK(
|
||||
CEF_UIT,
|
||||
base::BindOnce(&CefBrowserHostBase::NotifyScreenInfoChanged, this));
|
||||
return;
|
||||
}
|
||||
|
||||
if (platform_delegate_) {
|
||||
if (IsWindowless() || platform_delegate_->HasExternalParent()) {
|
||||
platform_delegate_->NotifyScreenInfoChanged();
|
||||
} else {
|
||||
LOG(WARNING)
|
||||
<< "Incorrect usage of CefBrowserHost::NotifyScreenInfoChanged";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CefBrowserHostBase::IsFullscreen() {
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
DCHECK(false) << "called on invalid thread";
|
||||
|
@ -265,6 +265,7 @@ class CefBrowserHostBase : public CefBrowserHost,
|
||||
void SetAudioMuted(bool mute) override;
|
||||
bool IsAudioMuted() override;
|
||||
void NotifyMoveOrResizeStarted() override;
|
||||
void NotifyScreenInfoChanged() override;
|
||||
bool IsFullscreen() override;
|
||||
void ExitFullscreen(bool will_cause_resize) override;
|
||||
bool IsRenderProcessUnresponsive() override;
|
||||
|
@ -244,8 +244,7 @@ void CefBrowserPlatformDelegate::PopupBrowserCreated(
|
||||
return;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowserView> new_browser_view =
|
||||
CefBrowserView::GetForBrowser(new_browser);
|
||||
auto new_browser_view = new_browser->GetBrowserView();
|
||||
CHECK(new_browser_view);
|
||||
|
||||
bool popup_handled = false;
|
||||
@ -389,9 +388,7 @@ bool CefBrowserPlatformDelegate::IsHidden() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegate::NotifyScreenInfoChanged() {
|
||||
DCHECK(false);
|
||||
}
|
||||
void CefBrowserPlatformDelegate::NotifyScreenInfoChanged() {}
|
||||
|
||||
void CefBrowserPlatformDelegate::Invalidate(cef_paint_element_type_t type) {
|
||||
DCHECK(false);
|
||||
|
@ -306,7 +306,7 @@ class CefBrowserPlatformDelegate {
|
||||
virtual bool IsHidden() const;
|
||||
|
||||
// Notify the browser that screen information has changed. Only used with
|
||||
// windowless rendering.
|
||||
// windowless rendering and external (client-provided) root window.
|
||||
virtual void NotifyScreenInfoChanged();
|
||||
|
||||
// Invalidate the view. Only used with windowless rendering.
|
||||
|
@ -173,6 +173,12 @@ class BrowserDelegate : public content::WebContentsDelegate {
|
||||
navigation_handle_callback) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Same as SetContentsBounds but returning false if unhandled.
|
||||
virtual bool SetContentsBoundsEx(content::WebContents* source,
|
||||
const gfx::Rect& bounds) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cef
|
||||
|
@ -573,6 +573,14 @@ bool ChromeBrowserDelegate::OpenURLFromTabEx(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChromeBrowserDelegate::SetContentsBoundsEx(content::WebContents* source,
|
||||
const gfx::Rect& bounds) {
|
||||
if (auto delegate = GetDelegateForWebContents(source)) {
|
||||
return delegate->SetContentsBoundsEx(source, bounds);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChromeBrowserDelegate::LoadingStateChanged(content::WebContents* source,
|
||||
bool should_show_loading_ui) {
|
||||
if (auto delegate = GetDelegateForWebContents(source)) {
|
||||
|
@ -94,6 +94,8 @@ class ChromeBrowserDelegate : public cef::BrowserDelegate {
|
||||
const content::OpenURLParams& params,
|
||||
base::OnceCallback<void(content::NavigationHandle&)>&
|
||||
navigation_handle_callback) override;
|
||||
bool SetContentsBoundsEx(content::WebContents* source,
|
||||
const gfx::Rect& bounds) override;
|
||||
|
||||
// WebContentsDelegate methods:
|
||||
void WebContentsCreated(content::WebContents* source_contents,
|
||||
|
@ -250,10 +250,6 @@ void ChromeBrowserHostImpl::WasHidden(bool hidden) {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void ChromeBrowserHostImpl::NotifyScreenInfoChanged() {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void ChromeBrowserHostImpl::Invalidate(PaintElementType type) {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
@ -84,7 +84,6 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
|
||||
bool IsWindowRenderingDisabled() override { return false; }
|
||||
void WasResized() override;
|
||||
void WasHidden(bool hidden) override;
|
||||
void NotifyScreenInfoChanged() override;
|
||||
void Invalidate(PaintElementType type) override;
|
||||
void SendExternalBeginFrame() override;
|
||||
void SendTouchEvent(const CefTouchEvent& event) override;
|
||||
|
@ -14,6 +14,10 @@
|
||||
#include "ui/views/win/hwnd_util.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_AURA)
|
||||
#include "cef/libcef/browser/native/browser_platform_delegate_native_aura.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
gfx::AcceleratedWidget GetParentWidget(const CefWindowInfo& window_info) {
|
||||
@ -61,6 +65,9 @@ class ChildWindowDelegate : public CefWindowDelegate {
|
||||
void OnWindowDestroyed(CefRefPtr<CefWindow> window) override {
|
||||
browser_view_ = nullptr;
|
||||
window_ = nullptr;
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
native_delegate_ = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
CefRect GetInitialBounds(CefRefPtr<CefWindow> window) override {
|
||||
@ -71,22 +78,38 @@ class ChildWindowDelegate : public CefWindowDelegate {
|
||||
return initial_bounds;
|
||||
}
|
||||
|
||||
#if defined(USE_AURA)
|
||||
void OnWindowBoundsChanged(CefRefPtr<CefWindow> window,
|
||||
const CefRect& new_bounds) override {
|
||||
if (native_delegate_) {
|
||||
// Send new bounds to the renderer process and trigger the resize event.
|
||||
native_delegate_->NotifyScreenInfoChanged();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
void ShowWindow() {
|
||||
#if defined(USE_AURA)
|
||||
auto browser = CefBrowserHostBase::FromBrowser(browser_view_->GetBrowser());
|
||||
auto platform_delegate = browser->platform_delegate();
|
||||
DCHECK(platform_delegate->IsViewsHosted());
|
||||
auto chrome_delegate =
|
||||
static_cast<CefBrowserPlatformDelegateChromeViews*>(platform_delegate);
|
||||
native_delegate_ = static_cast<CefBrowserPlatformDelegateNativeAura*>(
|
||||
chrome_delegate->native_delegate());
|
||||
native_delegate_->InstallRootWindowBoundsCallback();
|
||||
|
||||
#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 = CefBrowserHostBase::FromBrowser(browser_view_->GetBrowser());
|
||||
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);
|
||||
// The Windows delegate needs state to perform some actions.
|
||||
auto* delegate_win =
|
||||
static_cast<CefBrowserPlatformDelegateNativeWin*>(native_delegate_);
|
||||
delegate_win->set_widget(widget, widget_hwnd);
|
||||
|
||||
if (window_info_.ex_style & WS_EX_NOACTIVATE) {
|
||||
const DWORD widget_ex_styles = GetWindowLongPtr(widget_hwnd, GWL_EXSTYLE);
|
||||
@ -105,6 +128,7 @@ class ChildWindowDelegate : public CefWindowDelegate {
|
||||
return;
|
||||
}
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
#endif // defined(USE_AURA)
|
||||
|
||||
window_->Show();
|
||||
|
||||
@ -112,7 +136,6 @@ class ChildWindowDelegate : public CefWindowDelegate {
|
||||
browser_view_->RequestFocus();
|
||||
}
|
||||
|
||||
private:
|
||||
ChildWindowDelegate(CefRefPtr<CefBrowserView> browser_view,
|
||||
const CefWindowInfo& window_info)
|
||||
: browser_view_(browser_view), window_info_(window_info) {}
|
||||
@ -122,6 +145,11 @@ class ChildWindowDelegate : public CefWindowDelegate {
|
||||
|
||||
CefRefPtr<CefWindow> window_;
|
||||
|
||||
#if defined(USE_AURA)
|
||||
base::raw_ptr<CefBrowserPlatformDelegateNativeAura> native_delegate_ =
|
||||
nullptr;
|
||||
#endif
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ChildWindowDelegate);
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "cef/libcef/browser/native/browser_platform_delegate_native.h"
|
||||
|
||||
#include "cef/libcef/browser/alloy/alloy_browser_host_impl.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_impl.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host.h"
|
||||
#include "third_party/blink/public/common/input/web_mouse_event.h"
|
||||
@ -24,3 +25,25 @@ void CefBrowserPlatformDelegateNative::WasResized() {
|
||||
host->GetWidget()->SynchronizeVisualProperties();
|
||||
}
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegateNative::NotifyScreenInfoChanged() {
|
||||
content::RenderWidgetHostImpl* render_widget_host = nullptr;
|
||||
if (web_contents_) {
|
||||
if (auto* rvh = web_contents_->GetRenderViewHost()) {
|
||||
render_widget_host =
|
||||
content::RenderWidgetHostImpl::From(rvh->GetWidget());
|
||||
}
|
||||
}
|
||||
if (!render_widget_host) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send updated screen bounds information to the renderer process.
|
||||
if (render_widget_host->delegate()) {
|
||||
render_widget_host->delegate()->SendScreenRects();
|
||||
} else {
|
||||
render_widget_host->SendScreenRects();
|
||||
}
|
||||
|
||||
render_widget_host->NotifyScreenInfoChanged();
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ class CefBrowserPlatformDelegateNative
|
||||
// CefBrowserPlatformDelegate methods:
|
||||
SkColor GetBackgroundColor() const override;
|
||||
void WasResized() override;
|
||||
void NotifyScreenInfoChanged() override;
|
||||
|
||||
// Translate CEF events to Chromium/Blink Web events.
|
||||
virtual input::NativeWebKeyboardEvent TranslateWebKeyEvent(
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "cef/libcef/browser/native/browser_platform_delegate_native_aura.h"
|
||||
|
||||
#include "cef/libcef/browser/browser_host_base.h"
|
||||
#include "cef/libcef/browser/native/menu_runner_views_aura.h"
|
||||
#include "cef/libcef/browser/views/view_util.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
|
||||
@ -19,6 +20,42 @@ CefBrowserPlatformDelegateNativeAura::CefBrowserPlatformDelegateNativeAura(
|
||||
SkColor background_color)
|
||||
: CefBrowserPlatformDelegateNative(window_info, background_color) {}
|
||||
|
||||
void CefBrowserPlatformDelegateNativeAura::InstallRootWindowBoundsCallback() {
|
||||
auto* host_view = GetHostView();
|
||||
CHECK(host_view);
|
||||
|
||||
host_view->SetRootWindowBoundsCallback(base::BindRepeating(
|
||||
[](base::WeakPtr<CefBrowserPlatformDelegateNativeAura> self) {
|
||||
return self->RootWindowBoundsCallback();
|
||||
},
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
std::optional<gfx::Rect>
|
||||
CefBrowserPlatformDelegateNativeAura::RootWindowBoundsCallback() {
|
||||
if (browser_) {
|
||||
if (auto client = browser_->client()) {
|
||||
if (auto handler = client->GetDisplayHandler()) {
|
||||
CefRect rect;
|
||||
if (handler->GetRootWindowScreenRect(browser_.get(), rect) &&
|
||||
!rect.IsEmpty()) {
|
||||
return gfx::Rect(rect.x, rect.y, rect.width, rect.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call the default platform implementation, if any.
|
||||
return GetRootWindowBounds();
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegateNativeAura::RenderViewReady() {
|
||||
CefBrowserPlatformDelegateNative::RenderViewReady();
|
||||
|
||||
// The RWHV should now exist for Alloy style browsers.
|
||||
InstallRootWindowBoundsCallback();
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegateNativeAura::SendKeyEvent(
|
||||
const CefKeyEvent& event) {
|
||||
auto view = GetHostView();
|
||||
|
@ -5,19 +5,19 @@
|
||||
#ifndef CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_AURA_H_
|
||||
#define CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_AURA_H_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "cef/libcef/browser/native/browser_platform_delegate_native.h"
|
||||
#include "ui/events/event.h"
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
#include "ui/gfx/geometry/vector2d.h"
|
||||
|
||||
namespace content {
|
||||
class RenderWidgetHostViewAura;
|
||||
}
|
||||
|
||||
namespace gfx {
|
||||
class Vector2d;
|
||||
}
|
||||
|
||||
// Windowed browser implementation for Aura platforms.
|
||||
class CefBrowserPlatformDelegateNativeAura
|
||||
: public CefBrowserPlatformDelegateNative {
|
||||
@ -25,7 +25,10 @@ class CefBrowserPlatformDelegateNativeAura
|
||||
CefBrowserPlatformDelegateNativeAura(const CefWindowInfo& window_info,
|
||||
SkColor background_color);
|
||||
|
||||
void InstallRootWindowBoundsCallback();
|
||||
|
||||
// CefBrowserPlatformDelegate methods:
|
||||
void RenderViewReady() override;
|
||||
void SendKeyEvent(const CefKeyEvent& event) override;
|
||||
void SendMouseClickEvent(const CefMouseEvent& event,
|
||||
CefBrowserHost::MouseButtonType type,
|
||||
@ -71,9 +74,16 @@ class CefBrowserPlatformDelegateNativeAura
|
||||
int deltaY) const;
|
||||
virtual gfx::Vector2d GetUiWheelEventOffset(int deltaX, int deltaY) const;
|
||||
|
||||
// Returns the root window bounds in screen DIP coordinates.
|
||||
virtual std::optional<gfx::Rect> GetRootWindowBounds() {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
protected:
|
||||
base::OnceClosure GetWidgetDeleteCallback();
|
||||
|
||||
std::optional<gfx::Rect> RootWindowBoundsCallback();
|
||||
|
||||
static base::TimeTicks GetEventTimeStamp();
|
||||
static int TranslateUiEventModifiers(uint32_t cef_modifiers);
|
||||
static int TranslateUiChangedButtonFlags(uint32_t cef_modifiers);
|
||||
|
@ -427,6 +427,27 @@ CefEventHandle CefBrowserPlatformDelegateNativeWin::GetEventHandle(
|
||||
const_cast<CHROME_MSG*>(&event.os_event->native_event()));
|
||||
}
|
||||
|
||||
std::optional<gfx::Rect>
|
||||
CefBrowserPlatformDelegateNativeWin::GetRootWindowBounds() {
|
||||
if (window_widget_) {
|
||||
if (HWND hwnd = GetHostWindowHandle()) {
|
||||
if (HWND root_hwnd = ::GetAncestor(hwnd, GA_ROOT)) {
|
||||
RECT root_rect = {};
|
||||
if (::GetWindowRect(root_hwnd, &root_rect)) {
|
||||
auto* top_level =
|
||||
window_widget_->GetNativeWindow()->GetToplevelWindow();
|
||||
gfx::Rect bounds(root_rect);
|
||||
bounds = display::Screen::GetScreen()->ScreenToDIPRectInWindow(
|
||||
top_level, bounds);
|
||||
return bounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ui::KeyEvent CefBrowserPlatformDelegateNativeWin::TranslateUiKeyEvent(
|
||||
const CefKeyEvent& key_event) const {
|
||||
int flags = TranslateUiEventModifiers(key_event.modifiers);
|
||||
@ -596,8 +617,8 @@ LRESULT CALLBACK CefBrowserPlatformDelegateNativeWin::WndProc(HWND hwnd,
|
||||
|
||||
case WM_MOVING:
|
||||
case WM_MOVE:
|
||||
if (browser) {
|
||||
browser->NotifyMoveOrResizeStarted();
|
||||
if (platform_delegate) {
|
||||
platform_delegate->NotifyMoveOrResizeStarted();
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
@ -32,6 +32,7 @@ class CefBrowserPlatformDelegateNativeWin
|
||||
bool HandleKeyboardEvent(const input::NativeWebKeyboardEvent& event) override;
|
||||
CefEventHandle GetEventHandle(
|
||||
const input::NativeWebKeyboardEvent& event) const override;
|
||||
std::optional<gfx::Rect> GetRootWindowBounds() override;
|
||||
|
||||
// CefBrowserPlatformDelegateNativeAura methods:
|
||||
ui::KeyEvent TranslateUiKeyEvent(const CefKeyEvent& key_event) const override;
|
||||
|
@ -393,7 +393,10 @@ patches = [
|
||||
#
|
||||
# Windows: Fix crash during window creation.
|
||||
# https://bugs.chromium.org/p/chromium/issues/detail?id=761389
|
||||
'name': 'rwh_background_color_1984',
|
||||
#
|
||||
# Add RWHVAura::SetRootWindowBoundsCallback.
|
||||
# https://github.com/chromiumembedded/cef/issues/3920
|
||||
'name': 'renderer_host_aura',
|
||||
},
|
||||
{
|
||||
# Expose RFH via NavigationHandle for retrieval in DidFinishNavigation on
|
||||
|
@ -136,7 +136,7 @@ index 51c55cb054ae7..df9aa9bc45a67 100644
|
||||
]
|
||||
}
|
||||
diff --git chrome/browser/ui/browser.cc chrome/browser/ui/browser.cc
|
||||
index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
index d45f8f1713c87..de476f1ed4081 100644
|
||||
--- chrome/browser/ui/browser.cc
|
||||
+++ chrome/browser/ui/browser.cc
|
||||
@@ -272,6 +272,25 @@
|
||||
@ -285,7 +285,21 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
}
|
||||
|
||||
void Browser::CloseContents(WebContents* source) {
|
||||
@@ -2177,6 +2246,8 @@ void Browser::SetContentsBounds(WebContents* source, const gfx::Rect& bounds) {
|
||||
@@ -2157,6 +2226,13 @@ void Browser::CloseContents(WebContents* source) {
|
||||
}
|
||||
|
||||
void Browser::SetContentsBounds(WebContents* source, const gfx::Rect& bounds) {
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ if (cef_browser_delegate_ &&
|
||||
+ cef_browser_delegate_->SetContentsBoundsEx(source, bounds)) {
|
||||
+ return;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
if (is_type_normal()) {
|
||||
return;
|
||||
}
|
||||
@@ -2177,6 +2253,8 @@ void Browser::SetContentsBounds(WebContents* source, const gfx::Rect& bounds) {
|
||||
}
|
||||
|
||||
void Browser::UpdateTargetURL(WebContents* source, const GURL& url) {
|
||||
@ -294,7 +308,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
std::vector<StatusBubble*> status_bubbles = GetStatusBubbles();
|
||||
for (StatusBubble* status_bubble : status_bubbles) {
|
||||
StatusBubbleViews* status_bubble_views =
|
||||
@@ -2190,6 +2261,17 @@ void Browser::UpdateTargetURL(WebContents* source, const GURL& url) {
|
||||
@@ -2190,6 +2268,17 @@ void Browser::UpdateTargetURL(WebContents* source, const GURL& url) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,7 +326,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
void Browser::ContentsMouseEvent(WebContents* source, const ui::Event& event) {
|
||||
const ui::EventType type = event.type();
|
||||
const bool exited = type == ui::EventType::kMouseExited;
|
||||
@@ -2223,9 +2305,23 @@ void Browser::ContentsZoomChange(bool zoom_in) {
|
||||
@@ -2223,9 +2312,23 @@ void Browser::ContentsZoomChange(bool zoom_in) {
|
||||
}
|
||||
|
||||
bool Browser::TakeFocus(content::WebContents* source, bool reverse) {
|
||||
@ -336,7 +350,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
void Browser::BeforeUnloadFired(WebContents* web_contents,
|
||||
bool proceed,
|
||||
bool* proceed_to_fire_unload) {
|
||||
@@ -2338,12 +2434,24 @@ void Browser::WebContentsCreated(WebContents* source_contents,
|
||||
@@ -2338,12 +2441,24 @@ void Browser::WebContentsCreated(WebContents* source_contents,
|
||||
// to track `new_contents` after it is added to its TabModel this override can
|
||||
// be removed.
|
||||
CreateSessionServiceTabHelper(new_contents);
|
||||
@ -361,7 +375,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
// Don't show the page hung dialog when a HTML popup hangs because
|
||||
// the dialog will take the focus and immediately close the popup.
|
||||
RenderWidgetHostView* view = render_widget_host->GetView();
|
||||
@@ -2356,6 +2464,13 @@ void Browser::RendererUnresponsive(
|
||||
@@ -2356,6 +2471,13 @@ void Browser::RendererUnresponsive(
|
||||
void Browser::RendererResponsive(
|
||||
WebContents* source,
|
||||
content::RenderWidgetHost* render_widget_host) {
|
||||
@ -375,7 +389,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
RenderWidgetHostView* view = render_widget_host->GetView();
|
||||
if (view && !render_widget_host->GetView()->IsHTMLFormPopup()) {
|
||||
TabDialogs::FromWebContents(source)->HideHungRendererDialog(
|
||||
@@ -2365,6 +2480,15 @@ void Browser::RendererResponsive(
|
||||
@@ -2365,6 +2487,15 @@ void Browser::RendererResponsive(
|
||||
|
||||
content::JavaScriptDialogManager* Browser::GetJavaScriptDialogManager(
|
||||
WebContents* source) {
|
||||
@ -391,7 +405,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
return javascript_dialogs::TabModalDialogManager::FromWebContents(source);
|
||||
}
|
||||
|
||||
@@ -2400,6 +2524,11 @@ void Browser::DraggableRegionsChanged(
|
||||
@@ -2400,6 +2531,11 @@ void Browser::DraggableRegionsChanged(
|
||||
if (app_controller_) {
|
||||
app_controller_->DraggableRegionsChanged(regions, contents);
|
||||
}
|
||||
@ -403,7 +417,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
}
|
||||
|
||||
std::vector<blink::mojom::RelatedApplicationPtr>
|
||||
@@ -2514,11 +2643,15 @@ void Browser::EnterFullscreenModeForTab(
|
||||
@@ -2514,11 +2650,15 @@ void Browser::EnterFullscreenModeForTab(
|
||||
const blink::mojom::FullscreenOptions& options) {
|
||||
exclusive_access_manager_->fullscreen_controller()->EnterFullscreenModeForTab(
|
||||
requesting_frame, options.display_id);
|
||||
@ -419,7 +433,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
}
|
||||
|
||||
bool Browser::IsFullscreenForTabOrPending(const WebContents* web_contents) {
|
||||
@@ -2728,6 +2861,16 @@ void Browser::RequestMediaAccessPermission(
|
||||
@@ -2728,6 +2868,16 @@ void Browser::RequestMediaAccessPermission(
|
||||
content::WebContents* web_contents,
|
||||
const content::MediaStreamRequest& request,
|
||||
content::MediaResponseCallback callback) {
|
||||
@ -436,7 +450,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
const extensions::Extension* extension =
|
||||
GetExtensionForOrigin(profile_, request.security_origin);
|
||||
MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
|
||||
@@ -3313,9 +3456,11 @@ void Browser::RemoveScheduledUpdatesFor(WebContents* contents) {
|
||||
@@ -3313,9 +3463,11 @@ void Browser::RemoveScheduledUpdatesFor(WebContents* contents) {
|
||||
// Browser, Getters for UI (private):
|
||||
|
||||
std::vector<StatusBubble*> Browser::GetStatusBubbles() {
|
||||
@ -449,7 +463,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
}
|
||||
|
||||
// We hide the status bar for web apps windows as this matches native
|
||||
@@ -3323,6 +3468,12 @@ std::vector<StatusBubble*> Browser::GetStatusBubbles() {
|
||||
@@ -3323,6 +3475,12 @@ std::vector<StatusBubble*> Browser::GetStatusBubbles() {
|
||||
// mode, as the minimal browser UI includes the status bar.
|
||||
if (web_app::AppBrowserController::IsWebApp(this) &&
|
||||
!app_controller()->HasMinimalUiButtons()) {
|
||||
@ -462,7 +476,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -3476,6 +3627,8 @@ void Browser::SetAsDelegate(WebContents* web_contents, bool set_delegate) {
|
||||
@@ -3476,6 +3634,8 @@ void Browser::SetAsDelegate(WebContents* web_contents, bool set_delegate) {
|
||||
BookmarkTabHelper::FromWebContents(web_contents)->RemoveObserver(this);
|
||||
web_contents_collection_.StopObserving(web_contents);
|
||||
}
|
||||
@ -471,7 +485,7 @@ index d45f8f1713c87..7d69f3d8bd4cc 100644
|
||||
}
|
||||
|
||||
void Browser::TabDetachedAtImpl(content::WebContents* contents,
|
||||
@@ -3637,6 +3790,14 @@ bool Browser::PictureInPictureBrowserSupportsWindowFeature(
|
||||
@@ -3637,6 +3797,14 @@ bool Browser::PictureInPictureBrowserSupportsWindowFeature(
|
||||
|
||||
bool Browser::SupportsWindowFeatureImpl(WindowFeature feature,
|
||||
bool check_can_support) const {
|
||||
|
@ -1,15 +1,15 @@
|
||||
diff --git content/browser/renderer_host/render_widget_host_view_aura.cc content/browser/renderer_host/render_widget_host_view_aura.cc
|
||||
index 5867fc3e77326..54ac130dea600 100644
|
||||
index 5867fc3e77326..23656289851bc 100644
|
||||
--- content/browser/renderer_host/render_widget_host_view_aura.cc
|
||||
+++ content/browser/renderer_host/render_widget_host_view_aura.cc
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <limits>
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <memory>
|
||||
+#include <tuple>
|
||||
#include <set>
|
||||
#include <string_view>
|
||||
+#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "base/auto_reset.h"
|
||||
@@ -52,6 +53,7 @@
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "content/public/browser/device_service.h"
|
||||
@ -28,7 +28,20 @@ index 5867fc3e77326..54ac130dea600 100644
|
||||
SkColor color = *GetBackgroundColor();
|
||||
window_->layer()->SetColor(color);
|
||||
}
|
||||
@@ -2664,6 +2669,16 @@ void RenderWidgetHostViewAura::CreateAuraWindow(aura::client::WindowType type) {
|
||||
@@ -1102,6 +1107,12 @@ void RenderWidgetHostViewAura::TransformPointToRootSurface(gfx::PointF* point) {
|
||||
}
|
||||
|
||||
gfx::Rect RenderWidgetHostViewAura::GetBoundsInRootWindow() {
|
||||
+ if (!root_window_bounds_callback_.is_null()) {
|
||||
+ if (auto bounds = root_window_bounds_callback_.Run()) {
|
||||
+ return *bounds;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
aura::Window* top_level = window_->GetToplevelWindow();
|
||||
gfx::Rect bounds(top_level->GetBoundsInScreen());
|
||||
|
||||
@@ -2664,6 +2675,16 @@ void RenderWidgetHostViewAura::CreateAuraWindow(aura::client::WindowType type) {
|
||||
window_->layer()->SetColor(GetBackgroundColor() ? *GetBackgroundColor()
|
||||
: SK_ColorWHITE);
|
||||
UpdateFrameSinkIdRegistration();
|
||||
@ -45,3 +58,29 @@ index 5867fc3e77326..54ac130dea600 100644
|
||||
}
|
||||
|
||||
void RenderWidgetHostViewAura::UpdateFrameSinkIdRegistration() {
|
||||
diff --git content/browser/renderer_host/render_widget_host_view_aura.h content/browser/renderer_host/render_widget_host_view_aura.h
|
||||
index 6f96b83c36ee0..52cc4b37f0bbe 100644
|
||||
--- content/browser/renderer_host/render_widget_host_view_aura.h
|
||||
+++ content/browser/renderer_host/render_widget_host_view_aura.h
|
||||
@@ -451,6 +451,12 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
|
||||
}
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
|
||||
+ using RootWindowBoundsCallback =
|
||||
+ base::RepeatingCallback<std::optional<gfx::Rect>()>;
|
||||
+ void SetRootWindowBoundsCallback(const RootWindowBoundsCallback& callback) {
|
||||
+ root_window_bounds_callback_ = callback;
|
||||
+ }
|
||||
+
|
||||
protected:
|
||||
~RenderWidgetHostViewAura() override;
|
||||
|
||||
@@ -874,6 +880,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
|
||||
|
||||
std::optional<display::ScopedDisplayObserver> display_observer_;
|
||||
|
||||
+ RootWindowBoundsCallback root_window_bounds_callback_;
|
||||
+
|
||||
base::WeakPtrFactory<RenderWidgetHostViewAura> weak_ptr_factory_{this};
|
||||
};
|
||||
|
@ -83,6 +83,16 @@ void BrowserWindow::OnAutoResize(const CefSize& new_size) {
|
||||
delegate_->OnAutoResize(new_size);
|
||||
}
|
||||
|
||||
void BrowserWindow::OnContentsBounds(const CefRect& new_bounds) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
delegate_->OnContentsBounds(new_bounds);
|
||||
}
|
||||
|
||||
bool BrowserWindow::GetRootWindowScreenRect(CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
return delegate_->GetRootWindowScreenRect(rect);
|
||||
}
|
||||
|
||||
void BrowserWindow::OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) {
|
||||
|
@ -20,7 +20,8 @@ namespace client {
|
||||
class BrowserWindow : public ClientHandler::Delegate {
|
||||
public:
|
||||
// This interface is implemented by the owner of the BrowserWindow. The
|
||||
// methods of this class will be called on the main thread.
|
||||
// methods of this class will be called on the main thread unless otherwise
|
||||
// indicated.
|
||||
class Delegate {
|
||||
public:
|
||||
// Returns true if the window should use Alloy style. Safe to call on any
|
||||
@ -48,6 +49,9 @@ class BrowserWindow : public ClientHandler::Delegate {
|
||||
// Auto-resize contents.
|
||||
virtual void OnAutoResize(const CefSize& new_size) = 0;
|
||||
|
||||
// Set contents bounds.
|
||||
virtual void OnContentsBounds(const CefRect& new_bounds) = 0;
|
||||
|
||||
// Set the loading state.
|
||||
virtual void OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
@ -57,6 +61,9 @@ class BrowserWindow : public ClientHandler::Delegate {
|
||||
virtual void OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) = 0;
|
||||
|
||||
// Called on the UI thread to retrieve root window bounds.
|
||||
virtual bool GetRootWindowScreenRect(CefRect& rect) { return false; }
|
||||
|
||||
protected:
|
||||
virtual ~Delegate() = default;
|
||||
};
|
||||
@ -132,13 +139,15 @@ class BrowserWindow : public ClientHandler::Delegate {
|
||||
void OnSetTitle(const std::string& title) override;
|
||||
void OnSetFullscreen(bool fullscreen) override;
|
||||
void OnAutoResize(const CefSize& new_size) override;
|
||||
void OnContentsBounds(const CefRect& new_bounds) override;
|
||||
bool GetRootWindowScreenRect(CefRect& rect) override;
|
||||
void OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) override;
|
||||
void OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) override;
|
||||
|
||||
Delegate* delegate_;
|
||||
Delegate* const delegate_;
|
||||
CefRefPtr<CefBrowser> browser_;
|
||||
CefRefPtr<ClientHandler> client_handler_;
|
||||
bool is_closing_ = false;
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "include/base/cef_logging.h"
|
||||
#include "include/base/cef_macros.h"
|
||||
#include "include/views/cef_display.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "tests/cefclient/browser/util_gtk.h"
|
||||
#include "tests/shared/browser/geometry_util.h"
|
||||
@ -1092,7 +1093,7 @@ void BrowserWindowOsrGtk::SetDeviceScaleFactor(float device_scale_factor) {
|
||||
}
|
||||
|
||||
// Apply some sanity checks.
|
||||
if (device_scale_factor < 1.0f || device_scale_factor > 4.0f) {
|
||||
if (device_scale_factor < 0.5f || device_scale_factor > 4.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1142,15 +1143,36 @@ void BrowserWindowOsrGtk::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
bool BrowserWindowOsrGtk::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
|
||||
CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (!renderer_.settings().real_screen_bounds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!glarea_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float device_scale_factor;
|
||||
{
|
||||
base::AutoLock lock_scope(lock_);
|
||||
device_scale_factor = device_scale_factor_;
|
||||
}
|
||||
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
|
||||
GtkWidget* toplevel = gtk_widget_get_toplevel(glarea_);
|
||||
|
||||
// Convert to DIP coordinates.
|
||||
rect = DeviceToLogical(
|
||||
GetWindowBounds(GTK_WINDOW(toplevel), /*include_frame=*/true),
|
||||
device_scale_factor);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BrowserWindowOsrGtk::GetViewRect(CefRefPtr<CefBrowser> browser,
|
||||
CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
rect.x = rect.y = 0;
|
||||
|
||||
if (!glarea_) {
|
||||
// Never return an empty rectangle.
|
||||
rect.width = rect.height = 1;
|
||||
@ -1163,18 +1185,24 @@ void BrowserWindowOsrGtk::GetViewRect(CefRefPtr<CefBrowser> browser,
|
||||
device_scale_factor = device_scale_factor_;
|
||||
}
|
||||
|
||||
// The simulated screen and view rectangle are the same. This is necessary
|
||||
// for popup menus to be located and sized inside the view.
|
||||
GtkAllocation allocation;
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
|
||||
GtkAllocation allocation = {};
|
||||
gtk_widget_get_allocation(glarea_, &allocation);
|
||||
rect.width = DeviceToLogical(allocation.width, device_scale_factor);
|
||||
|
||||
// Convert to DIP coordinates.
|
||||
rect = DeviceToLogical(
|
||||
{allocation.x, allocation.y, allocation.width, allocation.height},
|
||||
device_scale_factor);
|
||||
if (rect.width == 0) {
|
||||
rect.width = 1;
|
||||
}
|
||||
rect.height = DeviceToLogical(allocation.height, device_scale_factor);
|
||||
if (rect.height == 0) {
|
||||
rect.height = 1;
|
||||
}
|
||||
if (!renderer_.settings().real_screen_bounds) {
|
||||
rect.x = rect.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool BrowserWindowOsrGtk::GetScreenPoint(CefRefPtr<CefBrowser> browser,
|
||||
@ -1204,9 +1232,6 @@ bool BrowserWindowOsrGtk::GetScreenInfo(CefRefPtr<CefBrowser> browser,
|
||||
CefScreenInfo& screen_info) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
CefRect view_rect;
|
||||
GetViewRect(browser, view_rect);
|
||||
|
||||
float device_scale_factor;
|
||||
{
|
||||
base::AutoLock lock_scope(lock_);
|
||||
@ -1215,10 +1240,23 @@ bool BrowserWindowOsrGtk::GetScreenInfo(CefRefPtr<CefBrowser> browser,
|
||||
|
||||
screen_info.device_scale_factor = device_scale_factor;
|
||||
|
||||
// The screen info rectangles are used by the renderer to create and position
|
||||
// popups. Keep popups inside the view rectangle.
|
||||
if (renderer_.settings().real_screen_bounds) {
|
||||
CefRect root_rect;
|
||||
GetRootScreenRect(browser, root_rect);
|
||||
|
||||
auto display = CefDisplay::GetDisplayMatchingBounds(
|
||||
root_rect, /*input_pixel_coords=*/false);
|
||||
screen_info.rect = display->GetBounds();
|
||||
screen_info.available_rect = display->GetWorkArea();
|
||||
} else {
|
||||
CefRect view_rect;
|
||||
GetViewRect(browser, view_rect);
|
||||
|
||||
// Keep HTML select popups inside the view rectangle.
|
||||
screen_info.rect = view_rect;
|
||||
screen_info.available_rect = view_rect;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -9,14 +9,18 @@
|
||||
#include <OpenGL/gl.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "include/base/cef_logging.h"
|
||||
#include "include/cef_parser.h"
|
||||
#include "include/views/cef_display.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "tests/cefclient/browser/bytes_write_handler.h"
|
||||
#include "tests/cefclient/browser/main_context.h"
|
||||
#include "tests/cefclient/browser/osr_accessibility_helper.h"
|
||||
#include "tests/cefclient/browser/osr_accessibility_node.h"
|
||||
#include "tests/cefclient/browser/text_input_client_osr_mac.h"
|
||||
#include "tests/cefclient/browser/util_mac.h"
|
||||
#include "tests/shared/browser/geometry_util.h"
|
||||
#include "tests/shared/browser/main_message_loop.h"
|
||||
|
||||
@ -784,7 +788,7 @@ NSPoint ConvertPointFromWindowToScreen(NSWindow* window, NSPoint point) {
|
||||
- (void)windowDidChangeBackingProperties:(NSNotification*)notification {
|
||||
// This delegate method is only called on 10.7 and later, so don't worry about
|
||||
// other backing changes calling it on 10.6 or earlier
|
||||
[self resetDeviceScaleFactor];
|
||||
[self resetDeviceScaleFactor:std::nullopt];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect {
|
||||
@ -1210,12 +1214,14 @@ NSPoint ConvertPointFromWindowToScreen(NSWindow* window, NSPoint point) {
|
||||
return viewPoint;
|
||||
}
|
||||
|
||||
- (void)resetDeviceScaleFactor {
|
||||
float device_scale_factor = 1.0f;
|
||||
- (void)resetDeviceScaleFactor:(std::optional<float>)requested_scale_factor {
|
||||
float device_scale_factor = requested_scale_factor.value_or(1.0f);
|
||||
if (!requested_scale_factor.has_value()) {
|
||||
NSWindow* window = [self window];
|
||||
if (window) {
|
||||
device_scale_factor = [window backingScaleFactor];
|
||||
}
|
||||
}
|
||||
[self setDeviceScaleFactor:device_scale_factor];
|
||||
}
|
||||
|
||||
@ -1225,7 +1231,7 @@ NSPoint ConvertPointFromWindowToScreen(NSWindow* window, NSPoint point) {
|
||||
}
|
||||
|
||||
// Apply some sanity checks.
|
||||
if (device_scale_factor < 1.0f || device_scale_factor > 4.0f) {
|
||||
if (device_scale_factor < 0.5f || device_scale_factor > 4.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1417,6 +1423,7 @@ class BrowserWindowOsrMacImpl {
|
||||
// The below members will only be accessed on the main thread which should be
|
||||
// the same as the CEF UI thread.
|
||||
OsrRenderer renderer_;
|
||||
std::optional<float> initial_scale_factor_;
|
||||
BrowserOpenGLView* native_browser_view_;
|
||||
bool hidden_;
|
||||
bool painting_popup_;
|
||||
@ -1542,7 +1549,7 @@ void BrowserWindowOsrMacImpl::SetBounds(int x,
|
||||
size_t width,
|
||||
size_t height) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
// Nothing to do here. GTK will take care of positioning in the container.
|
||||
// Nothing to do here. Cocoa will take care of positioning in the container.
|
||||
}
|
||||
|
||||
void BrowserWindowOsrMacImpl::SetFocus(bool focus) {
|
||||
@ -1556,6 +1563,8 @@ void BrowserWindowOsrMacImpl::SetDeviceScaleFactor(float device_scale_factor) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
if (native_browser_view_) {
|
||||
[native_browser_view_ setDeviceScaleFactor:device_scale_factor];
|
||||
} else {
|
||||
initial_scale_factor_ = device_scale_factor;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1564,7 +1573,7 @@ float BrowserWindowOsrMacImpl::GetDeviceScaleFactor() const {
|
||||
if (native_browser_view_) {
|
||||
return [native_browser_view_ getDeviceScaleFactor];
|
||||
}
|
||||
return 1.0f;
|
||||
return initial_scale_factor_.value_or(1.0f);
|
||||
}
|
||||
|
||||
ClientWindowHandle BrowserWindowOsrMacImpl::GetWindowHandle() const {
|
||||
@ -1590,14 +1599,33 @@ void BrowserWindowOsrMacImpl::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
bool BrowserWindowOsrMacImpl::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
|
||||
CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (!renderer_.settings().real_screen_bounds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!native_browser_view_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto screen_rect =
|
||||
GetWindowBoundsInScreen([native_browser_view_ window])) {
|
||||
rect = *screen_rect;
|
||||
}
|
||||
if (rect.width == 0) {
|
||||
rect.width = 1;
|
||||
}
|
||||
if (rect.height == 0) {
|
||||
rect.height = 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BrowserWindowOsrMacImpl::GetViewRect(CefRefPtr<CefBrowser> browser,
|
||||
CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
// Keep (0,0) origin for proper layout on macOS.
|
||||
rect.x = rect.y = 0;
|
||||
|
||||
if (!native_browser_view_) {
|
||||
@ -1614,12 +1642,12 @@ void BrowserWindowOsrMacImpl::GetViewRect(CefRefPtr<CefBrowser> browser,
|
||||
// Convert to device coordinates.
|
||||
bounds = [native_browser_view_ convertRectToBackingInternal:bounds];
|
||||
|
||||
// Convert to browser view coordinates.
|
||||
// Convert to DIP coordinates.
|
||||
rect.width = DeviceToLogical(bounds.size.width, device_scale_factor);
|
||||
rect.height = DeviceToLogical(bounds.size.height, device_scale_factor);
|
||||
if (rect.width == 0) {
|
||||
rect.width = 1;
|
||||
}
|
||||
rect.height = DeviceToLogical(bounds.size.height, device_scale_factor);
|
||||
if (rect.height == 0) {
|
||||
rect.height = 1;
|
||||
}
|
||||
@ -1639,7 +1667,7 @@ bool BrowserWindowOsrMacImpl::GetScreenPoint(CefRefPtr<CefBrowser> browser,
|
||||
|
||||
const float device_scale_factor = [native_browser_view_ getDeviceScaleFactor];
|
||||
|
||||
// (viewX, viewX) is in browser view coordinates.
|
||||
// (viewX, viewX) is in browser DIP coordinates.
|
||||
// Convert to device coordinates.
|
||||
NSPoint view_pt = NSMakePoint(LogicalToDevice(viewX, device_scale_factor),
|
||||
LogicalToDevice(viewY, device_scale_factor));
|
||||
@ -1670,16 +1698,24 @@ bool BrowserWindowOsrMacImpl::GetScreenInfo(CefRefPtr<CefBrowser> browser,
|
||||
return false;
|
||||
}
|
||||
|
||||
screen_info.device_scale_factor = [native_browser_view_ getDeviceScaleFactor];
|
||||
|
||||
if (renderer_.settings().real_screen_bounds) {
|
||||
CefRect root_rect;
|
||||
GetRootScreenRect(browser, root_rect);
|
||||
|
||||
auto display = CefDisplay::GetDisplayMatchingBounds(
|
||||
root_rect, /*input_pixel_coords=*/false);
|
||||
screen_info.rect = display->GetBounds();
|
||||
screen_info.available_rect = display->GetWorkArea();
|
||||
} else {
|
||||
CefRect view_rect;
|
||||
GetViewRect(browser, view_rect);
|
||||
|
||||
screen_info.device_scale_factor = [native_browser_view_ getDeviceScaleFactor];
|
||||
|
||||
// The screen info rectangles are used by the renderer to create and position
|
||||
// popups. Keep popups inside the view rectangle.
|
||||
// Keep HTML select popups inside the view rectangle.
|
||||
screen_info.rect = view_rect;
|
||||
screen_info.available_rect = view_rect;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1892,7 +1928,7 @@ void BrowserWindowOsrMacImpl::Create(ClientWindowHandle parent_handle,
|
||||
addSubview:native_browser_view_];
|
||||
|
||||
// Determine the default scale factor.
|
||||
[native_browser_view_ resetDeviceScaleFactor];
|
||||
[native_browser_view_ resetDeviceScaleFactor:initial_scale_factor_];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:native_browser_view_
|
||||
|
@ -103,7 +103,7 @@ void BrowserWindowOsrWin::SetDeviceScaleFactor(float device_scale_factor) {
|
||||
}
|
||||
|
||||
// Apply some sanity checks.
|
||||
if (device_scale_factor < 1.0f || device_scale_factor > 4.0f) {
|
||||
if (device_scale_factor < 0.5f || device_scale_factor > 4.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -571,12 +571,7 @@ ClientHandler::ClientHandler(Delegate* delegate,
|
||||
}
|
||||
|
||||
void ClientHandler::DetachDelegate() {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
// Execute this method on the main thread.
|
||||
MAIN_POST_CLOSURE(base::BindOnce(&ClientHandler::DetachDelegate, this));
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE_MAIN_THREAD();
|
||||
DCHECK(delegate_);
|
||||
delegate_ = nullptr;
|
||||
}
|
||||
@ -869,6 +864,24 @@ bool ClientHandler::OnCursorChange(CefRefPtr<CefBrowser> browser,
|
||||
return mouse_cursor_change_disabled_;
|
||||
}
|
||||
|
||||
#if CEF_API_ADDED(CEF_NEXT)
|
||||
bool ClientHandler::OnContentsBoundsChange(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& new_bounds) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
NotifyContentsBounds(new_bounds);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientHandler::GetRootWindowScreenRect(CefRefPtr<CefBrowser> browser,
|
||||
CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (delegate_) {
|
||||
return delegate_->GetRootWindowScreenRect(rect);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ClientHandler::CanDownload(CefRefPtr<CefBrowser> browser,
|
||||
const CefString& url,
|
||||
const CefString& request_method) {
|
||||
@ -1465,6 +1478,19 @@ void ClientHandler::NotifyAutoResize(const CefSize& new_size) {
|
||||
}
|
||||
}
|
||||
|
||||
void ClientHandler::NotifyContentsBounds(const CefRect& new_bounds) {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
// Execute this method on the main thread.
|
||||
MAIN_POST_CLOSURE(
|
||||
base::BindOnce(&ClientHandler::NotifyContentsBounds, this, new_bounds));
|
||||
return;
|
||||
}
|
||||
|
||||
if (delegate_) {
|
||||
delegate_->OnContentsBounds(new_bounds);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientHandler::NotifyLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) {
|
||||
|
@ -71,6 +71,9 @@ class ClientHandler : public BaseClientHandler,
|
||||
// Auto-resize contents.
|
||||
virtual void OnAutoResize(const CefSize& new_size) = 0;
|
||||
|
||||
// Set contents bounds.
|
||||
virtual void OnContentsBounds(const CefRect& new_bounds) = 0;
|
||||
|
||||
// Set the loading state.
|
||||
virtual void OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
@ -89,6 +92,9 @@ class ClientHandler : public BaseClientHandler,
|
||||
// Called on the UI thread before a context menu is displayed.
|
||||
virtual void OnBeforeContextMenu(CefRefPtr<CefMenuModel> model) {}
|
||||
|
||||
// Called on the UI thread to retrieve root window bounds.
|
||||
virtual bool GetRootWindowScreenRect(CefRect& rect) { return false; }
|
||||
|
||||
protected:
|
||||
virtual ~Delegate() = default;
|
||||
};
|
||||
@ -101,7 +107,8 @@ class ClientHandler : public BaseClientHandler,
|
||||
const std::string& startup_url);
|
||||
|
||||
// This object may outlive the Delegate object so it's necessary for the
|
||||
// Delegate to detach itself before destruction.
|
||||
// Delegate to detach itself before destruction. Called on the main thread
|
||||
// after the browser has closed.
|
||||
void DetachDelegate();
|
||||
|
||||
// CefClient methods
|
||||
@ -176,6 +183,12 @@ class ClientHandler : public BaseClientHandler,
|
||||
CefCursorHandle cursor,
|
||||
cef_cursor_type_t type,
|
||||
const CefCursorInfo& custom_cursor_info) override;
|
||||
#if CEF_API_ADDED(CEF_NEXT)
|
||||
bool OnContentsBoundsChange(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& new_bounds) override;
|
||||
bool GetRootWindowScreenRect(CefRefPtr<CefBrowser> browser,
|
||||
CefRect& rect) override;
|
||||
#endif
|
||||
|
||||
// CefDownloadHandler methods
|
||||
bool CanDownload(CefRefPtr<CefBrowser> browser,
|
||||
@ -345,6 +358,7 @@ class ClientHandler : public BaseClientHandler,
|
||||
void NotifyFavicon(CefRefPtr<CefImage> image);
|
||||
void NotifyFullscreen(bool fullscreen);
|
||||
void NotifyAutoResize(const CefSize& new_size);
|
||||
void NotifyContentsBounds(const CefRect& new_bounds);
|
||||
void NotifyLoadingState(bool isLoading, bool canGoBack, bool canGoForward);
|
||||
void NotifyDraggableRegions(const std::vector<CefDraggableRegion>& regions);
|
||||
void NotifyTakeFocus(bool next);
|
||||
@ -396,11 +410,7 @@ class ClientHandler : public BaseClientHandler,
|
||||
CefRefPtr<ClientPrintHandlerGtk> print_handler_;
|
||||
#endif
|
||||
|
||||
// MAIN THREAD MEMBERS
|
||||
// The following members will only be accessed on the main thread. This will
|
||||
// be the same as the CEF UI thread except when using multi-threaded message
|
||||
// loop mode on Windows.
|
||||
|
||||
// Safe to access from any thread during browser lifetime.
|
||||
Delegate* delegate_;
|
||||
|
||||
// UI THREAD MEMBERS
|
||||
|
@ -239,6 +239,8 @@ void MainContextImpl::PopulateBrowserSettings(CefBrowserSettings* settings) {
|
||||
void MainContextImpl::PopulateOsrSettings(OsrRendererSettings* settings) {
|
||||
settings->show_update_rect =
|
||||
command_line_->HasSwitch(switches::kShowUpdateRect);
|
||||
settings->real_screen_bounds =
|
||||
!command_line_->HasSwitch(switches::kFakeScreenBounds);
|
||||
|
||||
settings->shared_texture_enabled = shared_texture_enabled_;
|
||||
settings->external_begin_frame_enabled = external_begin_frame_enabled_;
|
||||
|
@ -16,6 +16,14 @@ struct OsrRendererSettings {
|
||||
// If true draw a border around update rectangles.
|
||||
bool show_update_rect = false;
|
||||
|
||||
// If true return real screen bounds from GetRootScreenRect/GetScreenInfo.
|
||||
// - Allows window.outerWidth/Height and window.screenX/Y to return correct
|
||||
// values.
|
||||
// - Allows JavaScript window.moveTo/By() and window.resizeTo/By() to provide
|
||||
// bounds that include the window frame.
|
||||
// - Causes HTML select popups to be cropped (limitation of cefclient impl).
|
||||
bool real_screen_bounds = true;
|
||||
|
||||
// Background color. Enables transparency if the alpha component is 0.
|
||||
cef_color_t background_color = 0;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "include/base/cef_build.h"
|
||||
#include "include/views/cef_display.h"
|
||||
#include "tests/cefclient/browser/main_context.h"
|
||||
#include "tests/cefclient/browser/osr_accessibility_helper.h"
|
||||
#include "tests/cefclient/browser/osr_accessibility_node.h"
|
||||
@ -30,20 +31,6 @@ namespace {
|
||||
|
||||
const wchar_t kWndClass[] = L"Client_OsrWindow";
|
||||
|
||||
// Helper funtion to check if it is Windows8 or greater.
|
||||
// https://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx
|
||||
inline BOOL IsWindows_8_Or_Newer() {
|
||||
OSVERSIONINFOEX osvi = {0};
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||
osvi.dwMajorVersion = 6;
|
||||
osvi.dwMinorVersion = 2;
|
||||
DWORDLONG dwlConditionMask = 0;
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
|
||||
return ::VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION,
|
||||
dwlConditionMask);
|
||||
}
|
||||
|
||||
// Helper function to detect mouse messages coming from emulation of touch
|
||||
// events. These should be ignored.
|
||||
bool IsMouseEventFromTouch(UINT message) {
|
||||
@ -92,7 +79,7 @@ OsrWindowWin::OsrWindowWin(Delegate* delegate,
|
||||
last_mouse_pos_(),
|
||||
current_mouse_pos_() {
|
||||
DCHECK(delegate_);
|
||||
client_rect_ = {0};
|
||||
client_rect_ = {};
|
||||
}
|
||||
|
||||
OsrWindowWin::~OsrWindowWin() {
|
||||
@ -870,17 +857,6 @@ bool OsrWindowWin::OnTouchEvent(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
point.x = TOUCH_COORD_TO_PIXEL(input[i].x);
|
||||
point.y = TOUCH_COORD_TO_PIXEL(input[i].y);
|
||||
|
||||
if (!IsWindows_8_Or_Newer()) {
|
||||
// Windows 7 sends touch events for touches in the non-client area,
|
||||
// whereas Windows 8 does not. In order to unify the behaviour, always
|
||||
// ignore touch events in the non-client area.
|
||||
LPARAM l_param_ht = MAKELPARAM(point.x, point.y);
|
||||
LRESULT hittest = SendMessage(hwnd_, WM_NCHITTEST, 0, l_param_ht);
|
||||
if (hittest != HTCLIENT) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ScreenToClient(hwnd_, &point);
|
||||
touch_event.x = DeviceToLogical(point.x, device_scale_factor_);
|
||||
touch_event.y = DeviceToLogical(point.y, device_scale_factor_);
|
||||
@ -969,24 +945,52 @@ void OsrWindowWin::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
bool OsrWindowWin::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
|
||||
CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
DCHECK_GT(device_scale_factor_, 0);
|
||||
|
||||
if (!settings_.real_screen_bounds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HWND root_hwnd = ::GetAncestor(hwnd_, GA_ROOT);
|
||||
DCHECK(root_hwnd);
|
||||
RECT root_rect = {};
|
||||
::GetWindowRect(root_hwnd, &root_rect);
|
||||
|
||||
// Convert to DIP coordinates.
|
||||
rect = DeviceToLogical(
|
||||
{root_rect.left, root_rect.top, root_rect.right - root_rect.left,
|
||||
root_rect.bottom - root_rect.top},
|
||||
device_scale_factor_);
|
||||
if (rect.width == 0) {
|
||||
rect.width = 1;
|
||||
}
|
||||
if (rect.height == 0) {
|
||||
rect.height = 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void OsrWindowWin::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
DCHECK_GT(device_scale_factor_, 0);
|
||||
|
||||
rect.x = rect.y = 0;
|
||||
rect.width = DeviceToLogical(client_rect_.right - client_rect_.left,
|
||||
RECT window_rect = {};
|
||||
::GetWindowRect(hwnd_, &window_rect);
|
||||
|
||||
// Convert to DIP coordinates.
|
||||
rect = DeviceToLogical(
|
||||
{window_rect.left, window_rect.top, window_rect.right - window_rect.left,
|
||||
window_rect.bottom - window_rect.top},
|
||||
device_scale_factor_);
|
||||
if (rect.width == 0) {
|
||||
rect.width = 1;
|
||||
}
|
||||
rect.height = DeviceToLogical(client_rect_.bottom - client_rect_.top,
|
||||
device_scale_factor_);
|
||||
if (rect.height == 0) {
|
||||
rect.height = 1;
|
||||
}
|
||||
if (!settings_.real_screen_bounds) {
|
||||
rect.x = rect.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool OsrWindowWin::GetScreenPoint(CefRefPtr<CefBrowser> browser,
|
||||
@ -1019,15 +1023,24 @@ bool OsrWindowWin::GetScreenInfo(CefRefPtr<CefBrowser> browser,
|
||||
return false;
|
||||
}
|
||||
|
||||
screen_info.device_scale_factor = device_scale_factor_;
|
||||
|
||||
if (settings_.real_screen_bounds) {
|
||||
CefRect root_rect;
|
||||
GetRootScreenRect(browser, root_rect);
|
||||
|
||||
auto display = CefDisplay::GetDisplayMatchingBounds(
|
||||
root_rect, /*input_pixel_coords=*/false);
|
||||
screen_info.rect = display->GetBounds();
|
||||
screen_info.available_rect = display->GetWorkArea();
|
||||
} else {
|
||||
CefRect view_rect;
|
||||
GetViewRect(browser, view_rect);
|
||||
|
||||
screen_info.device_scale_factor = device_scale_factor_;
|
||||
|
||||
// The screen info rectangles are used by the renderer to create and position
|
||||
// popups. Keep popups inside the view rectangle.
|
||||
// Keep HTML select popups inside the view rectangle.
|
||||
screen_info.rect = view_rect;
|
||||
screen_info.available_rect = view_rect;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
@ -185,8 +186,23 @@ class RootWindow
|
||||
// Hide the window.
|
||||
virtual void Hide() = 0;
|
||||
|
||||
// Set the window bounds in screen coordinates.
|
||||
virtual void SetBounds(int x, int y, size_t width, size_t height) = 0;
|
||||
// Set bounds in DIP screen coordinates. If |content_bounds| is true then the
|
||||
// specified bounds are for the browser's content area and will be expanded to
|
||||
// appropriate containing window bounds. Otherwise, the specified bounds are
|
||||
// for the containing window directly. Bounds will be constrained to the
|
||||
// containing display work area. Specific behavioral expectations depend on
|
||||
// platform and run mode. See the https://tests/window example for details.
|
||||
virtual void SetBounds(int x,
|
||||
int y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
bool content_bounds) = 0;
|
||||
void SetBounds(const CefRect& bounds, bool content_bounds) {
|
||||
SetBounds(bounds.x, bounds.y, bounds.width, bounds.height, content_bounds);
|
||||
}
|
||||
|
||||
// Returns true if this RootWindow should default to sizing by content bounds.
|
||||
virtual bool DefaultToContentBounds() const = 0;
|
||||
|
||||
// Close the window. If |force| is true onunload handlers will not be
|
||||
// executed.
|
||||
@ -198,7 +214,7 @@ class RootWindow
|
||||
|
||||
// Returns the device scale factor. Only used in combination with off-screen
|
||||
// rendering.
|
||||
virtual float GetDeviceScaleFactor() const = 0;
|
||||
virtual std::optional<float> GetDeviceScaleFactor() const = 0;
|
||||
|
||||
// Returns the browser that this window contains, if any.
|
||||
virtual CefRefPtr<CefBrowser> GetBrowser() const = 0;
|
||||
|
@ -14,11 +14,14 @@
|
||||
#include "include/cef_app.h"
|
||||
#include "tests/cefclient/browser/browser_window_osr_gtk.h"
|
||||
#include "tests/cefclient/browser/browser_window_std_gtk.h"
|
||||
#include "tests/cefclient/browser/client_prefs.h"
|
||||
#include "tests/cefclient/browser/main_context.h"
|
||||
#include "tests/cefclient/browser/resource.h"
|
||||
#include "tests/cefclient/browser/root_window_manager.h"
|
||||
#include "tests/cefclient/browser/temp_window.h"
|
||||
#include "tests/cefclient/browser/util_gtk.h"
|
||||
#include "tests/cefclient/browser/window_test_runner_gtk.h"
|
||||
#include "tests/shared/browser/geometry_util.h"
|
||||
#include "tests/shared/browser/main_message_loop.h"
|
||||
#include "tests/shared/common/client_switches.h"
|
||||
|
||||
@ -59,23 +62,139 @@ void UseDefaultX11VisualForGtk(GtkWidget* widget) {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsWindowMaximized(GtkWindow* window) {
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
|
||||
gint state = gdk_window_get_state(gdk_window);
|
||||
return (state & GDK_WINDOW_STATE_MAXIMIZED) ? true : false;
|
||||
// Keep the bounds inside the closest display work area.
|
||||
CefRect ClampBoundsToDisplay(const CefRect& pixel_bounds) {
|
||||
auto display = CefDisplay::GetDisplayMatchingBounds(
|
||||
pixel_bounds, /*input_pixel_coords=*/true);
|
||||
CefRect work_area =
|
||||
LogicalToDevice(display->GetWorkArea(), display->GetDeviceScaleFactor());
|
||||
|
||||
CefRect bounds = pixel_bounds;
|
||||
ConstrainWindowBounds(work_area, bounds);
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
void MinimizeWindow(GtkWindow* window) {
|
||||
// Unmaximize the window before minimizing so restore behaves correctly.
|
||||
if (IsWindowMaximized(window)) {
|
||||
gtk_window_unmaximize(window);
|
||||
float GetScaleFactor(const CefRect& bounds,
|
||||
const std::optional<float>& device_scale_factor,
|
||||
bool pixel_bounds) {
|
||||
if (device_scale_factor.has_value()) {
|
||||
return *device_scale_factor;
|
||||
}
|
||||
auto display = CefDisplay::GetDisplayMatchingBounds(
|
||||
bounds, /*input_pixel_coords=*/pixel_bounds);
|
||||
return display->GetDeviceScaleFactor();
|
||||
}
|
||||
|
||||
gtk_window_iconify(window);
|
||||
CefRect GetScreenPixelBounds(const CefRect& dip_bounds,
|
||||
const std::optional<float>& device_scale_factor) {
|
||||
const auto scale_factor =
|
||||
GetScaleFactor(dip_bounds, device_scale_factor, /*pixel_bounds=*/false);
|
||||
return LogicalToDevice(dip_bounds, scale_factor);
|
||||
}
|
||||
|
||||
void MaximizeWindow(GtkWindow* window) {
|
||||
gtk_window_maximize(window);
|
||||
CefRect GetScreenDIPBounds(const CefRect& pixel_bounds,
|
||||
const std::optional<float>& device_scale_factor) {
|
||||
const auto scale_factor =
|
||||
GetScaleFactor(pixel_bounds, device_scale_factor, /*pixel_bounds=*/true);
|
||||
return DeviceToLogical(pixel_bounds, scale_factor);
|
||||
}
|
||||
|
||||
// Existing window measurements in root window (pixel) coordinates.
|
||||
struct BoundsInfo {
|
||||
CefRect frame;
|
||||
CefRect window;
|
||||
CefRect browser;
|
||||
};
|
||||
|
||||
// |content_bounds| is the browser content area bounds in DIP screen
|
||||
// coordinates. Convert to root window (pixel) coordinates and then expand to
|
||||
// frame bounds. Keep the resulting bounds inside the closest display work area.
|
||||
// |device_scale_factor| will be specified with off-screen rendering.
|
||||
CefRect GetFrameBoundsInDisplay(
|
||||
const CefRect& content_bounds,
|
||||
const BoundsInfo& bounds_info,
|
||||
const std::optional<float>& device_scale_factor) {
|
||||
CefRect pixel_bounds =
|
||||
GetScreenPixelBounds(content_bounds, device_scale_factor);
|
||||
|
||||
// Expand the new bounds based on relative offsets for the current bounds.
|
||||
// - Position includes the frame.
|
||||
pixel_bounds.x -=
|
||||
bounds_info.window.x + bounds_info.browser.x - bounds_info.frame.x;
|
||||
pixel_bounds.y -=
|
||||
bounds_info.window.y + bounds_info.browser.y - bounds_info.frame.y;
|
||||
// - Size does not include the frame.
|
||||
pixel_bounds.width += bounds_info.window.width - bounds_info.browser.width;
|
||||
pixel_bounds.height += bounds_info.window.height - bounds_info.browser.height;
|
||||
|
||||
return ClampBoundsToDisplay(pixel_bounds);
|
||||
}
|
||||
|
||||
// Execute calls on the required threads.
|
||||
void GetPixelBoundsAndContinue(const CefRect& dip_bounds,
|
||||
const std::optional<BoundsInfo>& bounds_info,
|
||||
const std::optional<float>& device_scale_factor,
|
||||
base::OnceCallback<void(const CefRect&)> next) {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, base::BindOnce(&GetPixelBoundsAndContinue, dip_bounds,
|
||||
bounds_info, device_scale_factor,
|
||||
std::move(next)));
|
||||
return;
|
||||
}
|
||||
|
||||
CefRect pixel_bounds;
|
||||
if (bounds_info.has_value()) {
|
||||
pixel_bounds =
|
||||
GetFrameBoundsInDisplay(dip_bounds, *bounds_info, device_scale_factor);
|
||||
} else {
|
||||
pixel_bounds = ClampBoundsToDisplay(
|
||||
GetScreenPixelBounds(dip_bounds, device_scale_factor));
|
||||
}
|
||||
|
||||
if (CURRENTLY_ON_MAIN_THREAD()) {
|
||||
std::move(next).Run(pixel_bounds);
|
||||
} else {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(std::move(next), pixel_bounds));
|
||||
}
|
||||
}
|
||||
|
||||
void SaveWindowRestoreContinue(
|
||||
cef_show_state_t show_state,
|
||||
const CefRect& pixel_bounds,
|
||||
const std::optional<float>& device_scale_factor) {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, base::BindOnce(&SaveWindowRestoreContinue, show_state,
|
||||
pixel_bounds, device_scale_factor));
|
||||
return;
|
||||
}
|
||||
|
||||
CefRect dip_bounds;
|
||||
if (show_state == CEF_SHOW_STATE_NORMAL) {
|
||||
dip_bounds = GetScreenDIPBounds(pixel_bounds, device_scale_factor);
|
||||
}
|
||||
|
||||
prefs::SaveWindowRestorePreferences(show_state, dip_bounds);
|
||||
}
|
||||
|
||||
void SaveWindowRestore(GtkWidget* widget,
|
||||
const std::optional<float>& device_scale_factor) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
GtkWindow* window = GTK_WINDOW(widget);
|
||||
|
||||
cef_show_state_t show_state = CEF_SHOW_STATE_NORMAL;
|
||||
CefRect pixel_bounds;
|
||||
|
||||
if (!gtk_widget_get_visible(widget)) {
|
||||
show_state = CEF_SHOW_STATE_MINIMIZED;
|
||||
} else if (IsWindowMaximized(window)) {
|
||||
show_state = CEF_SHOW_STATE_MAXIMIZED;
|
||||
} else {
|
||||
pixel_bounds = GetWindowBounds(window, /*include_frame=*/true);
|
||||
}
|
||||
|
||||
SaveWindowRestoreContinue(show_state, pixel_bounds, device_scale_factor);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -117,10 +236,54 @@ void RootWindowGtk::Init(RootWindow::Delegate* delegate,
|
||||
with_controls_ = config->with_controls;
|
||||
always_on_top_ = config->always_on_top;
|
||||
with_osr_ = config->with_osr;
|
||||
start_rect_ = config->bounds;
|
||||
|
||||
CreateBrowserWindow(config->url);
|
||||
|
||||
if (CefCurrentlyOn(TID_UI)) {
|
||||
ContinueInitOnUIThread(std::move(config), settings);
|
||||
} else {
|
||||
CefPostTask(TID_UI, base::BindOnce(&RootWindowGtk::ContinueInitOnUIThread,
|
||||
this, std::move(config), settings));
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowGtk::ContinueInitOnUIThread(
|
||||
std::unique_ptr<RootWindowConfig> config,
|
||||
const CefBrowserSettings& settings) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (!config->bounds.IsEmpty()) {
|
||||
// Initial state was specified via the config object.
|
||||
start_rect_ = config->bounds;
|
||||
initial_show_state_ = config->show_state;
|
||||
} else {
|
||||
// Initial state may be specified via the command-line or global
|
||||
// preferences.
|
||||
std::optional<CefRect> bounds;
|
||||
if (prefs::LoadWindowRestorePreferences(initial_show_state_, bounds) &&
|
||||
bounds) {
|
||||
start_rect_ = GetScreenPixelBounds(*bounds, std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
if (with_osr_) {
|
||||
initial_scale_factor_ =
|
||||
GetScaleFactor(start_rect_, std::nullopt, /*pixel_bounds=*/true);
|
||||
}
|
||||
|
||||
if (CURRENTLY_ON_MAIN_THREAD()) {
|
||||
ContinueInitOnMainThread(std::move(config), settings);
|
||||
} else {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::ContinueInitOnMainThread,
|
||||
this, std::move(config), settings));
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowGtk::ContinueInitOnMainThread(
|
||||
std::unique_ptr<RootWindowConfig> config,
|
||||
const CefBrowserSettings& settings) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
initialized_ = true;
|
||||
|
||||
// Always post asynchronously to avoid reentrancy of the GDK lock.
|
||||
@ -135,6 +298,8 @@ void RootWindowGtk::InitAsPopup(RootWindow::Delegate* delegate,
|
||||
CefWindowInfo& windowInfo,
|
||||
CefRefPtr<CefClient>& client,
|
||||
CefBrowserSettings& settings) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
DCHECK(delegate);
|
||||
DCHECK(!initialized_);
|
||||
|
||||
@ -143,6 +308,7 @@ void RootWindowGtk::InitAsPopup(RootWindow::Delegate* delegate,
|
||||
with_osr_ = with_osr;
|
||||
is_popup_ = true;
|
||||
|
||||
// NOTE: This will be the size for the whole window including frame.
|
||||
if (popupFeatures.xSet) {
|
||||
start_rect_.x = popupFeatures.x;
|
||||
}
|
||||
@ -155,6 +321,13 @@ void RootWindowGtk::InitAsPopup(RootWindow::Delegate* delegate,
|
||||
if (popupFeatures.heightSet) {
|
||||
start_rect_.height = popupFeatures.height;
|
||||
}
|
||||
start_rect_ =
|
||||
ClampBoundsToDisplay(GetScreenPixelBounds(start_rect_, std::nullopt));
|
||||
|
||||
if (with_osr_) {
|
||||
initial_scale_factor_ =
|
||||
GetScaleFactor(start_rect_, std::nullopt, /*pixel_bounds=*/true);
|
||||
}
|
||||
|
||||
CreateBrowserWindow(std::string());
|
||||
|
||||
@ -203,26 +376,74 @@ void RootWindowGtk::Hide() {
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowGtk::SetBounds(int x, int y, size_t width, size_t height) {
|
||||
void RootWindowGtk::SetBounds(int x,
|
||||
int y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
bool content_bounds) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
if (!window_) {
|
||||
return;
|
||||
}
|
||||
|
||||
CefRect dip_bounds{x, y, static_cast<int>(width), static_cast<int>(height)};
|
||||
|
||||
GetWindowBoundsAndContinue(
|
||||
dip_bounds, content_bounds,
|
||||
base::BindOnce(
|
||||
[](GtkWidget* window, const CefRect& pixel_bounds) {
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(window);
|
||||
gdk_window_move_resize(gdk_window, pixel_bounds.x, pixel_bounds.y,
|
||||
pixel_bounds.width, pixel_bounds.height);
|
||||
},
|
||||
base::Unretained(window_)));
|
||||
}
|
||||
|
||||
bool RootWindowGtk::DefaultToContentBounds() const {
|
||||
if (!WithWindowlessRendering()) {
|
||||
// Root GtkWindow bounds are provided via GetRootWindowScreenRect.
|
||||
return false;
|
||||
}
|
||||
if (osr_settings_.real_screen_bounds) {
|
||||
// Root GtkWindow bounds are provided via GetRootScreenRect.
|
||||
return false;
|
||||
}
|
||||
// The root GtkWindow will not be queried by default.
|
||||
return true;
|
||||
}
|
||||
|
||||
void RootWindowGtk::GetWindowBoundsAndContinue(
|
||||
const CefRect& dip_bounds,
|
||||
bool content_bounds,
|
||||
base::OnceCallback<void(const CefRect& /*pixel_bounds*/)> next) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
DCHECK(window_);
|
||||
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
|
||||
GtkWindow* window = GTK_WINDOW(window_);
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(window_);
|
||||
|
||||
// Make sure the window isn't minimized or maximized.
|
||||
if (IsWindowMaximized(window)) {
|
||||
gtk_window_unmaximize(window);
|
||||
} else {
|
||||
gtk_window_present(window);
|
||||
// Make sure the window isn't minimized or maximized. It must also be
|
||||
// presented before we can retrieve bounds information.
|
||||
RestoreWindow(window);
|
||||
|
||||
std::optional<BoundsInfo> bounds_info;
|
||||
|
||||
if (content_bounds) {
|
||||
// Existing measurements in root window (pixel) coordinates.
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(window_);
|
||||
GdkRectangle frame_rect = {};
|
||||
gdk_window_get_frame_extents(gdk_window, &frame_rect);
|
||||
bounds_info = {
|
||||
{frame_rect.x, frame_rect.y, frame_rect.width, frame_rect.height},
|
||||
GetWindowBounds(window, /*include_frame=*/false),
|
||||
browser_bounds_};
|
||||
}
|
||||
|
||||
gdk_window_move_resize(gdk_window, x, y, width, height);
|
||||
GetPixelBoundsAndContinue(dip_bounds, bounds_info, GetDeviceScaleFactor(),
|
||||
std::move(next));
|
||||
}
|
||||
|
||||
void RootWindowGtk::Close(bool force) {
|
||||
@ -246,15 +467,14 @@ void RootWindowGtk::SetDeviceScaleFactor(float device_scale_factor) {
|
||||
}
|
||||
}
|
||||
|
||||
float RootWindowGtk::GetDeviceScaleFactor() const {
|
||||
std::optional<float> RootWindowGtk::GetDeviceScaleFactor() const {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
if (browser_window_ && with_osr_) {
|
||||
return browser_window_->GetDeviceScaleFactor();
|
||||
}
|
||||
|
||||
NOTREACHED();
|
||||
return 0.0f;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowser> RootWindowGtk::GetBrowser() const {
|
||||
@ -273,15 +493,15 @@ ClientWindowHandle RootWindowGtk::GetWindowHandle() const {
|
||||
|
||||
bool RootWindowGtk::WithWindowlessRendering() const {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
DCHECK(initialized_);
|
||||
return with_osr_;
|
||||
}
|
||||
|
||||
void RootWindowGtk::CreateBrowserWindow(const std::string& startup_url) {
|
||||
if (with_osr_) {
|
||||
OsrRendererSettings settings = {};
|
||||
MainContext::Get()->PopulateOsrSettings(&settings);
|
||||
browser_window_.reset(
|
||||
new BrowserWindowOsrGtk(this, with_controls_, startup_url, settings));
|
||||
MainContext::Get()->PopulateOsrSettings(&osr_settings_);
|
||||
browser_window_.reset(new BrowserWindowOsrGtk(this, with_controls_,
|
||||
startup_url, osr_settings_));
|
||||
} else {
|
||||
browser_window_.reset(
|
||||
new BrowserWindowStdGtk(this, with_controls_, startup_url));
|
||||
@ -329,7 +549,7 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
|
||||
G_CALLBACK(&RootWindowGtk::WindowDelete), this);
|
||||
|
||||
const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
|
||||
GdkRGBA rgba = {0};
|
||||
GdkRGBA rgba = {};
|
||||
rgba.red = CefColorGetR(background_color) * 65535 / 255;
|
||||
rgba.green = CefColorGetG(background_color) * 65535 / 255;
|
||||
rgba.blue = CefColorGetB(background_color) * 65535 / 255;
|
||||
@ -432,6 +652,20 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
|
||||
->set_xdisplay(xdisplay);
|
||||
}
|
||||
|
||||
if (with_osr_) {
|
||||
std::optional<float> parent_scale_factor;
|
||||
if (is_popup_) {
|
||||
if (auto parent_window =
|
||||
MainContext::Get()->GetRootWindowManager()->GetWindowForBrowser(
|
||||
opener_browser_id())) {
|
||||
parent_scale_factor = parent_window->GetDeviceScaleFactor();
|
||||
}
|
||||
}
|
||||
|
||||
browser_window_->SetDeviceScaleFactor(
|
||||
parent_scale_factor.value_or(initial_scale_factor_));
|
||||
}
|
||||
|
||||
if (!is_popup_) {
|
||||
// Create the browser window.
|
||||
browser_window_->CreateBrowser(parent, browser_bounds_, settings, nullptr,
|
||||
@ -525,19 +759,18 @@ void RootWindowGtk::OnAutoResize(const CefSize& new_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
CefRect dip_bounds{0, 0, new_size.width, new_size.height};
|
||||
|
||||
GetWindowBoundsAndContinue(
|
||||
dip_bounds, /*content_bounds=*/true,
|
||||
base::BindOnce(
|
||||
[](GtkWidget* window, const CefRect& pixel_bounds) {
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
|
||||
GtkWindow* window = GTK_WINDOW(window_);
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(window_);
|
||||
|
||||
// Make sure the window isn't minimized or maximized.
|
||||
if (IsWindowMaximized(window)) {
|
||||
gtk_window_unmaximize(window);
|
||||
} else {
|
||||
gtk_window_present(window);
|
||||
}
|
||||
|
||||
gdk_window_resize(gdk_window, new_size.width, new_size.height);
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(window);
|
||||
gdk_window_resize(gdk_window, pixel_bounds.width,
|
||||
pixel_bounds.height);
|
||||
},
|
||||
base::Unretained(window_)));
|
||||
}
|
||||
|
||||
void RootWindowGtk::OnSetLoadingState(bool isLoading,
|
||||
@ -561,29 +794,46 @@ void RootWindowGtk::OnSetDraggableRegions(
|
||||
// TODO(cef): Implement support for draggable regions on this platform.
|
||||
}
|
||||
|
||||
void RootWindowGtk::NotifyMoveOrResizeStarted() {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
MAIN_POST_CLOSURE(
|
||||
base::BindOnce(&RootWindowGtk::NotifyMoveOrResizeStarted, this));
|
||||
return;
|
||||
bool RootWindowGtk::GetRootWindowScreenRect(CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (!window_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
GtkWindow* window = GTK_WINDOW(window_);
|
||||
CefRect pixel_bounds = GetWindowBounds(window, /*include_frame=*/true);
|
||||
rect = GetScreenDIPBounds(pixel_bounds, std::nullopt);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RootWindowGtk::NotifyMoveOrResizeStarted() {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
// Called when size, position or stack order changes.
|
||||
CefRefPtr<CefBrowser> browser = GetBrowser();
|
||||
if (browser.get()) {
|
||||
if (auto browser = GetBrowser()) {
|
||||
// Notify the browser of move/resize events so that:
|
||||
// - Popup windows are displayed in the correct location and dismissed
|
||||
// when the window moves.
|
||||
// - Drag&drop areas are updated accordingly.
|
||||
browser->GetHost()->NotifyMoveOrResizeStarted();
|
||||
}
|
||||
|
||||
MaybeNotifyScreenInfoChanged();
|
||||
}
|
||||
|
||||
void RootWindowGtk::MaybeNotifyScreenInfoChanged() {
|
||||
if (!DefaultToContentBounds()) {
|
||||
// Send the new root window bounds to the renderer.
|
||||
if (auto browser = GetBrowser()) {
|
||||
browser->GetHost()->NotifyScreenInfoChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowGtk::NotifySetFocus() {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::NotifySetFocus, this));
|
||||
return;
|
||||
}
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
if (!browser_window_.get()) {
|
||||
return;
|
||||
@ -594,11 +844,7 @@ void RootWindowGtk::NotifySetFocus() {
|
||||
}
|
||||
|
||||
void RootWindowGtk::NotifyVisibilityChange(bool show) {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
MAIN_POST_CLOSURE(
|
||||
base::BindOnce(&RootWindowGtk::NotifyVisibilityChange, this, show));
|
||||
return;
|
||||
}
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
if (!browser_window_.get()) {
|
||||
return;
|
||||
@ -646,10 +892,7 @@ void RootWindowGtk::NotifyContentBounds(int x, int y, int width, int height) {
|
||||
}
|
||||
|
||||
void RootWindowGtk::NotifyLoadURL(const std::string& url) {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::NotifyLoadURL, this, url));
|
||||
return;
|
||||
}
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
CefRefPtr<CefBrowser> browser = GetBrowser();
|
||||
if (browser.get()) {
|
||||
@ -658,11 +901,7 @@ void RootWindowGtk::NotifyLoadURL(const std::string& url) {
|
||||
}
|
||||
|
||||
void RootWindowGtk::NotifyButtonClicked(int id) {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
MAIN_POST_CLOSURE(
|
||||
base::BindOnce(&RootWindowGtk::NotifyButtonClicked, this, id));
|
||||
return;
|
||||
}
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
CefRefPtr<CefBrowser> browser = GetBrowser();
|
||||
if (!browser.get()) {
|
||||
@ -688,10 +927,7 @@ void RootWindowGtk::NotifyButtonClicked(int id) {
|
||||
}
|
||||
|
||||
void RootWindowGtk::NotifyMenuItem(int id) {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::NotifyMenuItem, this, id));
|
||||
return;
|
||||
}
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
// Run the test.
|
||||
if (delegate_) {
|
||||
@ -700,19 +936,13 @@ void RootWindowGtk::NotifyMenuItem(int id) {
|
||||
}
|
||||
|
||||
void RootWindowGtk::NotifyForceClose() {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, base::BindOnce(&RootWindowGtk::NotifyForceClose, this));
|
||||
return;
|
||||
}
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
force_close_ = true;
|
||||
}
|
||||
|
||||
void RootWindowGtk::NotifyCloseBrowser() {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::NotifyCloseBrowser, this));
|
||||
return;
|
||||
}
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
CefRefPtr<CefBrowser> browser = GetBrowser();
|
||||
if (browser) {
|
||||
@ -798,15 +1028,18 @@ gboolean RootWindowGtk::WindowDelete(GtkWidget* widget,
|
||||
RootWindowGtk* self) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
SaveWindowRestore(widget, self->GetDeviceScaleFactor());
|
||||
|
||||
// Called to query whether the root window should be closed.
|
||||
if (self->force_close_) {
|
||||
return FALSE; // Allow the close.
|
||||
}
|
||||
|
||||
if (!self->is_closing_) {
|
||||
// Notify the browser window that we would like to close it. This
|
||||
// will result in a call to ClientHandler::DoClose() if the
|
||||
// JavaScript 'onbeforeunload' event handler allows it.
|
||||
// Notify the browser window that we would like to close it. With Alloy
|
||||
// style this will result in a call to ClientHandler::DoClose() if the
|
||||
// JavaScript 'onbeforeunload' event handler allows it. With Chrome style
|
||||
// this will close the window indirectly via browser destruction.
|
||||
self->NotifyCloseBrowser();
|
||||
|
||||
// Cancel the close.
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "tests/cefclient/browser/browser_window.h"
|
||||
#include "tests/cefclient/browser/osr_renderer_settings.h"
|
||||
#include "tests/cefclient/browser/root_window.h"
|
||||
|
||||
namespace client {
|
||||
@ -38,15 +39,25 @@ class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate {
|
||||
CefBrowserSettings& settings) override;
|
||||
void Show(ShowMode mode) override;
|
||||
void Hide() override;
|
||||
void SetBounds(int x, int y, size_t width, size_t height) override;
|
||||
void SetBounds(int x,
|
||||
int y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
bool content_bounds) override;
|
||||
bool DefaultToContentBounds() const override;
|
||||
void Close(bool force) override;
|
||||
void SetDeviceScaleFactor(float device_scale_factor) override;
|
||||
float GetDeviceScaleFactor() const override;
|
||||
std::optional<float> GetDeviceScaleFactor() const override;
|
||||
CefRefPtr<CefBrowser> GetBrowser() const override;
|
||||
ClientWindowHandle GetWindowHandle() const override;
|
||||
bool WithWindowlessRendering() const override;
|
||||
|
||||
private:
|
||||
void ContinueInitOnUIThread(std::unique_ptr<RootWindowConfig> config,
|
||||
const CefBrowserSettings& settings);
|
||||
void ContinueInitOnMainThread(std::unique_ptr<RootWindowConfig> config,
|
||||
const CefBrowserSettings& settings);
|
||||
|
||||
void CreateBrowserWindow(const std::string& startup_url);
|
||||
void CreateRootWindow(const CefBrowserSettings& settings,
|
||||
bool initially_hidden);
|
||||
@ -60,11 +71,21 @@ class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate {
|
||||
void OnSetTitle(const std::string& title) override;
|
||||
void OnSetFullscreen(bool fullscreen) override;
|
||||
void OnAutoResize(const CefSize& new_size) override;
|
||||
void OnContentsBounds(const CefRect& new_bounds) override {
|
||||
RootWindow::SetBounds(new_bounds,
|
||||
/*content_bounds=*/DefaultToContentBounds());
|
||||
}
|
||||
void OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) override;
|
||||
void OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) override;
|
||||
bool GetRootWindowScreenRect(CefRect& rect) override;
|
||||
|
||||
void GetWindowBoundsAndContinue(
|
||||
const CefRect& dip_bounds,
|
||||
bool content_bounds,
|
||||
base::OnceCallback<void(const CefRect& /*pixel_bounds*/)> next);
|
||||
|
||||
void NotifyMoveOrResizeStarted();
|
||||
void NotifySetFocus();
|
||||
@ -78,6 +99,8 @@ class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate {
|
||||
void NotifyCloseBrowser();
|
||||
void NotifyDestroyedIfDone(bool window_destroyed, bool browser_destroyed);
|
||||
|
||||
void MaybeNotifyScreenInfoChanged();
|
||||
|
||||
GtkWidget* CreateMenuBar();
|
||||
GtkWidget* CreateMenu(GtkWidget* menu_bar, const char* text);
|
||||
GtkWidget* AddMenuEntry(GtkWidget* menu_widget, const char* text, int id);
|
||||
@ -128,8 +151,11 @@ class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate {
|
||||
bool with_controls_;
|
||||
bool always_on_top_;
|
||||
bool with_osr_;
|
||||
OsrRendererSettings osr_settings_;
|
||||
bool is_popup_;
|
||||
CefRect start_rect_;
|
||||
cef_show_state_t initial_show_state_ = CEF_SHOW_STATE_NORMAL;
|
||||
float initial_scale_factor_ = 1.0;
|
||||
std::unique_ptr<BrowserWindow> browser_window_;
|
||||
|
||||
// Main window.
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
namespace client {
|
||||
|
||||
struct OsrRendererSettings;
|
||||
class RootWindowMacImpl;
|
||||
|
||||
// OS X implementation of a top-level native window in the browser process.
|
||||
@ -27,6 +28,7 @@ class RootWindowMac : public RootWindow, public BrowserWindow::Delegate {
|
||||
|
||||
BrowserWindow* browser_window() const;
|
||||
RootWindow::Delegate* delegate() const;
|
||||
const OsrRendererSettings* osr_settings() const;
|
||||
|
||||
// RootWindow methods.
|
||||
void Init(RootWindow::Delegate* delegate,
|
||||
@ -41,10 +43,15 @@ class RootWindowMac : public RootWindow, public BrowserWindow::Delegate {
|
||||
CefBrowserSettings& settings) override;
|
||||
void Show(ShowMode mode) override;
|
||||
void Hide() override;
|
||||
void SetBounds(int x, int y, size_t width, size_t height) override;
|
||||
void SetBounds(int x,
|
||||
int y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
bool content_bounds) override;
|
||||
bool DefaultToContentBounds() const override;
|
||||
void Close(bool force) override;
|
||||
void SetDeviceScaleFactor(float device_scale_factor) override;
|
||||
float GetDeviceScaleFactor() const override;
|
||||
std::optional<float> GetDeviceScaleFactor() const override;
|
||||
CefRefPtr<CefBrowser> GetBrowser() const override;
|
||||
ClientWindowHandle GetWindowHandle() const override;
|
||||
bool WithWindowlessRendering() const override;
|
||||
@ -57,6 +64,10 @@ class RootWindowMac : public RootWindow, public BrowserWindow::Delegate {
|
||||
void OnSetTitle(const std::string& title) override;
|
||||
void OnSetFullscreen(bool fullscreen) override;
|
||||
void OnAutoResize(const CefSize& new_size) override;
|
||||
void OnContentsBounds(const CefRect& new_bounds) override {
|
||||
RootWindow::SetBounds(new_bounds,
|
||||
/*content_bounds=*/DefaultToContentBounds());
|
||||
}
|
||||
void OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) override;
|
||||
|
@ -14,7 +14,10 @@
|
||||
#include "tests/cefclient/browser/browser_window_std_mac.h"
|
||||
#include "tests/cefclient/browser/client_prefs.h"
|
||||
#include "tests/cefclient/browser/main_context.h"
|
||||
#include "tests/cefclient/browser/osr_renderer_settings.h"
|
||||
#include "tests/cefclient/browser/root_window_manager.h"
|
||||
#include "tests/cefclient/browser/temp_window.h"
|
||||
#include "tests/cefclient/browser/util_mac.h"
|
||||
#include "tests/cefclient/browser/window_test_runner_mac.h"
|
||||
#include "tests/shared/browser/main_message_loop.h"
|
||||
#include "tests/shared/common/client_switches.h"
|
||||
@ -65,40 +68,6 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
|
||||
return button;
|
||||
}
|
||||
|
||||
// Returns the current DIP screen bounds for a visible window in the
|
||||
// restored position, or nullopt if the window is currently minimized or
|
||||
// fullscreen.
|
||||
std::optional<CefRect> GetWindowBoundsInScreen(NSWindow* window) {
|
||||
if ([window isMiniaturized] or [window isZoomed]) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto screen = [window screen];
|
||||
if (screen == nil) {
|
||||
screen = [NSScreen mainScreen];
|
||||
}
|
||||
|
||||
const auto bounds = [window frame];
|
||||
const auto screen_bounds = [screen frame];
|
||||
|
||||
if (NSEqualRects(bounds, screen_bounds)) {
|
||||
// Don't include windows that are transitioning to fullscreen.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CefRect dip_bounds{static_cast<int>(bounds.origin.x),
|
||||
static_cast<int>(bounds.origin.y),
|
||||
static_cast<int>(bounds.size.width),
|
||||
static_cast<int>(bounds.size.height)};
|
||||
|
||||
// Convert from macOS coordinates (bottom-left origin) to DIP coordinates
|
||||
// (top-left origin).
|
||||
dip_bounds.y = static_cast<int>(screen_bounds.size.height) -
|
||||
dip_bounds.height - dip_bounds.y;
|
||||
|
||||
return dip_bounds;
|
||||
}
|
||||
|
||||
// Keep the frame bounds inside the display work area.
|
||||
NSRect ClampNSBoundsToWorkArea(const NSRect& frame_bounds,
|
||||
const CefRect& display_bounds,
|
||||
@ -142,6 +111,7 @@ NSRect ClampNSBoundsToWorkArea(const NSRect& frame_bounds,
|
||||
void GetNSBoundsInDisplay(const CefRect& dip_bounds,
|
||||
bool input_content_bounds,
|
||||
NSWindowStyleMask style_mask,
|
||||
bool add_controls,
|
||||
NSRect& frame_rect,
|
||||
NSRect& content_rect) {
|
||||
// Identify the closest display.
|
||||
@ -158,18 +128,24 @@ void GetNSBoundsInDisplay(const CefRect& dip_bounds,
|
||||
requested_rect.origin.y = display_bounds.height - requested_rect.size.height -
|
||||
requested_rect.origin.y;
|
||||
|
||||
bool changed_content_bounds = false;
|
||||
|
||||
// Calculate the equivalent frame and content bounds.
|
||||
if (input_content_bounds) {
|
||||
// Compute frame rect from content rect. Keep the requested origin.
|
||||
content_rect = requested_rect;
|
||||
frame_rect = [NSWindow frameRectForContentRect:content_rect
|
||||
styleMask:style_mask];
|
||||
if (add_controls) {
|
||||
frame_rect.size.height += URLBAR_HEIGHT;
|
||||
}
|
||||
frame_rect.origin = requested_rect.origin;
|
||||
} else {
|
||||
// Compute content rect from frame rect.
|
||||
frame_rect = requested_rect;
|
||||
content_rect = [NSWindow contentRectForFrameRect:frame_rect
|
||||
styleMask:style_mask];
|
||||
changed_content_bounds = true;
|
||||
}
|
||||
|
||||
// Keep the frame inside the display work area.
|
||||
@ -179,6 +155,12 @@ void GetNSBoundsInDisplay(const CefRect& dip_bounds,
|
||||
frame_rect = new_frame_rect;
|
||||
content_rect = [NSWindow contentRectForFrameRect:frame_rect
|
||||
styleMask:style_mask];
|
||||
changed_content_bounds = true;
|
||||
}
|
||||
|
||||
if (changed_content_bounds && add_controls) {
|
||||
content_rect.origin.y -= URLBAR_HEIGHT;
|
||||
content_rect.size.height -= URLBAR_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,10 +193,15 @@ class RootWindowMacImpl
|
||||
CefBrowserSettings& settings);
|
||||
void Show(RootWindow::ShowMode mode);
|
||||
void Hide();
|
||||
void SetBounds(int x, int y, size_t width, size_t height);
|
||||
void SetBounds(int x,
|
||||
int y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
bool content_bounds);
|
||||
bool DefaultToContentBounds() const;
|
||||
void Close(bool force);
|
||||
void SetDeviceScaleFactor(float device_scale_factor);
|
||||
float GetDeviceScaleFactor() const;
|
||||
std::optional<float> GetDeviceScaleFactor() const;
|
||||
CefRefPtr<CefBrowser> GetBrowser() const;
|
||||
ClientWindowHandle GetWindowHandle() const;
|
||||
bool WithWindowlessRendering() const;
|
||||
@ -236,6 +223,7 @@ class RootWindowMacImpl
|
||||
RootWindowMac& root_window_;
|
||||
bool with_controls_ = false;
|
||||
bool with_osr_ = false;
|
||||
OsrRendererSettings osr_settings_;
|
||||
bool is_popup_ = false;
|
||||
CefRect initial_bounds_;
|
||||
cef_show_state_t initial_show_state_ = CEF_SHOW_STATE_NORMAL;
|
||||
@ -390,7 +378,11 @@ void RootWindowMacImpl::Hide() {
|
||||
[window_ orderOut:nil];
|
||||
}
|
||||
|
||||
void RootWindowMacImpl::SetBounds(int x, int y, size_t width, size_t height) {
|
||||
void RootWindowMacImpl::SetBounds(int x,
|
||||
int y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
bool content_bounds) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
if (!window_) {
|
||||
@ -399,15 +391,29 @@ void RootWindowMacImpl::SetBounds(int x, int y, size_t width, size_t height) {
|
||||
|
||||
const CefRect dip_bounds(x, y, static_cast<int>(width),
|
||||
static_cast<int>(height));
|
||||
const bool add_controls = WithWindowlessRendering() || with_controls_;
|
||||
|
||||
// Calculate the equivalent frame and content area bounds.
|
||||
NSRect frame_rect, content_rect;
|
||||
GetNSBoundsInDisplay(dip_bounds, /*input_content_bounds=*/true,
|
||||
[window_ styleMask], frame_rect, content_rect);
|
||||
GetNSBoundsInDisplay(dip_bounds, content_bounds, [window_ styleMask],
|
||||
add_controls, frame_rect, content_rect);
|
||||
|
||||
[window_ setFrame:frame_rect display:YES];
|
||||
}
|
||||
|
||||
bool RootWindowMacImpl::DefaultToContentBounds() const {
|
||||
if (!WithWindowlessRendering()) {
|
||||
// The root NSWindow will be queried by default.
|
||||
return false;
|
||||
}
|
||||
if (osr_settings_.real_screen_bounds) {
|
||||
// Root NSWindow bounds are provided via GetRootWindowRect.
|
||||
return false;
|
||||
}
|
||||
// The root NSWindow will not be queried by default.
|
||||
return true;
|
||||
}
|
||||
|
||||
void RootWindowMacImpl::Close(bool force) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
@ -426,15 +432,14 @@ void RootWindowMacImpl::SetDeviceScaleFactor(float device_scale_factor) {
|
||||
}
|
||||
}
|
||||
|
||||
float RootWindowMacImpl::GetDeviceScaleFactor() const {
|
||||
std::optional<float> RootWindowMacImpl::GetDeviceScaleFactor() const {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
if (browser_window_ && with_osr_) {
|
||||
return browser_window_->GetDeviceScaleFactor();
|
||||
}
|
||||
|
||||
NOTREACHED();
|
||||
return 0.0f;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowser> RootWindowMacImpl::GetBrowser() const {
|
||||
@ -453,6 +458,7 @@ ClientWindowHandle RootWindowMacImpl::GetWindowHandle() const {
|
||||
|
||||
bool RootWindowMacImpl::WithWindowlessRendering() const {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
DCHECK(root_window_.initialized_);
|
||||
return with_osr_;
|
||||
}
|
||||
|
||||
@ -464,10 +470,9 @@ void RootWindowMacImpl::OnNativeWindowClosed() {
|
||||
|
||||
void RootWindowMacImpl::CreateBrowserWindow(const std::string& startup_url) {
|
||||
if (with_osr_) {
|
||||
OsrRendererSettings settings = {};
|
||||
MainContext::Get()->PopulateOsrSettings(&settings);
|
||||
MainContext::Get()->PopulateOsrSettings(&osr_settings_);
|
||||
browser_window_.reset(new BrowserWindowOsrMac(&root_window_, with_controls_,
|
||||
startup_url, settings));
|
||||
startup_url, osr_settings_));
|
||||
} else {
|
||||
browser_window_.reset(
|
||||
new BrowserWindowStdMac(&root_window_, with_controls_, startup_url));
|
||||
@ -501,10 +506,12 @@ void RootWindowMacImpl::CreateRootWindow(const CefBrowserSettings& settings,
|
||||
(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
|
||||
NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable);
|
||||
|
||||
// Calculate the equivalent frame and content area bounds.
|
||||
// Calculate the equivalent frame and content area bounds. Controls, if any,
|
||||
// are already included in the desired size.
|
||||
NSRect frame_rect, content_rect;
|
||||
GetNSBoundsInDisplay(dip_bounds, /*input_content_bounds=*/is_popup_,
|
||||
style_mask, frame_rect, content_rect);
|
||||
style_mask, /*add_controls=*/false, frame_rect,
|
||||
content_rect);
|
||||
|
||||
// Create the main window.
|
||||
window_ = [[NSWindow alloc] initWithContentRect:content_rect
|
||||
@ -606,6 +613,25 @@ void RootWindowMacImpl::CreateRootWindow(const CefBrowserSettings& settings,
|
||||
// if the point is on a secondary display.
|
||||
[window_ setFrameOrigin:frame_rect.origin];
|
||||
|
||||
if (with_osr_) {
|
||||
std::optional<float> parent_scale_factor;
|
||||
if (is_popup_) {
|
||||
if (auto parent_window =
|
||||
MainContext::Get()->GetRootWindowManager()->GetWindowForBrowser(
|
||||
root_window_.opener_browser_id())) {
|
||||
parent_scale_factor = parent_window->GetDeviceScaleFactor();
|
||||
}
|
||||
}
|
||||
|
||||
if (parent_scale_factor) {
|
||||
browser_window_->SetDeviceScaleFactor(*parent_scale_factor);
|
||||
} else {
|
||||
auto display = CefDisplay::GetDisplayMatchingBounds(
|
||||
dip_bounds, /*input_pixel_coords=*/false);
|
||||
browser_window_->SetDeviceScaleFactor(display->GetDeviceScaleFactor());
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_popup_) {
|
||||
// Create the browser window.
|
||||
browser_window_->CreateBrowser(
|
||||
@ -709,14 +735,20 @@ void RootWindowMacImpl::OnAutoResize(const CefSize& new_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Desired content rectangle.
|
||||
NSRect content_rect;
|
||||
content_rect.size.width = static_cast<int>(new_size.width);
|
||||
content_rect.size.height =
|
||||
static_cast<int>(new_size.height) + (with_controls_ ? URLBAR_HEIGHT : 0);
|
||||
CefRect dip_bounds(0, 0, static_cast<int>(new_size.width),
|
||||
static_cast<int>(new_size.height));
|
||||
|
||||
if (auto screen_bounds = GetWindowBoundsInScreen(window_)) {
|
||||
dip_bounds.x = (*screen_bounds).x;
|
||||
dip_bounds.y = (*screen_bounds).y;
|
||||
}
|
||||
|
||||
// Calculate the equivalent frame and content area bounds.
|
||||
NSRect frame_rect, content_rect;
|
||||
GetNSBoundsInDisplay(dip_bounds, /*input_content_bounds=*/true,
|
||||
[window_ styleMask], with_controls_, frame_rect,
|
||||
content_rect);
|
||||
|
||||
// Convert to a frame rectangle.
|
||||
NSRect frame_rect = [window_ frameRectForContentRect:content_rect];
|
||||
// Don't change the origin.
|
||||
frame_rect.origin = window_.frame.origin;
|
||||
|
||||
@ -775,6 +807,10 @@ RootWindow::Delegate* RootWindowMac::delegate() const {
|
||||
return delegate_;
|
||||
}
|
||||
|
||||
const OsrRendererSettings* RootWindowMac::osr_settings() const {
|
||||
return &impl_->osr_settings_;
|
||||
}
|
||||
|
||||
void RootWindowMac::Init(RootWindow::Delegate* delegate,
|
||||
std::unique_ptr<RootWindowConfig> config,
|
||||
const CefBrowserSettings& settings) {
|
||||
@ -804,8 +840,16 @@ void RootWindowMac::Hide() {
|
||||
impl_->Hide();
|
||||
}
|
||||
|
||||
void RootWindowMac::SetBounds(int x, int y, size_t width, size_t height) {
|
||||
impl_->SetBounds(x, y, width, height);
|
||||
void RootWindowMac::SetBounds(int x,
|
||||
int y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
bool content_bounds) {
|
||||
impl_->SetBounds(x, y, width, height, content_bounds);
|
||||
}
|
||||
|
||||
bool RootWindowMac::DefaultToContentBounds() const {
|
||||
return impl_->DefaultToContentBounds();
|
||||
}
|
||||
|
||||
void RootWindowMac::Close(bool force) {
|
||||
@ -816,7 +860,7 @@ void RootWindowMac::SetDeviceScaleFactor(float device_scale_factor) {
|
||||
impl_->SetDeviceScaleFactor(device_scale_factor);
|
||||
}
|
||||
|
||||
float RootWindowMac::GetDeviceScaleFactor() const {
|
||||
std::optional<float> RootWindowMac::GetDeviceScaleFactor() const {
|
||||
return impl_->GetDeviceScaleFactor();
|
||||
}
|
||||
|
||||
@ -1005,6 +1049,16 @@ void RootWindowMac::OnNativeWindowClosed() {
|
||||
if (dip_bounds) {
|
||||
last_visible_bounds_ = dip_bounds;
|
||||
}
|
||||
|
||||
if (root_window_->WithWindowlessRendering() &&
|
||||
root_window_->osr_settings()->real_screen_bounds) {
|
||||
// Send the new root window bounds to the renderer.
|
||||
if (auto* browser_window = root_window_->browser_window()) {
|
||||
if (auto browser = browser_window->GetBrowser()) {
|
||||
browser->GetHost()->NotifyScreenInfoChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the application has been hidden.
|
||||
|
@ -137,11 +137,18 @@ void RootWindowViews::Hide() {
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowViews::SetBounds(int x, int y, size_t width, size_t height) {
|
||||
void RootWindowViews::SetBounds(int x,
|
||||
int y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
bool content_bounds) {
|
||||
// We always expect Window bounds with Views-hosted browsers.
|
||||
DCHECK(!content_bounds);
|
||||
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
// Execute this method on the UI thread.
|
||||
CefPostTask(TID_UI, base::BindOnce(&RootWindowViews::SetBounds, this, x, y,
|
||||
width, height));
|
||||
width, height, content_bounds));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -151,6 +158,11 @@ void RootWindowViews::SetBounds(int x, int y, size_t width, size_t height) {
|
||||
}
|
||||
}
|
||||
|
||||
bool RootWindowViews::DefaultToContentBounds() const {
|
||||
// Views-hosted browsers always receive CefWindow bounds.
|
||||
return false;
|
||||
}
|
||||
|
||||
void RootWindowViews::Close(bool force) {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
// Execute this method on the UI thread.
|
||||
@ -169,11 +181,11 @@ void RootWindowViews::SetDeviceScaleFactor(float device_scale_factor) {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
float RootWindowViews::GetDeviceScaleFactor() const {
|
||||
std::optional<float> RootWindowViews::GetDeviceScaleFactor() const {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
// Windowless rendering is not supported.
|
||||
NOTREACHED();
|
||||
return 0.0;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowser> RootWindowViews::GetBrowser() const {
|
||||
|
@ -44,10 +44,15 @@ class RootWindowViews : public RootWindow,
|
||||
CefBrowserSettings& settings) override;
|
||||
void Show(ShowMode mode) override;
|
||||
void Hide() override;
|
||||
void SetBounds(int x, int y, size_t width, size_t height) override;
|
||||
void SetBounds(int x,
|
||||
int y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
bool content_bounds) override;
|
||||
bool DefaultToContentBounds() const override;
|
||||
void Close(bool force) override;
|
||||
void SetDeviceScaleFactor(float device_scale_factor) override;
|
||||
float GetDeviceScaleFactor() const override;
|
||||
std::optional<float> GetDeviceScaleFactor() const override;
|
||||
CefRefPtr<CefBrowser> GetBrowser() const override;
|
||||
ClientWindowHandle GetWindowHandle() const override;
|
||||
bool WithWindowlessRendering() const override { return false; }
|
||||
@ -80,6 +85,10 @@ class RootWindowViews : public RootWindow,
|
||||
void OnSetFavicon(CefRefPtr<CefImage> image) override;
|
||||
void OnSetFullscreen(bool fullscreen) override;
|
||||
void OnAutoResize(const CefSize& new_size) override;
|
||||
void OnContentsBounds(const CefRect& new_bounds) override {
|
||||
RootWindow::SetBounds(new_bounds,
|
||||
/*content_bounds=*/DefaultToContentBounds());
|
||||
}
|
||||
void OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) override;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "tests/cefclient/browser/client_prefs.h"
|
||||
#include "tests/cefclient/browser/main_context.h"
|
||||
#include "tests/cefclient/browser/resource.h"
|
||||
#include "tests/cefclient/browser/root_window_manager.h"
|
||||
#include "tests/cefclient/browser/temp_window.h"
|
||||
#include "tests/cefclient/browser/window_test_runner_win.h"
|
||||
#include "tests/shared/browser/geometry_util.h"
|
||||
@ -85,6 +86,8 @@ bool IsProcessPerMonitorDpiAware() {
|
||||
// DPI value for 1x scale factor.
|
||||
#define DPI_1X 96.0f
|
||||
|
||||
// WARNING: Only use this value for scaling native controls. DIP coordinates
|
||||
// originating from the browser should be converted using GetScreenPixelBounds.
|
||||
float GetWindowScaleFactor(HWND hwnd) {
|
||||
if (hwnd && IsProcessPerMonitorDpiAware()) {
|
||||
typedef UINT(WINAPI * GetDpiForWindowPtr)(HWND);
|
||||
@ -106,6 +109,104 @@ int GetURLBarHeight(HWND hwnd) {
|
||||
return LogicalToDevice(URLBAR_HEIGHT, GetWindowScaleFactor(hwnd));
|
||||
}
|
||||
|
||||
float GetScaleFactor(const CefRect& bounds,
|
||||
const std::optional<float>& device_scale_factor,
|
||||
bool pixel_bounds) {
|
||||
if (device_scale_factor.has_value()) {
|
||||
return *device_scale_factor;
|
||||
}
|
||||
auto display = CefDisplay::GetDisplayMatchingBounds(
|
||||
bounds, /*input_pixel_coords=*/pixel_bounds);
|
||||
return display->GetDeviceScaleFactor();
|
||||
}
|
||||
|
||||
// Keep the bounds inside the closest display work area.
|
||||
CefRect ClampBoundsToDisplay(const CefRect& pixel_bounds) {
|
||||
auto display = CefDisplay::GetDisplayMatchingBounds(
|
||||
pixel_bounds, /*input_pixel_coords=*/true);
|
||||
CefRect work_area =
|
||||
CefDisplay::ConvertScreenRectToPixels(display->GetWorkArea());
|
||||
|
||||
CefRect bounds = pixel_bounds;
|
||||
ConstrainWindowBounds(work_area, bounds);
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
// Convert DIP screen coordinates originating from the browser to device screen
|
||||
// (pixel) coordinates. |device_scale_factor| will be specified with off-screen
|
||||
// rendering.
|
||||
CefRect GetScreenPixelBounds(const CefRect& dip_bounds,
|
||||
const std::optional<float>& device_scale_factor) {
|
||||
if (device_scale_factor.has_value()) {
|
||||
return LogicalToDevice(dip_bounds, *device_scale_factor);
|
||||
}
|
||||
return CefDisplay::ConvertScreenRectToPixels(dip_bounds);
|
||||
}
|
||||
|
||||
// |content_bounds| is the browser content area bounds in DIP screen
|
||||
// coordinates. Convert to device screen (pixel) coordinates and then expand to
|
||||
// frame bounds. Keep the resulting bounds inside the closest display work area.
|
||||
// |device_scale_factor| will be specified with off-screen rendering.
|
||||
CefRect GetFrameBoundsInDisplay(
|
||||
HWND hwnd,
|
||||
const CefRect& content_bounds,
|
||||
bool with_controls,
|
||||
const std::optional<float>& device_scale_factor) {
|
||||
CefRect pixel_bounds =
|
||||
GetScreenPixelBounds(content_bounds, device_scale_factor);
|
||||
if (with_controls) {
|
||||
// Expand the bounds to include native controls.
|
||||
const int urlbar_height = GetURLBarHeight(hwnd);
|
||||
pixel_bounds.y -= urlbar_height;
|
||||
pixel_bounds.height += urlbar_height;
|
||||
}
|
||||
|
||||
RECT rect = {pixel_bounds.x, pixel_bounds.y,
|
||||
pixel_bounds.x + pixel_bounds.width,
|
||||
pixel_bounds.y + pixel_bounds.height};
|
||||
DWORD style = GetWindowLong(hwnd, GWL_STYLE);
|
||||
DWORD ex_style = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
bool has_menu = !(style & WS_CHILD) && (GetMenu(hwnd) != nullptr);
|
||||
|
||||
// Calculate the frame size based on the current style.
|
||||
AdjustWindowRectEx(&rect, style, has_menu, ex_style);
|
||||
|
||||
return ClampBoundsToDisplay(
|
||||
{rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top});
|
||||
}
|
||||
|
||||
// Execute calls on the required threads.
|
||||
void GetPixelBoundsAndContinue(HWND hwnd,
|
||||
const CefRect& dip_bounds,
|
||||
bool content_bounds,
|
||||
bool with_controls,
|
||||
const std::optional<float>& device_scale_factor,
|
||||
base::OnceCallback<void(const CefRect&)> next) {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI,
|
||||
base::BindOnce(&GetPixelBoundsAndContinue, hwnd, dip_bounds,
|
||||
content_bounds, with_controls,
|
||||
device_scale_factor, std::move(next)));
|
||||
return;
|
||||
}
|
||||
|
||||
CefRect pixel_bounds;
|
||||
if (content_bounds) {
|
||||
pixel_bounds = GetFrameBoundsInDisplay(hwnd, dip_bounds, with_controls,
|
||||
device_scale_factor);
|
||||
} else {
|
||||
pixel_bounds = ClampBoundsToDisplay(
|
||||
GetScreenPixelBounds(dip_bounds, device_scale_factor));
|
||||
}
|
||||
|
||||
if (CURRENTLY_ON_MAIN_THREAD()) {
|
||||
std::move(next).Run(pixel_bounds);
|
||||
} else {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(std::move(next), pixel_bounds));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RootWindowWin::RootWindowWin(bool use_alloy_style)
|
||||
@ -165,9 +266,18 @@ void RootWindowWin::ContinueInitOnUIThread(
|
||||
}
|
||||
}
|
||||
|
||||
if (with_osr_) {
|
||||
initial_scale_factor_ =
|
||||
GetScaleFactor(initial_bounds_, std::nullopt, /*pixel_bounds=*/true);
|
||||
}
|
||||
|
||||
if (CURRENTLY_ON_MAIN_THREAD()) {
|
||||
ContinueInitOnMainThread(std::move(config), settings);
|
||||
} else {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowWin::ContinueInitOnMainThread,
|
||||
this, std::move(config), settings));
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowWin::ContinueInitOnMainThread(
|
||||
std::unique_ptr<RootWindowConfig> config,
|
||||
@ -196,6 +306,7 @@ void RootWindowWin::InitAsPopup(RootWindow::Delegate* delegate,
|
||||
with_osr_ = with_osr;
|
||||
is_popup_ = true;
|
||||
|
||||
// NOTE: This will be the size for the whole window including frame.
|
||||
if (popupFeatures.xSet) {
|
||||
initial_bounds_.x = popupFeatures.x;
|
||||
}
|
||||
@ -208,6 +319,13 @@ void RootWindowWin::InitAsPopup(RootWindow::Delegate* delegate,
|
||||
if (popupFeatures.heightSet) {
|
||||
initial_bounds_.height = popupFeatures.height;
|
||||
}
|
||||
initial_bounds_ = ClampBoundsToDisplay(
|
||||
CefDisplay::ConvertScreenRectToPixels(initial_bounds_));
|
||||
|
||||
if (with_osr_) {
|
||||
initial_scale_factor_ =
|
||||
GetScaleFactor(initial_bounds_, std::nullopt, /*pixel_bounds=*/true);
|
||||
}
|
||||
|
||||
CreateBrowserWindow(std::string());
|
||||
|
||||
@ -256,13 +374,51 @@ void RootWindowWin::Hide() {
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowWin::SetBounds(int x, int y, size_t width, size_t height) {
|
||||
void RootWindowWin::SetBounds(int x,
|
||||
int y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
bool content_bounds) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
if (hwnd_) {
|
||||
SetWindowPos(hwnd_, nullptr, x, y, static_cast<int>(width),
|
||||
static_cast<int>(height), SWP_NOZORDER);
|
||||
if (!hwnd_) {
|
||||
return;
|
||||
}
|
||||
|
||||
CefRect dip_bounds = {x, y, static_cast<int>(width),
|
||||
static_cast<int>(height)};
|
||||
GetWindowBoundsAndContinue(
|
||||
dip_bounds, content_bounds,
|
||||
base::BindOnce(
|
||||
[](HWND hwnd, const CefRect& pixel_bounds) {
|
||||
SetWindowPos(hwnd, nullptr, pixel_bounds.x, pixel_bounds.y,
|
||||
pixel_bounds.width, pixel_bounds.height, SWP_NOZORDER);
|
||||
},
|
||||
hwnd_));
|
||||
}
|
||||
|
||||
bool RootWindowWin::DefaultToContentBounds() const {
|
||||
if (!WithWindowlessRendering()) {
|
||||
// The root HWND will be queried by default.
|
||||
return false;
|
||||
}
|
||||
if (osr_settings_.real_screen_bounds) {
|
||||
// Root HWND bounds are provided via GetRootWindowRect.
|
||||
return false;
|
||||
}
|
||||
// The root HWND will not be queried by default.
|
||||
return true;
|
||||
}
|
||||
|
||||
void RootWindowWin::GetWindowBoundsAndContinue(
|
||||
const CefRect& dip_bounds,
|
||||
bool content_bounds,
|
||||
base::OnceCallback<void(const CefRect&)> next) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
DCHECK(hwnd_);
|
||||
|
||||
GetPixelBoundsAndContinue(hwnd_, dip_bounds, content_bounds, with_controls_,
|
||||
GetDeviceScaleFactor(), std::move(next));
|
||||
}
|
||||
|
||||
void RootWindowWin::Close(bool force) {
|
||||
@ -285,15 +441,14 @@ void RootWindowWin::SetDeviceScaleFactor(float device_scale_factor) {
|
||||
}
|
||||
}
|
||||
|
||||
float RootWindowWin::GetDeviceScaleFactor() const {
|
||||
std::optional<float> RootWindowWin::GetDeviceScaleFactor() const {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
if (browser_window_ && with_osr_) {
|
||||
return browser_window_->GetDeviceScaleFactor();
|
||||
}
|
||||
|
||||
NOTREACHED();
|
||||
return 0.0f;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowser> RootWindowWin::GetBrowser() const {
|
||||
@ -312,15 +467,15 @@ ClientWindowHandle RootWindowWin::GetWindowHandle() const {
|
||||
|
||||
bool RootWindowWin::WithWindowlessRendering() const {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
DCHECK(initialized_);
|
||||
return with_osr_;
|
||||
}
|
||||
|
||||
void RootWindowWin::CreateBrowserWindow(const std::string& startup_url) {
|
||||
if (with_osr_) {
|
||||
OsrRendererSettings settings = {};
|
||||
MainContext::Get()->PopulateOsrSettings(&settings);
|
||||
MainContext::Get()->PopulateOsrSettings(&osr_settings_);
|
||||
browser_window_ = std::make_unique<BrowserWindowOsrWin>(
|
||||
this, with_controls_, startup_url, settings);
|
||||
this, with_controls_, startup_url, osr_settings_);
|
||||
} else {
|
||||
browser_window_ = std::make_unique<BrowserWindowStdWin>(
|
||||
this, with_controls_, startup_url);
|
||||
@ -771,15 +926,27 @@ void RootWindowWin::OnSize(bool minimized) {
|
||||
// Size the browser window to the whole client area.
|
||||
browser_window_->SetBounds(0, 0, rect.right, rect.bottom);
|
||||
}
|
||||
|
||||
MaybeNotifyScreenInfoChanged();
|
||||
}
|
||||
|
||||
void RootWindowWin::OnMove() {
|
||||
// Notify the browser of move events so that popup windows are displayed
|
||||
// in the correct location and dismissed when the window moves.
|
||||
CefRefPtr<CefBrowser> browser = GetBrowser();
|
||||
if (browser) {
|
||||
if (auto browser = GetBrowser()) {
|
||||
browser->GetHost()->NotifyMoveOrResizeStarted();
|
||||
}
|
||||
|
||||
MaybeNotifyScreenInfoChanged();
|
||||
}
|
||||
|
||||
void RootWindowWin::MaybeNotifyScreenInfoChanged() {
|
||||
if (!DefaultToContentBounds()) {
|
||||
// Send the new root window bounds to the renderer.
|
||||
if (auto browser = GetBrowser()) {
|
||||
browser->GetHost()->NotifyScreenInfoChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowWin::OnDpiChanged(WPARAM wParam, LPARAM lParam) {
|
||||
@ -788,6 +955,10 @@ void RootWindowWin::OnDpiChanged(WPARAM wParam, LPARAM lParam) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hwnd_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (browser_window_ && with_osr_) {
|
||||
// Scale factor for the new display.
|
||||
const float display_scale_factor =
|
||||
@ -797,8 +968,8 @@ void RootWindowWin::OnDpiChanged(WPARAM wParam, LPARAM lParam) {
|
||||
|
||||
// Suggested size and position of the current window scaled for the new DPI.
|
||||
const RECT* rect = reinterpret_cast<RECT*>(lParam);
|
||||
SetBounds(rect->left, rect->top, rect->right - rect->left,
|
||||
rect->bottom - rect->top);
|
||||
SetWindowPos(hwnd_, nullptr, rect->left, rect->top, rect->right - rect->left,
|
||||
rect->bottom - rect->top, SWP_NOZORDER);
|
||||
}
|
||||
|
||||
bool RootWindowWin::OnEraseBkgnd() {
|
||||
@ -999,42 +1170,37 @@ void RootWindowWin::OnCreate(LPCREATESTRUCT lpCreateStruct) {
|
||||
::SetMenu(hwnd_, nullptr);
|
||||
}
|
||||
|
||||
const float device_scale_factor = GetWindowScaleFactor(hwnd_);
|
||||
|
||||
if (with_osr_) {
|
||||
browser_window_->SetDeviceScaleFactor(device_scale_factor);
|
||||
std::optional<float> parent_scale_factor;
|
||||
if (is_popup_) {
|
||||
if (auto parent_window =
|
||||
MainContext::Get()->GetRootWindowManager()->GetWindowForBrowser(
|
||||
opener_browser_id())) {
|
||||
parent_scale_factor = parent_window->GetDeviceScaleFactor();
|
||||
}
|
||||
}
|
||||
|
||||
browser_window_->SetDeviceScaleFactor(
|
||||
parent_scale_factor.value_or(initial_scale_factor_));
|
||||
}
|
||||
|
||||
CefRect bounds(rect.left, rect.top, rect.right - rect.left,
|
||||
rect.bottom - rect.top);
|
||||
if (!is_popup_) {
|
||||
// Create the browser window.
|
||||
CefRect cef_rect(rect.left, rect.top, rect.right - rect.left,
|
||||
rect.bottom - rect.top);
|
||||
browser_window_->CreateBrowser(hwnd_, cef_rect, browser_settings_, nullptr,
|
||||
browser_window_->CreateBrowser(hwnd_, bounds, browser_settings_, nullptr,
|
||||
delegate_->GetRequestContext());
|
||||
} else {
|
||||
// With popups we already have a browser window. Parent the browser window
|
||||
// to the root window and show it in the correct location.
|
||||
browser_window_->ShowPopup(hwnd_, rect.left, rect.top,
|
||||
rect.right - rect.left, rect.bottom - rect.top);
|
||||
browser_window_->ShowPopup(hwnd_, bounds.x, bounds.y, bounds.width,
|
||||
bounds.height);
|
||||
}
|
||||
|
||||
window_created_ = true;
|
||||
}
|
||||
|
||||
bool RootWindowWin::OnClose() {
|
||||
if (browser_window_ && !browser_window_->IsClosing()) {
|
||||
CefRefPtr<CefBrowser> browser = GetBrowser();
|
||||
if (browser) {
|
||||
// Notify the browser window that we would like to close it. This
|
||||
// will result in a call to ClientHandler::DoClose() if the
|
||||
// JavaScript 'onbeforeunload' event handler allows it.
|
||||
browser->GetHost()->CloseBrowser(false);
|
||||
|
||||
// Cancel the close.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve current window placement information.
|
||||
WINDOWPLACEMENT placement;
|
||||
::GetWindowPlacement(hwnd_, &placement);
|
||||
@ -1047,6 +1213,20 @@ bool RootWindowWin::OnClose() {
|
||||
base::BindOnce(&RootWindowWin::SaveWindowRestoreOnUIThread, placement));
|
||||
}
|
||||
|
||||
if (browser_window_ && !browser_window_->IsClosing()) {
|
||||
CefRefPtr<CefBrowser> browser = GetBrowser();
|
||||
if (browser) {
|
||||
// Notify the browser window that we would like to close it. With Alloy
|
||||
// style this will result in a call to ClientHandler::DoClose() if the
|
||||
// JavaScript 'onbeforeunload' event handler allows it. With Chrome style
|
||||
// this will close the window indirectly via browser destruction.
|
||||
browser->GetHost()->CloseBrowser(false);
|
||||
|
||||
// Cancel the close.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Allow the close.
|
||||
return false;
|
||||
}
|
||||
@ -1124,29 +1304,18 @@ void RootWindowWin::OnAutoResize(const CefSize& new_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
int new_width = new_size.width;
|
||||
CefRect dip_bounds = {0, 0, new_size.width, new_size.height};
|
||||
|
||||
// Make the window wide enough to drag by the top menu bar.
|
||||
if (new_width < 200) {
|
||||
new_width = 200;
|
||||
}
|
||||
|
||||
const float device_scale_factor = GetWindowScaleFactor(hwnd_);
|
||||
RECT rect = {0, 0, LogicalToDevice(new_width, device_scale_factor),
|
||||
LogicalToDevice(new_size.height, device_scale_factor)};
|
||||
DWORD style = GetWindowLong(hwnd_, GWL_STYLE);
|
||||
DWORD ex_style = GetWindowLong(hwnd_, GWL_EXSTYLE);
|
||||
bool has_menu = !(style & WS_CHILD) && (GetMenu(hwnd_) != nullptr);
|
||||
|
||||
// The size value is for the client area. Calculate the whole window size
|
||||
// based on the current style.
|
||||
AdjustWindowRectEx(&rect, style, has_menu, ex_style);
|
||||
|
||||
// Size the window. The left/top values may be negative.
|
||||
// Also show the window if it's not currently visible.
|
||||
SetWindowPos(hwnd_, nullptr, 0, 0, rect.right - rect.left,
|
||||
rect.bottom - rect.top,
|
||||
GetWindowBoundsAndContinue(
|
||||
dip_bounds, /*content_bounds=*/true,
|
||||
base::BindOnce(
|
||||
[](HWND hwnd, const CefRect& pixel_bounds) {
|
||||
// Size the window and show if it's not currently visible.
|
||||
SetWindowPos(
|
||||
hwnd, nullptr, 0, 0, pixel_bounds.width, pixel_bounds.height,
|
||||
SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
|
||||
},
|
||||
hwnd_));
|
||||
}
|
||||
|
||||
void RootWindowWin::OnSetLoadingState(bool isLoading,
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "tests/cefclient/browser/browser_window.h"
|
||||
#include "tests/cefclient/browser/osr_renderer_settings.h"
|
||||
#include "tests/cefclient/browser/root_window.h"
|
||||
|
||||
namespace client {
|
||||
@ -40,10 +41,15 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
|
||||
CefBrowserSettings& settings) override;
|
||||
void Show(ShowMode mode) override;
|
||||
void Hide() override;
|
||||
void SetBounds(int x, int y, size_t width, size_t height) override;
|
||||
void SetBounds(int x,
|
||||
int y,
|
||||
size_t width,
|
||||
size_t height,
|
||||
bool content_bounds) override;
|
||||
bool DefaultToContentBounds() const override;
|
||||
void Close(bool force) override;
|
||||
void SetDeviceScaleFactor(float device_scale_factor) override;
|
||||
float GetDeviceScaleFactor() const override;
|
||||
std::optional<float> GetDeviceScaleFactor() const override;
|
||||
CefRefPtr<CefBrowser> GetBrowser() const override;
|
||||
ClientWindowHandle GetWindowHandle() const override;
|
||||
bool WithWindowlessRendering() const override;
|
||||
@ -58,6 +64,11 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
|
||||
void CreateRootWindow(const CefBrowserSettings& settings,
|
||||
bool initially_hidden);
|
||||
|
||||
void GetWindowBoundsAndContinue(
|
||||
const CefRect& dip_bounds,
|
||||
bool content_bounds,
|
||||
base::OnceCallback<void(const CefRect& /*pixel_bounds*/)> next);
|
||||
|
||||
// Register the root window class.
|
||||
static void RegisterRootClass(HINSTANCE hInstance,
|
||||
const std::wstring& window_class,
|
||||
@ -106,6 +117,10 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
|
||||
void OnSetTitle(const std::string& title) override;
|
||||
void OnSetFullscreen(bool fullscreen) override;
|
||||
void OnAutoResize(const CefSize& new_size) override;
|
||||
void OnContentsBounds(const CefRect& new_bounds) override {
|
||||
RootWindow::SetBounds(new_bounds,
|
||||
/*content_bounds=*/DefaultToContentBounds());
|
||||
}
|
||||
void OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) override;
|
||||
@ -114,6 +129,8 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
|
||||
|
||||
void NotifyDestroyedIfDone();
|
||||
|
||||
void MaybeNotifyScreenInfoChanged();
|
||||
|
||||
static void SaveWindowRestoreOnUIThread(const WINDOWPLACEMENT& placement);
|
||||
|
||||
// After initialization all members are only accessed on the main thread.
|
||||
@ -121,9 +138,11 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
|
||||
bool with_controls_ = false;
|
||||
bool always_on_top_ = false;
|
||||
bool with_osr_ = false;
|
||||
OsrRendererSettings osr_settings_;
|
||||
bool is_popup_ = false;
|
||||
CefRect initial_bounds_;
|
||||
cef_show_state_t initial_show_state_ = CEF_SHOW_STATE_NORMAL;
|
||||
float initial_scale_factor_ = 1.0;
|
||||
std::unique_ptr<BrowserWindow> browser_window_;
|
||||
CefBrowserSettings browser_settings_;
|
||||
|
||||
|
@ -146,7 +146,9 @@ void RunNewWindowTest(CefRefPtr<CefBrowser> browser) {
|
||||
|
||||
void RunPopupWindowTest(CefRefPtr<CefBrowser> browser) {
|
||||
browser->GetMainFrame()->ExecuteJavaScript(
|
||||
"window.open('https://www.google.com');", "about:blank", 0);
|
||||
"window.open('https://www.google.com', 'google', "
|
||||
"'left=100,top=100,width=600,height=400');",
|
||||
"about:blank", 0);
|
||||
}
|
||||
|
||||
void RunDialogWindowTest(CefRefPtr<CefBrowser> browser) {
|
||||
@ -269,7 +271,7 @@ void PromptDSF(CefRefPtr<CefBrowser> browser) {
|
||||
|
||||
// Format the default value string.
|
||||
std::stringstream ss;
|
||||
ss << RootWindow::GetForBrowser(browser->GetIdentifier())
|
||||
ss << *RootWindow::GetForBrowser(browser->GetIdentifier())
|
||||
->GetDeviceScaleFactor();
|
||||
|
||||
Prompt(browser, kPromptDSF, "Enter Device Scale Factor", ss.str());
|
||||
|
@ -30,4 +30,54 @@ ScopedGdkThreadsEnter::~ScopedGdkThreadsEnter() {
|
||||
}
|
||||
}
|
||||
|
||||
CefRect GetWindowBounds(GtkWindow* window, bool include_frame) {
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
|
||||
|
||||
gint x = 0;
|
||||
gint y = 0;
|
||||
gdk_window_get_origin(gdk_window, &x, &y);
|
||||
|
||||
gint width = 0;
|
||||
gint height = 0;
|
||||
gdk_window_get_geometry(gdk_window, nullptr, nullptr, &width, &height);
|
||||
|
||||
if (include_frame) {
|
||||
GdkRectangle frame_rect = {};
|
||||
gdk_window_get_frame_extents(gdk_window, &frame_rect);
|
||||
|
||||
// This calculation assumes that all added frame height is at the top of the
|
||||
// window, which may be incorrect for some window managers.
|
||||
y -= frame_rect.height - height;
|
||||
}
|
||||
|
||||
return {x, y, width, height};
|
||||
}
|
||||
|
||||
bool IsWindowMaximized(GtkWindow* window) {
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
|
||||
gint state = gdk_window_get_state(gdk_window);
|
||||
return (state & GDK_WINDOW_STATE_MAXIMIZED) ? true : false;
|
||||
}
|
||||
|
||||
void MinimizeWindow(GtkWindow* window) {
|
||||
// Unmaximize the window before minimizing so restore behaves correctly.
|
||||
if (IsWindowMaximized(window)) {
|
||||
gtk_window_unmaximize(window);
|
||||
}
|
||||
|
||||
gtk_window_iconify(window);
|
||||
}
|
||||
|
||||
void MaximizeWindow(GtkWindow* window) {
|
||||
gtk_window_maximize(window);
|
||||
}
|
||||
|
||||
void RestoreWindow(GtkWindow* window) {
|
||||
if (IsWindowMaximized(window)) {
|
||||
gtk_window_unmaximize(window);
|
||||
} else {
|
||||
gtk_window_present(window);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@ -6,8 +6,11 @@
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_UTIL_GTK_H_
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "include/base/cef_macros.h"
|
||||
#include "include/base/cef_platform_thread.h"
|
||||
#include "include/internal/cef_types_wrappers.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
@ -36,6 +39,16 @@ class ScopedGdkThreadsEnter {
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedGdkThreadsEnter);
|
||||
};
|
||||
|
||||
// Returns the window bounds in root window (pixel) coordinates.
|
||||
CefRect GetWindowBounds(GtkWindow* window, bool include_frame);
|
||||
|
||||
bool IsWindowMaximized(GtkWindow* window);
|
||||
void MinimizeWindow(GtkWindow* window);
|
||||
void MaximizeWindow(GtkWindow* window);
|
||||
|
||||
// Make sure the window isn't minimized or maximized.
|
||||
void RestoreWindow(GtkWindow* window);
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_UTIL_GTK_H_
|
||||
|
23
tests/cefclient/browser/util_mac.h
Normal file
23
tests/cefclient/browser/util_mac.h
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2025 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_TESTS_CEFCLIENT_BROWSER_UTIL_MAC_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_UTIL_MAC_H_
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
#include "include/internal/cef_types_wrappers.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
// Returns the current DIP screen bounds for a visible window in the restored
|
||||
// position, or nullopt if the window is currently minimized or fullscreen.
|
||||
std::optional<CefRect> GetWindowBoundsInScreen(NSWindow* window);
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_UTIL_MAC_H_
|
40
tests/cefclient/browser/util_mac.mm
Normal file
40
tests/cefclient/browser/util_mac.mm
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2025 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 "tests/cefclient/browser/util_mac.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
std::optional<CefRect> GetWindowBoundsInScreen(NSWindow* window) {
|
||||
if ([window isMiniaturized] or [window isZoomed]) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto screen = [window screen];
|
||||
if (screen == nil) {
|
||||
screen = [NSScreen mainScreen];
|
||||
}
|
||||
|
||||
const auto bounds = [window frame];
|
||||
const auto screen_bounds = [screen frame];
|
||||
|
||||
if (NSEqualRects(bounds, screen_bounds)) {
|
||||
// Don't include windows that are transitioning to fullscreen.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CefRect dip_bounds{static_cast<int>(bounds.origin.x),
|
||||
static_cast<int>(bounds.origin.y),
|
||||
static_cast<int>(bounds.size.width),
|
||||
static_cast<int>(bounds.size.height)};
|
||||
|
||||
// Convert from macOS coordinates (bottom-left origin) to DIP coordinates
|
||||
// (top-left origin).
|
||||
dip_bounds.y = static_cast<int>(screen_bounds.size.height) -
|
||||
dip_bounds.height - dip_bounds.y;
|
||||
|
||||
return dip_bounds;
|
||||
}
|
||||
|
||||
} // namespace client
|
@ -17,6 +17,7 @@
|
||||
#include "tests/cefclient/browser/main_context.h"
|
||||
#include "tests/cefclient/browser/resource.h"
|
||||
#include "tests/cefclient/browser/views_style.h"
|
||||
#include "tests/shared/browser/geometry_util.h"
|
||||
#include "tests/shared/common/client_switches.h"
|
||||
|
||||
#if !defined(OS_WIN)
|
||||
@ -229,7 +230,9 @@ void ViewsWindow::Maximize() {
|
||||
void ViewsWindow::SetBounds(const CefRect& bounds) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (window_) {
|
||||
window_->SetBounds(bounds);
|
||||
auto window_bounds = bounds;
|
||||
ConstrainWindowBounds(window_->GetDisplay()->GetWorkArea(), window_bounds);
|
||||
window_->SetBounds(window_bounds);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "include/views/cef_browser_view.h"
|
||||
#include "include/wrapper/cef_stream_resource_handler.h"
|
||||
#include "tests/cefclient/browser/main_context.h"
|
||||
#include "tests/cefclient/browser/root_window.h"
|
||||
#include "tests/cefclient/browser/test_runner.h"
|
||||
#include "tests/cefclient/browser/window_test_runner.h"
|
||||
#include "tests/cefclient/browser/window_test_runner_views.h"
|
||||
@ -40,7 +41,8 @@ const char kMessageTitlebarHeightName[] = "WindowTest.TitlebarHeight";
|
||||
// Create the appropriate platform test runner object.
|
||||
std::unique_ptr<WindowTestRunner> CreateWindowTestRunner(
|
||||
CefRefPtr<CefBrowser> browser) {
|
||||
if (CefBrowserView::GetForBrowser(browser)) {
|
||||
auto root_window = RootWindow::GetForBrowser(browser->GetIdentifier());
|
||||
if (root_window->IsViewsHosted()) {
|
||||
// Browser is Views-hosted.
|
||||
return std::make_unique<WindowTestRunnerViews>();
|
||||
}
|
||||
@ -99,6 +101,20 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
|
||||
return false;
|
||||
}
|
||||
|
||||
RunOnMainThread(browser, request, callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static void RunOnMainThread(CefRefPtr<CefBrowser> browser,
|
||||
const CefString& request,
|
||||
CefRefPtr<Callback> callback) {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(&Handler::RunOnMainThread, browser,
|
||||
request, callback));
|
||||
return;
|
||||
}
|
||||
|
||||
auto runner = CreateWindowTestRunner(browser);
|
||||
|
||||
const std::string& message_name = request;
|
||||
@ -123,7 +139,6 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
|
||||
}
|
||||
|
||||
callback->Success("");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4,35 +4,21 @@
|
||||
|
||||
#include "tests/cefclient/browser/window_test_runner.h"
|
||||
|
||||
#include "tests/cefclient/browser/root_window.h"
|
||||
|
||||
namespace client::window_test {
|
||||
|
||||
// static
|
||||
void WindowTestRunner::ModifyBounds(const CefRect& display, CefRect& window) {
|
||||
window.x += display.x;
|
||||
window.y += display.y;
|
||||
void WindowTestRunner::SetPos(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
if (window.x < display.x) {
|
||||
window.x = display.x;
|
||||
}
|
||||
if (window.y < display.y) {
|
||||
window.y = display.y;
|
||||
}
|
||||
if (window.width < 100) {
|
||||
window.width = 100;
|
||||
} else if (window.width >= display.width) {
|
||||
window.width = display.width;
|
||||
}
|
||||
if (window.height < 100) {
|
||||
window.height = 100;
|
||||
} else if (window.height >= display.height) {
|
||||
window.height = display.height;
|
||||
}
|
||||
if (window.x + window.width >= display.x + display.width) {
|
||||
window.x = display.x + display.width - window.width;
|
||||
}
|
||||
if (window.y + window.height >= display.y + display.height) {
|
||||
window.y = display.y + display.height - window.height;
|
||||
}
|
||||
auto root_window = RootWindow::GetForBrowser(browser->GetIdentifier());
|
||||
root_window->SetBounds(
|
||||
x, y, width, height,
|
||||
/*content_bounds=*/root_window->DefaultToContentBounds());
|
||||
}
|
||||
|
||||
void WindowTestRunner::Fullscreen(CefRefPtr<CefBrowser> browser) {
|
||||
|
@ -13,25 +13,21 @@
|
||||
namespace client::window_test {
|
||||
|
||||
// Implement this interface for different platforms. Methods will be called on
|
||||
// the browser process UI thread unless otherwise indicated.
|
||||
// the browser process main thread unless otherwise indicated.
|
||||
class WindowTestRunner {
|
||||
public:
|
||||
virtual ~WindowTestRunner() = default;
|
||||
|
||||
virtual void SetPos(CefRefPtr<CefBrowser> browser,
|
||||
void SetPos(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) = 0;
|
||||
int height);
|
||||
virtual void Minimize(CefRefPtr<CefBrowser> browser) = 0;
|
||||
virtual void Maximize(CefRefPtr<CefBrowser> browser) = 0;
|
||||
virtual void Restore(CefRefPtr<CefBrowser> browser) = 0;
|
||||
virtual void Fullscreen(CefRefPtr<CefBrowser> browser);
|
||||
|
||||
// Fit |window| inside |display|. Coordinates are relative to the upper-left
|
||||
// corner of the display.
|
||||
static void ModifyBounds(const CefRect& display, CefRect& window);
|
||||
|
||||
virtual void SetTitleBarHeight(CefRefPtr<CefBrowser> browser,
|
||||
const std::optional<float>& height);
|
||||
};
|
||||
|
@ -29,113 +29,32 @@ GtkWindow* GetWindow(CefRefPtr<CefBrowser> browser) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IsMaximized(GtkWindow* window) {
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
|
||||
gint state = gdk_window_get_state(gdk_window);
|
||||
return (state & GDK_WINDOW_STATE_MAXIMIZED) ? true : false;
|
||||
}
|
||||
|
||||
void SetPosImpl(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
|
||||
GtkWindow* window = GetWindow(browser);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
|
||||
|
||||
// Make sure the window isn't minimized or maximized.
|
||||
if (IsMaximized(window)) {
|
||||
gtk_window_unmaximize(window);
|
||||
} else {
|
||||
gtk_window_present(window);
|
||||
}
|
||||
|
||||
// Retrieve information about the display that contains the window.
|
||||
GdkScreen* screen = gdk_screen_get_default();
|
||||
gint monitor = gdk_screen_get_monitor_at_window(screen, gdk_window);
|
||||
GdkRectangle rect;
|
||||
gdk_screen_get_monitor_geometry(screen, monitor, &rect);
|
||||
|
||||
// Make sure the window is inside the display.
|
||||
CefRect display_rect(rect.x, rect.y, rect.width, rect.height);
|
||||
CefRect window_rect(x, y, width, height);
|
||||
WindowTestRunner::ModifyBounds(display_rect, window_rect);
|
||||
|
||||
gdk_window_move_resize(gdk_window, window_rect.x, window_rect.y,
|
||||
window_rect.width, window_rect.height);
|
||||
}
|
||||
|
||||
void MinimizeImpl(CefRefPtr<CefBrowser> browser) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
|
||||
GtkWindow* window = GetWindow(browser);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Unmaximize the window before minimizing so restore behaves correctly.
|
||||
if (IsMaximized(window)) {
|
||||
gtk_window_unmaximize(window);
|
||||
}
|
||||
|
||||
gtk_window_iconify(window);
|
||||
}
|
||||
|
||||
void MaximizeImpl(CefRefPtr<CefBrowser> browser) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
|
||||
GtkWindow* window = GetWindow(browser);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
gtk_window_maximize(window);
|
||||
}
|
||||
|
||||
void RestoreImpl(CefRefPtr<CefBrowser> browser) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
|
||||
GtkWindow* window = GetWindow(browser);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
if (IsMaximized(window)) {
|
||||
gtk_window_unmaximize(window);
|
||||
} else {
|
||||
gtk_window_present(window);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
WindowTestRunnerGtk::WindowTestRunnerGtk() {}
|
||||
|
||||
void WindowTestRunnerGtk::SetPos(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(SetPosImpl, browser, x, y, width, height));
|
||||
}
|
||||
WindowTestRunnerGtk::WindowTestRunnerGtk() = default;
|
||||
|
||||
void WindowTestRunnerGtk::Minimize(CefRefPtr<CefBrowser> browser) {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(MinimizeImpl, browser));
|
||||
REQUIRE_MAIN_THREAD();
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
if (auto* window = GetWindow(browser)) {
|
||||
MinimizeWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowTestRunnerGtk::Maximize(CefRefPtr<CefBrowser> browser) {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(MaximizeImpl, browser));
|
||||
REQUIRE_MAIN_THREAD();
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
if (auto* window = GetWindow(browser)) {
|
||||
MaximizeWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowTestRunnerGtk::Restore(CefRefPtr<CefBrowser> browser) {
|
||||
MAIN_POST_CLOSURE(base::BindOnce(RestoreImpl, browser));
|
||||
REQUIRE_MAIN_THREAD();
|
||||
ScopedGdkThreadsEnter scoped_gdk_threads;
|
||||
if (auto* window = GetWindow(browser)) {
|
||||
RestoreWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace window_test
|
||||
|
@ -16,11 +16,6 @@ class WindowTestRunnerGtk : public WindowTestRunner {
|
||||
public:
|
||||
WindowTestRunnerGtk();
|
||||
|
||||
void SetPos(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) override;
|
||||
void Minimize(CefRefPtr<CefBrowser> browser) override;
|
||||
void Maximize(CefRefPtr<CefBrowser> browser) override;
|
||||
void Restore(CefRefPtr<CefBrowser> browser) override;
|
||||
|
@ -16,11 +16,6 @@ class WindowTestRunnerMac : public WindowTestRunner {
|
||||
public:
|
||||
WindowTestRunnerMac();
|
||||
|
||||
void SetPos(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) override;
|
||||
void Minimize(CefRefPtr<CefBrowser> browser) override;
|
||||
void Maximize(CefRefPtr<CefBrowser> browser) override;
|
||||
void Restore(CefRefPtr<CefBrowser> browser) override;
|
||||
|
@ -22,48 +22,7 @@ NSWindow* GetWindow(CefRefPtr<CefBrowser> browser) {
|
||||
|
||||
} // namespace
|
||||
|
||||
WindowTestRunnerMac::WindowTestRunnerMac() {}
|
||||
|
||||
void WindowTestRunnerMac::SetPos(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
NSWindow* window = GetWindow(browser);
|
||||
|
||||
// Make sure the window isn't minimized or maximized.
|
||||
if ([window isMiniaturized]) {
|
||||
[window deminiaturize:nil];
|
||||
} else if ([window isZoomed]) {
|
||||
[window performZoom:nil];
|
||||
}
|
||||
|
||||
// Retrieve information for the display that contains the window.
|
||||
NSScreen* screen = [window screen];
|
||||
if (screen == nil) {
|
||||
screen = [NSScreen mainScreen];
|
||||
}
|
||||
NSRect frame = [screen frame];
|
||||
NSRect visibleFrame = [screen visibleFrame];
|
||||
|
||||
// Make sure the window is inside the display.
|
||||
CefRect display_rect(
|
||||
visibleFrame.origin.x,
|
||||
frame.size.height - visibleFrame.size.height - visibleFrame.origin.y,
|
||||
visibleFrame.size.width, visibleFrame.size.height);
|
||||
CefRect window_rect(x, y, width, height);
|
||||
ModifyBounds(display_rect, window_rect);
|
||||
|
||||
NSRect newRect;
|
||||
newRect.origin.x = window_rect.x;
|
||||
newRect.origin.y = frame.size.height - window_rect.height - window_rect.y;
|
||||
newRect.size.width = window_rect.width;
|
||||
newRect.size.height = window_rect.height;
|
||||
[window setFrame:newRect display:YES];
|
||||
}
|
||||
WindowTestRunnerMac::WindowTestRunnerMac() = default;
|
||||
|
||||
void WindowTestRunnerMac::Minimize(CefRefPtr<CefBrowser> browser) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
#include "tests/cefclient/browser/root_window_views.h"
|
||||
#include "tests/cefclient/browser/views_window.h"
|
||||
#include "tests/shared/browser/geometry_util.h"
|
||||
|
||||
namespace client::window_test {
|
||||
|
||||
@ -28,46 +29,39 @@ CefRefPtr<CefWindow> GetWindow(const CefRefPtr<CefBrowser>& browser) {
|
||||
return window;
|
||||
}
|
||||
|
||||
void SetTitlebarHeight(const CefRefPtr<CefBrowser>& browser,
|
||||
const std::optional<float>& height) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
auto root_window = RootWindow::GetForBrowser(browser->GetIdentifier());
|
||||
DCHECK(root_window.get());
|
||||
|
||||
auto root_window_views = static_cast<RootWindowViews*>(root_window.get());
|
||||
root_window_views->SetTitlebarHeight(height);
|
||||
void MinimizeImpl(CefRefPtr<CefBrowser> browser) {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, base::BindOnce(&MinimizeImpl, browser));
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
WindowTestRunnerViews::WindowTestRunnerViews() = default;
|
||||
|
||||
void WindowTestRunnerViews::SetPos(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
CefRefPtr<CefWindow> window = GetWindow(browser);
|
||||
|
||||
CefRect window_bounds(x, y, width, height);
|
||||
ModifyBounds(window->GetDisplay()->GetWorkArea(), window_bounds);
|
||||
|
||||
window->SetBounds(window_bounds);
|
||||
}
|
||||
|
||||
void WindowTestRunnerViews::Minimize(CefRefPtr<CefBrowser> browser) {
|
||||
GetWindow(browser)->Minimize();
|
||||
}
|
||||
|
||||
void WindowTestRunnerViews::Maximize(CefRefPtr<CefBrowser> browser) {
|
||||
void MaximizeImpl(CefRefPtr<CefBrowser> browser) {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, base::BindOnce(&MaximizeImpl, browser));
|
||||
return;
|
||||
}
|
||||
|
||||
GetWindow(browser)->Maximize();
|
||||
}
|
||||
|
||||
void WindowTestRunnerViews::Restore(CefRefPtr<CefBrowser> browser) {
|
||||
void RestoreImpl(CefRefPtr<CefBrowser> browser) {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, base::BindOnce(&RestoreImpl, browser));
|
||||
return;
|
||||
}
|
||||
|
||||
GetWindow(browser)->Restore();
|
||||
}
|
||||
|
||||
void WindowTestRunnerViews::Fullscreen(CefRefPtr<CefBrowser> browser) {
|
||||
void FullscreenImpl(CefRefPtr<CefBrowser> browser) {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, base::BindOnce(&FullscreenImpl, browser));
|
||||
return;
|
||||
}
|
||||
|
||||
auto window = GetWindow(browser);
|
||||
|
||||
// Results in a call to ViewsWindow::OnWindowFullscreenTransition().
|
||||
@ -78,10 +72,34 @@ void WindowTestRunnerViews::Fullscreen(CefRefPtr<CefBrowser> browser) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
WindowTestRunnerViews::WindowTestRunnerViews() = default;
|
||||
|
||||
void WindowTestRunnerViews::Minimize(CefRefPtr<CefBrowser> browser) {
|
||||
MinimizeImpl(browser);
|
||||
}
|
||||
|
||||
void WindowTestRunnerViews::Maximize(CefRefPtr<CefBrowser> browser) {
|
||||
MaximizeImpl(browser);
|
||||
}
|
||||
|
||||
void WindowTestRunnerViews::Restore(CefRefPtr<CefBrowser> browser) {
|
||||
RestoreImpl(browser);
|
||||
}
|
||||
|
||||
void WindowTestRunnerViews::Fullscreen(CefRefPtr<CefBrowser> browser) {
|
||||
FullscreenImpl(browser);
|
||||
}
|
||||
|
||||
void WindowTestRunnerViews::SetTitleBarHeight(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
const std::optional<float>& height) {
|
||||
SetTitlebarHeight(browser, height);
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
auto root_window = RootWindow::GetForBrowser(browser->GetIdentifier());
|
||||
auto root_window_views = static_cast<RootWindowViews*>(root_window.get());
|
||||
root_window_views->SetTitlebarHeight(height);
|
||||
}
|
||||
|
||||
} // namespace client::window_test
|
||||
|
@ -15,11 +15,6 @@ class WindowTestRunnerViews : public WindowTestRunner {
|
||||
public:
|
||||
WindowTestRunnerViews();
|
||||
|
||||
void SetPos(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) override;
|
||||
void Minimize(CefRefPtr<CefBrowser> browser) override;
|
||||
void Maximize(CefRefPtr<CefBrowser> browser) override;
|
||||
void Restore(CefRefPtr<CefBrowser> browser) override;
|
||||
|
@ -27,52 +27,13 @@ void Toggle(HWND root_hwnd, UINT nCmdShow) {
|
||||
}
|
||||
}
|
||||
|
||||
void SetPosImpl(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
HWND root_hwnd = GetRootHwnd(browser);
|
||||
if (!root_hwnd) {
|
||||
return;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Retrieve current window placement information.
|
||||
WINDOWPLACEMENT placement;
|
||||
::GetWindowPlacement(root_hwnd, &placement);
|
||||
WindowTestRunnerWin::WindowTestRunnerWin() = default;
|
||||
|
||||
// Retrieve information about the display that contains the window.
|
||||
HMONITOR monitor =
|
||||
MonitorFromRect(&placement.rcNormalPosition, MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFO info;
|
||||
info.cbSize = sizeof(info);
|
||||
GetMonitorInfo(monitor, &info);
|
||||
void WindowTestRunnerWin::Minimize(CefRefPtr<CefBrowser> browser) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
// Make sure the window is inside the display.
|
||||
CefRect display_rect(info.rcWork.left, info.rcWork.top,
|
||||
info.rcWork.right - info.rcWork.left,
|
||||
info.rcWork.bottom - info.rcWork.top);
|
||||
CefRect window_rect(x, y, width, height);
|
||||
WindowTestRunner::ModifyBounds(display_rect, window_rect);
|
||||
|
||||
if (placement.showCmd == SW_SHOWMINIMIZED ||
|
||||
placement.showCmd == SW_SHOWMAXIMIZED) {
|
||||
// The window is currently minimized or maximized. Restore it to the desired
|
||||
// position.
|
||||
placement.rcNormalPosition.left = window_rect.x;
|
||||
placement.rcNormalPosition.right = window_rect.x + window_rect.width;
|
||||
placement.rcNormalPosition.top = window_rect.y;
|
||||
placement.rcNormalPosition.bottom = window_rect.y + window_rect.height;
|
||||
::SetWindowPlacement(root_hwnd, &placement);
|
||||
::ShowWindow(root_hwnd, SW_RESTORE);
|
||||
} else {
|
||||
// Set the window position.
|
||||
::SetWindowPos(root_hwnd, nullptr, window_rect.x, window_rect.y,
|
||||
window_rect.width, window_rect.height, SWP_NOZORDER);
|
||||
}
|
||||
}
|
||||
|
||||
void MinimizeImpl(CefRefPtr<CefBrowser> browser) {
|
||||
HWND root_hwnd = GetRootHwnd(browser);
|
||||
if (!root_hwnd) {
|
||||
return;
|
||||
@ -80,7 +41,9 @@ void MinimizeImpl(CefRefPtr<CefBrowser> browser) {
|
||||
Toggle(root_hwnd, SW_MINIMIZE);
|
||||
}
|
||||
|
||||
void MaximizeImpl(CefRefPtr<CefBrowser> browser) {
|
||||
void WindowTestRunnerWin::Maximize(CefRefPtr<CefBrowser> browser) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
HWND root_hwnd = GetRootHwnd(browser);
|
||||
if (!root_hwnd) {
|
||||
return;
|
||||
@ -88,7 +51,9 @@ void MaximizeImpl(CefRefPtr<CefBrowser> browser) {
|
||||
Toggle(root_hwnd, SW_MAXIMIZE);
|
||||
}
|
||||
|
||||
void RestoreImpl(CefRefPtr<CefBrowser> browser) {
|
||||
void WindowTestRunnerWin::Restore(CefRefPtr<CefBrowser> browser) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
HWND root_hwnd = GetRootHwnd(browser);
|
||||
if (!root_hwnd) {
|
||||
return;
|
||||
@ -96,48 +61,4 @@ void RestoreImpl(CefRefPtr<CefBrowser> browser) {
|
||||
::ShowWindow(root_hwnd, SW_RESTORE);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
WindowTestRunnerWin::WindowTestRunnerWin() = default;
|
||||
|
||||
void WindowTestRunnerWin::SetPos(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
if (CURRENTLY_ON_MAIN_THREAD()) {
|
||||
SetPosImpl(browser, x, y, width, height);
|
||||
} else {
|
||||
// Execute on the main application thread.
|
||||
MAIN_POST_CLOSURE(base::BindOnce(SetPosImpl, browser, x, y, width, height));
|
||||
}
|
||||
}
|
||||
|
||||
void WindowTestRunnerWin::Minimize(CefRefPtr<CefBrowser> browser) {
|
||||
if (CURRENTLY_ON_MAIN_THREAD()) {
|
||||
MinimizeImpl(browser);
|
||||
} else {
|
||||
// Execute on the main application thread.
|
||||
MAIN_POST_CLOSURE(base::BindOnce(MinimizeImpl, browser));
|
||||
}
|
||||
}
|
||||
|
||||
void WindowTestRunnerWin::Maximize(CefRefPtr<CefBrowser> browser) {
|
||||
if (CURRENTLY_ON_MAIN_THREAD()) {
|
||||
MaximizeImpl(browser);
|
||||
} else {
|
||||
// Execute on the main application thread.
|
||||
MAIN_POST_CLOSURE(base::BindOnce(MaximizeImpl, browser));
|
||||
}
|
||||
}
|
||||
|
||||
void WindowTestRunnerWin::Restore(CefRefPtr<CefBrowser> browser) {
|
||||
if (CURRENTLY_ON_MAIN_THREAD()) {
|
||||
RestoreImpl(browser);
|
||||
} else {
|
||||
// Execute on the main application thread.
|
||||
MAIN_POST_CLOSURE(base::BindOnce(RestoreImpl, browser));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace client::window_test
|
||||
|
@ -16,11 +16,6 @@ class WindowTestRunnerWin : public WindowTestRunner {
|
||||
public:
|
||||
WindowTestRunnerWin();
|
||||
|
||||
void SetPos(CefRefPtr<CefBrowser> browser,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) override;
|
||||
void Minimize(CefRefPtr<CefBrowser> browser) override;
|
||||
void Maximize(CefRefPtr<CefBrowser> browser) override;
|
||||
void Restore(CefRefPtr<CefBrowser> browser) override;
|
||||
|
@ -7,6 +7,12 @@
|
||||
:fullscreen {
|
||||
background: pink;
|
||||
}
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.mono {
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function setup() {
|
||||
@ -74,11 +80,66 @@ function setTitlebarHeight() {
|
||||
else
|
||||
send_message('TitlebarHeight', height);
|
||||
}
|
||||
|
||||
function execWindowAction() {
|
||||
const dx = parseInt(document.getElementById('window_dx').value);
|
||||
const dy = parseInt(document.getElementById('window_dy').value);
|
||||
if (isNaN(dx) || isNaN(dy)) {
|
||||
alert('Please specify a valid numeric value.');
|
||||
return;
|
||||
}
|
||||
|
||||
const e = document.getElementById("window_action");
|
||||
const option = e.options[e.selectedIndex].text;
|
||||
switch (option) {
|
||||
case "moveTo":
|
||||
return window.moveTo(dx, dy);
|
||||
case "moveBy":
|
||||
return window.moveBy(dx, dy);
|
||||
case "resizeTo":
|
||||
return window.resizeTo(dx, dy);
|
||||
case "resizeBy":
|
||||
return window.resizeBy(dx, dy);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body bgcolor="white" onload="setup()">
|
||||
<form id="form">
|
||||
Click a button to perform the associated window action.
|
||||
<p class="bold">Click a button to perform the associated window action.</p>
|
||||
<p>Input values are in DIP coordinates. See <a href="https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-coordinate-systems" target="_new">here</a> for important details about coordinate systems and window behavior.</p>
|
||||
<details>
|
||||
<summary>Implementation details for cefclient (click to expand).</summary>
|
||||
<ul>
|
||||
<li>The below actions will configure window size (<span class="mono">window.outerWidth/Height</span>) and position (<span class="mono">window.screenX/Y</span>) as reported by browser content (see "Current window settings" below).</li>
|
||||
<li>Whether this calculation includes the window frame will depend on what information is known/provided to CEF.</li>
|
||||
<ul>
|
||||
<li>Views-hosted windows are sized/positioned relative to the CefWindow frame.</li>
|
||||
<li>Native windows (<span class="mono">--use-native</span>) are sized/positioned relative to the cefclient window frame.</li>
|
||||
<ul>
|
||||
<li>MacOS windows are sized/positioned relative to the parent NSWindow frame (default behavior).</li>
|
||||
<li>Windows windows are sized/positioned relative to the root HWND frame (default behavior).</li>
|
||||
<li>Linux windows are sized/positioned relative to CefDisplayHandler::GetRootWindowScreenRect.</li>
|
||||
</ul>
|
||||
<li>Windowless (off-screen) windows (<span class="mono">--off-screen-rendering-enabled</span>) are sized/positioned relative to CefRenderHandler::GetRootScreenRect.</li>
|
||||
<ul>
|
||||
<li>Pass <span class="mono">--fake-screen-bounds</span> to instead size/position relative to the browser content area.
|
||||
This will also report (0,0) for position.</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<li>Exiting and relaunching cefclient will save/restore window bounds as DIP coordinates in all modes.</li>
|
||||
<li>The <span class="mono">window.devicePixelRatio</span> value is a combination of device scale factor and browser zoom (if not 100%).</li>
|
||||
<ul>
|
||||
<li>Default device scale factor will match the associated display (e.g. user/system-level display settings).</li>
|
||||
<li>Device scale factor can be configured via command-line (<span class="mono">--force-device-scale-factor=[float]</span>) or the "Tests > Set Scale Factor" menu option with windowless rendering.</li>
|
||||
<ul>
|
||||
<li>MacOS custom device scale factor will impact rendering quality only. DIP coordinates are not impacted.</li>
|
||||
<li>Windows/Linux custom device scale factor will impact rendering quality and DIP coordinates.</li>
|
||||
</ul>
|
||||
<li>Browser zoom can be configured via the Chrome menu or "Tests > Zoom In/Out/Reset" menu options.
|
||||
</ul>
|
||||
</ul>
|
||||
</details>
|
||||
<br/><input type="button" onclick="minimize();" value="Minimize">
|
||||
<br/><input type="button" onclick="maximize();" value="Maximize">
|
||||
<br/><input type="button" onclick="restore();" value="Restore"> (minimizes and then restores the window as topmost)
|
||||
@ -86,11 +147,55 @@ Click a button to perform the associated window action.
|
||||
<br/><input type="button" onclick="fullscreenBrowser();" value="Toggle Browser Fullscreen"> (uses <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API" target="_new">Fullscreen API</a>; background turns pink)
|
||||
<br/><input type="button" onclick="position();" value="Set Position">
|
||||
X: <input type="text" size="4" id="x" value="200">
|
||||
Y: <input type="text" size="4" id="y" value="100">
|
||||
Y: <input type="text" size="4" id="y" value="200">
|
||||
Width: <input type="text" size="4" id="width" value="800">
|
||||
Height: <input type="text" size="4" id="height" value="600">
|
||||
<br/><input type="button" onclick="setTitlebarHeight();" value="Set Titlebar Height">
|
||||
<input type="number" min="0" max="100" id="title_bar_height" value="50"> (works on macOS with Views)
|
||||
<br/><input type="button" onclick="execWindowAction();" value="Execute JavaScript"> window.<select id="window_action">
|
||||
<option>moveTo</option>
|
||||
<option>moveBy</option>
|
||||
<option>resizeTo</option>
|
||||
<option>resizeBy</option>
|
||||
</select>(<input type="text" size="4" id="window_dx" value="200">,<input type="text" size="4" id="window_dy" value="200">) (calls CefDisplayHandler::OnContentsBoundsChange)
|
||||
</form>
|
||||
<p class="bold">Current window settings:</p>
|
||||
<div id="size"></div>
|
||||
<script>
|
||||
function reportDimensions() {
|
||||
document.getElementById('size').innerHTML =
|
||||
`DIP coordinates:` +
|
||||
`<br/>window.screen.width/height: ${window.screen.width} x ${window.screen.height}` +
|
||||
`<br/>window.outerWidth/Height: ${window.outerWidth} x ${window.outerHeight}` +
|
||||
`<br/>window.screenX/Y: x=${window.screenX}, y=${window.screenY}` +
|
||||
`<br/><br/>CSS pixels:` +
|
||||
`<br/>window.innerWidth/Height: ${window.innerWidth} x ${window.innerHeight}` +
|
||||
`<br/>window.devicePixelRatio: ${window.devicePixelRatio.toFixed(2)}`;
|
||||
}
|
||||
|
||||
// Observe window resize events.
|
||||
window.addEventListener('resize', function() { console.log('resize'); reportDimensions(); });
|
||||
|
||||
if (window.onmove) {
|
||||
// Observe window move events.
|
||||
// Only available with --enable-experimental-web-platform-features.
|
||||
window.addEventListener('move', reportDimensions);
|
||||
} else {
|
||||
// Poll for window movement.
|
||||
var last_x = window.screenX;
|
||||
var last_y = window.screenY;
|
||||
setInterval(function() {
|
||||
const x = window.screenX;
|
||||
const y = window.screenY;
|
||||
if (x != last_x || y != last_y) {
|
||||
last_x = x;
|
||||
last_y = y;
|
||||
reportDimensions();
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
reportDimensions();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -42,4 +42,21 @@ void DeviceToLogical(CefTouchEvent& value, float device_scale_factor) {
|
||||
value.y = DeviceToLogical(value.y, device_scale_factor);
|
||||
}
|
||||
|
||||
void ConstrainWindowBounds(const CefRect& display, CefRect& window) {
|
||||
if (window.x < display.x) {
|
||||
window.x = display.x;
|
||||
}
|
||||
if (window.y < display.y) {
|
||||
window.y = display.y;
|
||||
}
|
||||
window.width = std::clamp(window.width, 100, display.width);
|
||||
window.height = std::clamp(window.height, 100, display.height);
|
||||
if (window.x + window.width >= display.x + display.width) {
|
||||
window.x = display.x + display.width - window.width;
|
||||
}
|
||||
if (window.y + window.height >= display.y + display.height) {
|
||||
window.y = display.y + display.height - window.height;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@ -20,6 +20,10 @@ CefRect DeviceToLogical(const CefRect& value, float device_scale_factor);
|
||||
void DeviceToLogical(CefMouseEvent& value, float device_scale_factor);
|
||||
void DeviceToLogical(CefTouchEvent& value, float device_scale_factor);
|
||||
|
||||
// Fit |window| inside |display|. Coordinates are relative to the upper-left
|
||||
// corner of the display.
|
||||
void ConstrainWindowBounds(const CefRect& display, CefRect& window);
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_SHARED_BROWSER_GEOMETRY_UTIL_H_
|
||||
|
@ -24,6 +24,7 @@ const char kOffScreenRenderingEnabled[] = "off-screen-rendering-enabled";
|
||||
const char kOffScreenFrameRate[] = "off-screen-frame-rate";
|
||||
const char kTransparentPaintingEnabled[] = "transparent-painting-enabled";
|
||||
const char kShowUpdateRect[] = "show-update-rect";
|
||||
const char kFakeScreenBounds[] = "fake-screen-bounds";
|
||||
const char kSharedTextureEnabled[] = "shared-texture-enabled";
|
||||
const char kExternalBeginFrameEnabled[] = "external-begin-frame-enabled";
|
||||
const char kMouseCursorChangeDisabled[] = "mouse-cursor-change-disabled";
|
||||
|
@ -18,6 +18,7 @@ extern const char kOffScreenRenderingEnabled[];
|
||||
extern const char kOffScreenFrameRate[];
|
||||
extern const char kTransparentPaintingEnabled[];
|
||||
extern const char kShowUpdateRect[];
|
||||
extern const char kFakeScreenBounds[];
|
||||
extern const char kSharedTextureEnabled[];
|
||||
extern const char kExternalBeginFrameEnabled[];
|
||||
extern const char kMouseCursorChangeDisabled[];
|
||||
|
Reference in New Issue
Block a user