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:
Marshall Greenblatt
2025-04-23 20:33:07 -04:00
parent f59112d839
commit faa85bf980
68 changed files with 1725 additions and 700 deletions

View File

@@ -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();
return false;
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,
device_scale_factor_);
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;
}
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.
screen_info.rect = view_rect;
screen_info.available_rect = view_rect;
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);
// Keep HTML select popups inside the view rectangle.
screen_info.rect = view_rect;
screen_info.available_rect = view_rect;
}
return true;
}