Gnoblin

window_frames

Configuration API

Most apps draw their own titlebar and buttons. This is client-side decoration (CSD). Gnoblin can draw them instead: server-side decoration (SSD).

window_management.action_*_titlebar sets Mutter's titlebar action preferences. GTK apps typically draw their own titlebars and read GNOME settings directly, so this Lua setting does not change their client-side decoration (CSD) behavior.

Gnoblin's built-in fallback server-side decoration (SSD) supports these actions:

  • toggle-maximize
  • toggle-maximize-horizontally
  • toggle-maximize-vertically
  • minimize
  • lower
  • menu
  • none

A custom SSD renderer implements its own titlebar click behavior.

Use frame.button_layout to choose the right-side buttons in Gnoblin's native frame and its fallback. External renderers use their own settings. window_management.button_layout does not change these titlebars. See titlebar button placement.

The embedded default config enables Gnoblin's built-in native renderer with mode = "auto" and extents {32, 1, 1, 1}. Apps keep their own titlebars; apps requesting server decorations get a native frame. It needs no desktop shell or external renderer. The default config disables animations.

Use mode to decide which windows get a frame and renderer to choose what draws it. Setting a renderer alone does not enable frames. A config without a frame rule retains the API default, "off".

Run gnoblinctl config restore-default to replace your config with the current embedded defaults; Gnoblin backs up your previous config. To keep your other settings, add the frame rule below instead.

Choose a mode

Mode Behavior
off Let the app draw its titlebar; add no frame or cropping
auto Add a frame only when the app explicitly asks for one
prefer-server Prefer a Gnoblin frame for apps that support decoration negotiation
replace Hide the configured app margins and draw a Gnoblin frame

Apps negotiate decorations through Wayland decoration protocols. GTK on Wayland uses KDE's server-decoration protocol; other clients commonly use xdg-decoration. Gnoblin supports server decorations through both. GTK windows that create the KDE decoration object use auto behavior by default, so Gnoblin's native renderer supplies their frame. A matching Lua window rule can select another mode. auto uses client requests instead of guessing from appearance.

X11 apps count as asking for a server frame when they do not turn decorations off with _MOTIF_WM_HINTS; with no rule they use auto. The frame is drawn by the compositor around the client, so _NET_FRAME_EXTENTS reports Gnoblin's border and client_type = "x11" in a rule match selects only these windows.

GTK apps with a custom titlebar can still draw titlebar controls inside their surface. Gnoblin applies its frame and clips declared client shadow margins, but it cannot identify arbitrary pixels inside an app surface as a border without risking removal of app content. corners.remove_csd reconstructs detected client-rounded corners before applying Gnoblin's shape.

With prefer-server, Gnoblin uses the app's declared visible bounds when the app keeps CSD. It clips buffer margins outside those bounds and draws Gnoblin's configured border and shadow around them. Apps that omit visible bounds use the full surface.

Let apps request a Gnoblin titlebar

Add this to ~/.config/gnoblin/init.lua after any gnoblin.load(...) lines:

Lua
gnoblin.window_rule {
    match = {type = "window"},
    frame = {
        mode = "auto",
        renderer = "native",
        extents = {36, 0, 0, 0},
    },
}

This uses the built-in renderer with a 36-pixel titlebar and no side or bottom border. extents lists top, right, bottom and left sizes in that order.

Save and run gnoblinctl config reload. The app must also update its Wayland surface before a decoration change takes effect; if it does not change, reopen the app. Apps that draw their own titlebars can look unchanged under auto.

Frame options

All fields below go inside frame. Later matching rules override individual fields. Sizes are logical pixels.

Field Default Values
mode "off" Modes listed above
extents {32, 1, 1, 1} Top/right/bottom/left frame size; integers 0–256
crop {0, 0, 0, 0} Removed client margins; same order and range
renderer "native" Registered service name
style "default" Style understood by that renderer
background "#242424" Active background colour
foreground "#eeeeee" Foreground colour
inactive_background "#303030" Unfocused background colour
button_layout {"minimize", "maximize", "close"} Native-frame buttons, without duplicates; {} hides them

Colours accept #RRGGBB or #RRGGBBAA. Renderer and style names accept 1–64 letters, digits, _ or -.

Cropping client decorations

The crop option hides a strip of the app and makes that strip unclickable. It cannot distinguish a titlebar from tabs, search boxes or other controls. Use it only when you know exactly which margins you want to hide.

With prefer-server, the declared visible bounds are cropped automatically when an app keeps CSD; crop adds extra margins in that case. Negotiated SSD clients use their own declared bounds and ignore crop. With replace, zero extents give a crop-only window. Fullscreen temporarily removes explicit crop and frame extents.

Custom renderers

Register the renderer command, then select its name in a rule:

Lua
gnoblin.configure {
    frame_renderers = {
        cairo = {"gnoblin-frame-cairo"},
    },
}

gnoblin.window_rule {
    match = {type = "window"},
    frame = {mode = "auto", renderer = "cairo"},
}

Use a command name resolved through the compositor's PATH, followed by separate arguments. A full executable path is also accepted. native is reserved. Bingux supplies its own styled renderer.

Config reload restarts external renderers, including rebuilt executables at unchanged paths. The native frame keeps controls available during replacement or failure. A compositor upgrade still needs logout and login.

Limits

Frames work on normal Wayland application windows (xdg-toplevel) and on X11 apps running through Xwayland, which have the same frame, rules, effects and input as Wayland windows. They do not apply to popups, menus, bars or launchers.

An X11 app can ask for its frame size (_NET_REQUEST_FRAME_EXTENTS) before the window exists, when no rule can match its title or application. Gnoblin answers with the rules that match only type = "window" and client_type; the real size is set when the window is managed.

Text input, client-driven background blur and activation tokens come from Wayland protocols, so X11 apps do not use them. Moving framed windows between displays with different scales and cropping apps with many popups have limited test coverage.

Wayland window effects exclude transparent buffer margins outside the client's declared window geometry. Borders and shadows include Gnoblin's server frame. When an app uses Gnoblin's frame, corners.radius rounds the whole window, frame and content, even in auto mode, so square app content never shows outside the frame's corners.

States where rounding is off, such as maximised with keep_maximized = false, make both the frame and the content square.

Popup positions use the parent window's client origin, excluding Gnoblin's frame extents and accounting for cropped margins. This also applies when a popup acknowledges its configuration or follows a moved parent.

For renderer implementation and tests, see renderer architecture and the author guide.

Esc

Try