# wayland-bar-compositor A Wayland compositor written in jolt directly on wlroots, for putting a Wayland panel (such as `cosmic-panel`) onto an X11 desktop. There is no shared object here: `jolt.ffi` binds libwlroots, libwayland-server, libxkbcommon, libX11, libXext and libXi directly. The compositor opens one wlroots X11 output, draws layer-shell and xdg-shell clients through the wlroots scene graph, and forwards pointer and keyboard input to them. Because it owns the scene, it shapes its own X11 window: the bar strip plus the outline of whatever popups are mapped, traced from the rendered frame so rounded corners show the desktop behind them. XInput2 raw button presses on the root window let a click on an X11 app close open popups. wayland-bar-compositor the compositor build generates offsets.edn from the installed headers gen-offsets.c the offsetof dump build compiles offsets.edn wlroots struct layout facts, read at startup protocol/ wlr-layer-shell XML for the header wlroots omits ## Running ```bash ./build # after any wlroots update WLR_BACKENDS=x11 WLR_RENDERER=pixman \ ./wayland-bar-compositor --size 1920x640 --strip 0,0,1920,40 --title my-bar -- cosmic-panel ``` `--size` is the whole output, bar plus room for popups; `--strip` is the part always shown; `--title` names the X11 window so a launcher can find it and dock it (`_NET_WM_WINDOW_TYPE_DOCK` plus a strut). Set `WBC_DEBUG=1` to log input, popups and shape changes. ## Why a compositor in jolt works Every wlroots listener shares one native callback that dispatches on the listener's address, and listeners come from a free list, so surfaces that come and go don't leak callbacks. The event loop is `wl_event_loop_dispatch` called from jolt's own thread, so every callback arrives on that thread — nothing blocks the collector. wlroots changes struct layouts between minor versions, which is why the offsets are generated from the headers rather than written by hand. Written for wlroots 0.20 on x86_64. On a native Wayland desktop — COSMIC with cosmic-comp, for one — none of this is needed: the panel runs directly.