A custom window frame looks like a small job until you notice that "where do the window buttons go" has three different right answers, and one of them is not knowable in advance.
appframe draws the title bar in Compose and wires up the real window controls underneath. Most of the work is not drawing.
Two platforms tell you
macOS puts the traffic lights on the left. Windows puts minimize, maximize and close on the right. Both are stable conventions, so both are a lookup on the host OS.
The details are where it stops being a lookup:
- Windows 11 has specific button metrics, including the red hover on close. Get the width wrong and it reads as a knock-off immediately.
- The macOS lights dim when the window loses focus and only reveal their glyphs on hover.
- The green button is not maximize. It goes fullscreen, and treating it as maximize is one of the tells that an app was ported rather than written for the platform.
- Corners are rounded on macOS and squared off again the moment the window is maximized or fullscreen.
Linux does not
There is no Linux convention. GNOME ships with close only, on the right. KDE and XFCE put three on the right. elementary OS puts them on the left, as did the old Unity layout.
You cannot infer this from the distribution, and you should not try. The desktop already knows, and it will tell you:
org.gnome.desktop.wm.preferences button-layout
That setting decides both the side and which buttons exist at all — which is why a hardcoded three-button layout looks wrong on a stock GNOME desktop rather than merely misplaced. appframe reads it and lays out accordingly, falling back to the right-hand layout when the setting cannot be read.
This is the whole point of the library, compressed into one sentence: the environment is the source of truth, and asking it is cheaper than modelling it.
Maximize is not resize
The other thing that separates a real title bar from a drawn one is what maximize does. Setting the window to the screen bounds covers the taskbar and misbehaves across monitors. WindowPlacement.Maximized hands the decision to the window manager, which knows about docks and about the monitor the window is actually on.
Double-clicking the title bar toggles it, because that is what a title bar does.
What it deliberately does not have
No icon dependency. Every glyph is drawn with Canvas, so adding a window frame does not add a font or an icon pack to your build.
No theme of its own either — it takes Material 3 colours from whatever MaterialTheme it finds itself in, and it is a drop-in replacement for the Window block you already have.
Source: github.com/youndie/appframe