WindowControlsOverlay
A desktop PWA that draws its own title bar needs to know where the OS window controls are - this is the geometry, and the event that fires when it changes.
@inject Bit.Butil.WindowControlsOverlay overlayMDN reference
"display_override": ["window-controls-overlay"], and the user can switch it off from
the app's own menu. In a browser tab IsVisible is false and the geometry is all
zeros - which is exactly what you should design for.
titlebar-area-x,
titlebar-area-y, titlebar-area-width and
titlebar-area-height environment variables, and app-region: drag marks
the part of your header that moves the window. Use CSS for the layout and this service for the
logic that CSS cannot express.
Supported is not the same as visible: a supporting browser still reports an invisible overlay for a page running in a tab. During prerender/SSR both return false rather than throwing.
@inject Bit.Butil.WindowControlsOverlay overlay
if (await overlay.IsVisible())
{
// we are drawing our own title bar
}The rectangle your own content may use. It starts after the window controls on the leading side and stops before them on the trailing side, which is why X is not always zero - a toolbar that ignores it ends up underneath the close button.
var rect = await overlay.GetTitlebarAreaRect();
// rect.X is the left edge you may draw from,
// rect.Width how much room you have, rect.Height how tall the bar is.Fires when the window is resized and when the user toggles the overlay, and once immediately with the current geometry so a subscriber can lay out before anything changes. Dispose the returned subscription.
_sub = await overlay.OnGeometryChange(geometry =>
{
_titlebarPadding = geometry.X;
InvokeAsync(StateHasChanged);
});API reference
ValueTask<bool> IsSupported()ValueTask<bool> IsVisible()ValueTask<WindowControlsOverlayGeometry> GetTitlebarAreaRect()Task<ButilSubscription> OnGeometryChange(Action<WindowControlsOverlayGeometry> handler)ValueTask DisposeAsync()