fix: hiddenInset frameless window on Windows#363
fix: hiddenInset frameless window on Windows#363255doesnotexist wants to merge 3 commits intoblackboardsh:mainfrom
Conversation
- Use WS_CAPTION | WS_THICKFRAME instead of WS_POPUP to preserve system resize borders and DWM shadow. - Handle WM_NCCALCSIZE to remove the caption bar area while keeping the frame for resizing. - Trigger SWP_FRAMECHANGED after SetWindowLongPtr so the frame recalculates with the new handler in place.
There was a problem hiding this comment.
Pull request overview
Updates Windows titleBarStyle: "hiddenInset" handling to achieve a truly frameless look while keeping standard DWM shadow and resize behavior.
Changes:
- Adds an
isHiddenInsetflag to per-window state to enable conditional non-client handling. - Switches
hiddenInsetwindow styles toWS_CAPTION | WS_THICKFRAMEand customizesWM_NCCALCSIZEto remove the caption area. - Forces a non-client recalculation (
SWP_FRAMECHANGED) after userdata is attached so the newWM_NCCALCSIZElogic applies.
| case WM_NCCALCSIZE: | ||
| if (wParam == TRUE) { | ||
| WindowData* data = (WindowData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); | ||
| if (data && data->isHiddenInset) { | ||
| NCCALCSIZE_PARAMS* p = (NCCALCSIZE_PARAMS*)lParam; | ||
| RECT original = p->rgrc[0]; | ||
| LRESULT ret = DefWindowProc(hwnd, msg, wParam, lParam); | ||
| p->rgrc[0].top = original.top; | ||
| return ret; |
There was a problem hiding this comment.
WM_NCCALCSIZE: resetting rgrc[0].top to the original window top removes not only the caption height but also the top resize border (and in maximized state can push the client area into the hidden/negative frame bounds, causing clipped content at the top). Consider preserving the top resize border thickness and only removing the caption portion, and special-casing maximized windows so the client rect stays within the monitor work area.
|
|
||
| case WM_NCCALCSIZE: | ||
| if (wParam == TRUE) { | ||
| WindowData* data = (WindowData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); |
There was a problem hiding this comment.
WM_NCCALCSIZE handler re-fetches and re-declares WindowData* data, shadowing the variable already loaded at the top of WindowProc. This is redundant and makes the control flow harder to follow; reuse the existing data pointer.
| WindowData* data = (WindowData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); |
|
updated: maximized state now clamps the client area to the monitor work area instead of letting the caption bar show through.
verified in a real app: no top residue in normal mode and no caption bar leak when maximized. |
remind the implementation refered in this reply is not active now. we use ChromeStyle enum instead.regarding `isHiddenInset` in `WindowData`:it's a per-window bool flag used inside the message loop to decide whether
during window creation ( |
moves the per window chrome style flag from a single use bool to an explicit enum class. this matches the ts titleBarStyle type and makes it trivial to add new styles later without adding more booleans to WindowData. ChromeStyle lives in shared/callbacks.h since it is cross platform and already included by all three native wrappers.
|
follow up refactor on top of the fix: replaced the one off
|
|
this pr partially resolves #320 and #226. #320 (reported by @Andreas-Froyland): the hiddenInset residue and broken frame behavior on Windows is addressed by keeping the system DWM frame (WS_CAPTION | WS_THICKFRAME) and stripping only the caption bar in WM_NCCALCSIZE. four edge resize, shadow, and window snapping all work. the maximize/fullscreen confusion mentioned in #226 (reported by @deeivihh) is also fixed: maximized windows now clamp to the monitor work area instead of covering the taskbar. cc @YoavCodes for review. |
problem
on windows, `titleBarStyle: "hiddenInset"` currently uses `WS_POPUP | WS_THICKFRAME`. this leaves a ~2-4px caption bar residue at the top. and another choice `titleBarStyle: "hidden"` drops the DWM shadow, while resize borders behave inconsistently.
root cause
`WS_POPUP | WS_THICKFRAME` tells the window manager to draw a thickframe without a caption, but windows still reserves a small non-client area at the top. without handling `WM_NCCALCSIZE`, that residue stays. `WS_POPUP` also disables the standard DWM frame entirely.
comparison with other frameworks
this patch aligns with the electron approach: keep the system frame for shadow and resize, then surgically remove only the caption area in `WM_NCCALCSIZE`.
fix
verification