Skip to content

fix(windows): position child host windows in parent-client coordinates - #16

Merged
Y-PLONI merged 1 commit into
Otzaria:masterfrom
palmoni5:fix/windows-child-host-position
Aug 29, 2026
Merged

fix(windows): position child host windows in parent-client coordinates#16
Y-PLONI merged 1 commit into
Otzaria:masterfrom
palmoni5:fix/windows-child-host-position

Conversation

@palmoni5

Copy link
Copy Markdown
Member

Problem

Porting upstream PR pichillilorenzo#2768 (c568a24e) turned the three internal WebView host HWNDs into WS_CHILD windows. InAppWebView::setPosition was not adjusted and kept passing screen coordinates to SetWindowPos:

GetWindowRect(flutterWindowHWnd, &flutterWindowRect);
::SetWindowPos(webViewHWnd, nullptr,
  flutterWindowRect.left + scaled_x - borderWidth,
  flutterWindowRect.top  + scaled_y - titleBarHeight, ...);

That was correct for the previous owned top-level host. For a child window SetWindowPos takes coordinates relative to the parent's client area, so the host window ends up offset by the Flutter window's screen origin.

Everything the host window owns moves with it: <select> dropdowns, the print preview printer/color pickers, and context menus all open away from the WebView. Because the error tracks the window position, it changes as the window is moved or resized and reads as intermittent. Keyboard navigation is unaffected (no coordinates involved), which hides the cause.

Measured on a real app window (client origin (42,133)), the host HWND sat at (79,275) — offset by exactly the window origin plus the frame fudge.

Fix

Pass the widget offset as-is. This also removes the hand-rolled frame arithmetic (GetWindowRect + SM_CYCAPTION/SM_CYFRAME/SM_CXPADDEDBORDER), which mis-measured borderless windows and was never DPI-correct — it used GetSystemMetrics rather than GetSystemMetricsForDpi.

::SetWindowPos(webViewHWnd, nullptr, scaled_x, scaled_y, 0, 0,
  SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);

Testing

  • native_host_window_position_test.dart — new, source-scanning in the same style as native_host_window_style_test.dart: asserts setPosition positions by scaled_x/scaled_y and does not reintroduce screen-space APIs.
  • Verified at runtime in a Flutter Windows host: <select> dropdowns and the WebView2 print preview pickers open in the right place again.

Note for hosts on a mirrored window: a parent with WS_EX_LAYOUTRTL measures child coordinates from the right edge, so that style has to be off for child-relative positioning to land correctly.

Porting upstream PR pichillilorenzo#2768 turned the three internal WebView host HWNDs into WS_CHILD windows, but InAppWebView::setPosition kept passing screen coordinates to SetWindowPos. Those were correct for the previous owned top-level host, and are wrong for a child window, whose coordinates are relative to the parent client area.

The host window therefore sat offset by the Flutter window origin, and every popup it owns went with it: <select> dropdowns, the print preview printer/color pickers and context menus all opened away from the WebView. The offset shifted with the window position, so it looked intermittent. Keyboard navigation was unaffected, which hid the cause.

setPosition now passes the widget offset as-is. This also drops the hand-rolled frame arithmetic (GetWindowRect plus SM_CYCAPTION/SM_CYFRAME/SM_CXPADDEDBORDER), which mis-measured borderless windows and was never DPI-correct. Adds native_host_window_position_test.dart alongside the existing WS_CHILD coverage.
@Y-PLONI
Y-PLONI merged commit 9a51795 into Otzaria:master Aug 29, 2026
1 check passed
@palmoni5
palmoni5 deleted the fix/windows-child-host-position branch August 29, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants