Gnoblin

files_and_load_order

Configuration reference

Start with one init.lua. Split it into modules when that makes it easier to read.

Which file is loaded?

gnoblinctl config path prints the main config file used by your running session.

The usual path is ~/.config/gnoblin/init.lua, or $XDG_CONFIG_HOME/gnoblin/init.lua when that variable is set. The compositor's GNOBLIN_CONFIG environment variable overrides it.

Without that override, Gnoblin checks init.lua, then the old gnoblin.toml and gnoblin.conf names. Those names are detected only so Gnoblin can report that the file must be converted; TOML and CONF are not parsed. Rename or remove an old file after converting it to Lua. Every selected root and included configuration file must use the .lua suffix.

When no user config exists, the session supervisor loads the starter Lua configuration embedded in the binary, followed by the system drop-ins. Run gnoblinctl init to create an editable copy at the selected config path. The command leaves existing files unchanged. Setting GNOBLIN_CONFIG in a terminal does not change the environment of an already-running compositor.

System drop-ins

Packages and administrators can add configuration for every user without touching anyone's init.lua. Gnoblin loads these .lua files itself; nobody needs to add a gnoblin.load line for them.

Gnoblin looks in these directories, in this order:

  1. gnoblin/conf.d/ inside each directory of XDG_DATA_DIRS, such as /usr/share/gnoblin/conf.d/. The default is /usr/local/share:/usr/share. XDG_DATA_DIRS lists the highest priority first, so Gnoblin loads the last entry first and the first entry last. When two packages set the same value, the first entry wins.
  2. /etc/gnoblin/conf.d/, for settings that belong to this machine. It loads after every package.

Files inside one directory load in filename order (byte order). Name them 10-name.lua, 90-name.lua and so on to control the sequence. A directory that does not exist is skipped. Names that start with a dot, files without the .lua suffix and subdirectories are ignored; a drop-in can still load its own parts with gnoblin.load("parts/extra.lua"), relative to the drop-in file.

Where the drop-ins fit depends on whether you have your own init.lua:

Your config Order
No init.lua Built-in defaults, then system drop-ins
An init.lua of your own System drop-ins, then your init.lua and the files it loads

Whatever loads later replaces earlier values. A package can change a built-in default, and your own config can change what a package set.

A copy of the starter files made with gnoblinctl init is part of your own config. If it contains a rule that a package also sets, your copy overrides the package. Delete that rule from your copy to use the package's value. The starter files never load the drop-ins a second time.

A drop-in that has a syntax error or fails while it runs is skipped. Gnoblin loads the other drop-ins and your own config as usual, writes ignored file <path>: <reason> to the session log and lists it in the recovery notice. It does not reject a reload.

Run gnoblinctl config reload after installing or removing a package that ships a drop-in.

A Gnoblin installed under its own prefix, such as /usr/local/lib/gnoblin, adds that prefix's share directory to the front of XDG_DATA_DIRS for the session. Its share/gnoblin/conf.d/ therefore loads last among the data directories.

Include a file

Lua
gnoblin.load("appearance.lua")

The path is relative to the calling file. Absolute and ~/ paths also work. The included file uses the same API:

Lua
gnoblin.configure {
    window_management = {focus_mode = "hover"},
}

Include a directory

Lua
gnoblin.load("conf.d/**/*.lua")

Matching files load in filename order (byte order, independent of your language settings). Use numbered names such as 10-appearance.lua and 90-local.lua to make the order predictable.

  • *, ? and [abc] match within one path segment.
  • ** also searches subdirectories, without following directory symlinks.
  • Hidden names need an explicit dot in the pattern.
  • An unmatched glob is allowed; a missing exact filename is an error.

Gnoblin reads these files at login and on reload. It does not watch them. After you add, remove or change a file, run gnoblinctl config reload.

Override or append?

Put gnoblin.load(...) calls before your personal settings so your changes are applied last.

Repeated gnoblin.configure calls keep settings you have not changed:

Lua
gnoblin.configure {window_management = {focus_mode = "hover"}}
gnoblin.configure {window_management = {raise_on_click = true}}

The result keeps sloppy focus and raises windows when clicked. The second call does not remove settings that it does not mention.

