[Windows] hiddenInset windows maximize over the taskbar (missing WS_MAXIMIZEBOX)
Related: #417 proposed exactly this fix against 1.x and was closed as "implemented in Electrobun 2.0" — the
IsNonClientRegionSupportEnabledhalf did land, but theWS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENUhalf did not (verified in the v2.0.1 and current-mainnativeWrapper.cpp: thehiddenInsetstyle isWS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN | WS_CLIPSIBLINGSonly). #395 and #226 covered the"hidden"/popup variant; thehiddenInsetmaximize path appears unreported so far.
Summary
Since the (much appreciated!) hiddenInset frameless support landed on Windows (#319/#320, #363), a window created with titleBarStyle: "hiddenInset" maximizes to the monitor bounds instead of the work area — the bottom of the window ends up behind the taskbar.
Root cause: the hiddenInset window style omits WS_MAXIMIZEBOX (and WS_MINIMIZEBOX/WS_SYSMENU), and Windows only applies the work-area adjustment during SW_MAXIMIZE when the window has WS_MAXIMIZEBOX.
Environment
- Electrobun v2.0.1 (same code on current
main) - Windows 11 x64, WebView2 renderer, 125% DPI
- Window created with
titleBarStyle: "hiddenInset"
Measured behavior
Window style of a hiddenInset window:
GWL_STYLE = 0x16C40000 = WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE(125% DPI (120), monitor 1536x864 physical, work area 1536x816, taskbar 48px)
A) As shipped (no WS_MAXIMIZEBOX) — window maximized:
Window : (-7,-7)-(1543,871) <- monitor bounds + 7px frame overhang
Client : (0,0)-(1536,864) <- 48px of content behind the taskbarB) Same window after adding WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX at runtime (SetWindowLongPtr + SWP_FRAMECHANGED), then restore + maximize:
Window : (-7,-7)-(1543,823) <- work area + 7px frame overhang
Client : (0,0)-(1536,816) <- exactly the work area, nothing behind the taskbarThe WebView2 child follows the client rect in both cases, so the visible web content is what overlaps the taskbar in case A.
Suggested fix
In package/src/native/win/nativeWrapper.cpp, the hiddenInset branch of window creation:
windowStyle = WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;add the missing style bits:
windowStyle = WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
| WS_CLIPCHILDREN | WS_CLIPSIBLINGS;This should also, for free (as #417 anticipated):
- enable the native caption double-click maximize/restore toggle (currently inert —
DefWindowProcignoresWM_NCLBUTTONDBLCLKonHTCAPTIONwithoutWS_MAXIMIZEBOX; since WebView2'sIsNonClientRegionSupportEnabledalready routesapp-region: dragregions asHTCAPTION, drag-region double-clicks would start toggling natively), - restore Aero Snap / Aero Shake / the Alt+Space system menu, and
- restore native minimize/maximize animations.
Two smaller follow-ups while in this area (happy to file separately if preferred):
- Top edge not resizable: the
WM_NCCALCSIZEhandler forChromeStyle::HiddenInsetrestoresrgrc[0].top = original.top, which folds the top resize border into the client —WM_NCHITTESTon the top edge returnsHTCLIENT(left/right/bottom edges and all four corners work). Stripping only the caption height (or re-exposing the top edge viaWM_NCHITTEST) would fix it. WM_GETMINMAXINFOclamp: the existing work-area clamp only applies toWS_POPUPwindows; it's what makes"hidden"maximize correctly today. With the style bits added tohiddenInsetthe default work-area behavior kicks in, but it may be worth handling explicitly like the popup path.
Workaround in the meantime
We've stayed on titleBarStyle: "hidden" (bare WS_POPUP) because its maximize is clamped to the work area by the WM_GETMINMAXINFO handler — at the cost of losing everything the hiddenInset frame provides: edge-resize cursors, the Windows 11 rounded corners, and the DWM drop shadow. All of it comes back with the style-bits fix above.
Happy to test any changes on Windows if that helps — thanks for the great work on 2.0!
Activity
0No activity yet.