Lists replace earlier values. This applies to window_rules, shortcuts, and autostart.

To add a window rule while keeping previous rules, use:

Lua
gnoblin.window_rule {
    match = {type = "window", focused = false},
    opacity = 0.95,
}

The shortcuts and autostart maps merge entries with the same name. Set an entry's enable field to false to disable an imported shortcut or autostart. Disabling an autostart entry does not stop a running process.

To remove every shortcut loaded so far:

Lua
gnoblin.configure {shortcuts = {}}

Use gnoblin.configure.shortcuts to add or change individual shortcuts without clearing the others.

Use a Lua module

Use a module when you want a file to return settings for another file to use. For ordinary config files, gnoblin.load is enough.

In appearance.lua:

Lua
return {window_management = {focus_mode = "hover"}}

In init.lua:

Lua
gnoblin.configure(require("appearance"))

require("appearance") searches appearance.lua, then lua/appearance.lua, relative to its caller. It runs once per reload.

Returning a table does not apply its settings by itself. Pass it to gnoblin.configure as shown above.

Dots in module names are not converted to directories. For explicit subdirectories, use gnoblin.load("parts/motion.lua"). Avoid loading the same file through both a glob and require.

Available Lua functions

gnoblin is available globally in every loaded file and module. See the function reference.

Setting names use snake_case. The API converts them to Gnoblin's internal hyphenated names. String values, shader uniform names and renderer names stay literal. Do not supply both spellings of the same key in one table.

Each reload evaluates the files again; Lua variables do not survive it.

Config code can use Lua's table, string, math and UTF-8 helpers. It cannot read arbitrary files, run processes or load native modules. These are not available:

  • The os, io, debug and package libraries. os.getenv("HOME") fails with "attempt to index a nil value (global 'os')".
  • dofile and loadfile. To load another file, use gnoblin.load.

To launch programs, use shortcuts or autostart.

Evaluation is limited to 8 MiB of Lua memory, one million instructions and 32 nested files.

For event-driven compositor behavior, load a Lua module that registers a callback with gnoblin.on. See Lua event handlers and the event reference. Keep presentation in separate Wayland clients; the runtime API controls compositor state.

Reload and persistence

Change Applies When removed
Rules and animations On reload Earlier rules/defaults apply
Titlebar policy After reload and the app's next surface update Earlier rules/defaults apply
Command shortcuts On reload Binding released; launched process stays
Built-in keybindings On reload Built-in default applies
Window-management preferences On reload Gnoblin default applies
Compositor interaction preferences On reload Gnoblin default applies
Input preferences On reload GNOME/Mutter settings apply
Input sources On reload Session input sources apply
Orientation lock On reload GNOME orientation setting applies
Cursor theme and size On reload Adwaita at 24 logical pixels
Notifications and layout popup On reload Saved GSettings value stays
Autostart Reconciled on reload Updated or removed child stops
Renderer services Restart on reload Enabled frames use native fallback
Protocols On reload for new clients Default on reload for new clients
Launcher focus behaviour On reload Default on reload
Drag boundary Next drag after reload Defaults to enabled
Portal routes Portal service restarts on reload Active portal requests may be interrupted
Xwayland server flags Xwayland restarts when flags change Running X11 apps disconnect

If you change a setting with the CLI, a value written in your config file will replace that change on the next config reload.

gnoblinctl config reload replaces the active Lua configuration and its event callbacks. It does not replace native libraries or restart separate desktop clients.

Reload and error notices

Gnoblin draws a small notice at the top centre of the screen when a reload finishes and when a shortcut or command you configured does not start. Notices never take keyboard focus. A click on a notice dismisses it; a click anywhere else goes to the window underneath.

Event Notice Removed
A reload applied Config reloaded After about 2 seconds. Another reload restarts the time.
A reload was rejected Config reload failed and the first line of the error When you click it, or when a later reload succeeds.
A shortcut or command could not start <name> could not start: <reason> After about 8 seconds. Repeats of the same message show once.

For example, media-next could not start: No such file or directory means the command behind the media-next shortcut is not installed. A rejected reload leaves the active configuration unchanged. Run gnoblinctl config reload to see the whole error. Up to four notices stack under each other; the oldest goes first. Starting the session shows no reload notice.

Esc

Try