# Ragnar replaces the layout tree with preset tilings and a binary IPC socket

> Ragnar is a GPL-3.0 licensed X11 window manager in about 5,000 lines of C, built on XCB rather than Xlib, with libconfig configuration and a socket-based IPC for plugins. Its distinguishing choice is that it refuses tree layouts entirely, and its 2.0 line has been in development longer than the latest 1.5 tag suggests.

**cococry/ragnar** — Minimal, flexible & user-friendly X tiling window manager

- Repository: https://github.com/cococry/ragnar
- Stars: 1,249 · Forks: 29
- Language: C
- License: GPL-3.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/cococry-ragnar

## Ragnar refuses tree layouts and offers preset tilings instead

Ragnar is described as a feature-rich, straight-to-the-point dynamic window manager for X11, and it is designed to work both as a foundation for a full desktop environment and as a minimal daily-driver window manager. The project stays compact at roughly 5,000 lines of code while still providing the core features: IPC support, external configuration, tiling layouts, EWMH and ICCCM support, reparenting-based window decoration, and runtime configuration reloads.

The design decision that separates it from the family of window managers it resembles is the layout model. Client windows are stored in a doubly linked list, and for tiling Ragnar does not use a tree-based layout system. Instead it provides preset layouts with predictable structure. The README gives the reason plainly: this keeps window placement simple and avoids requiring the user to manually decide where each new window should appear.

That is a genuine philosophical fork, not a feature difference. In a tree model, the arrangement is something you shape over time by splitting, moving and promoting containers. In Ragnar, the arrangement is one of a fixed set that you pick, and the structure stays predictable. Layouts can still be adjusted at runtime by changing the size of the master and slave areas through keybindings, so the proportions are yours even when the topology is not.

The project carries the i3 topic tag, so the comparison is expected. The distinction that matters for a reader is exactly this one, because a tree model and a preset model produce different daily behaviour even when both are called tiling window managers.

## XCB for the protocol, Xlib still in the link line

Since version 2.0, Ragnar uses the XCB API to communicate with the X server. The README gives the reason: XCB provides a lower-level alternative to Xlib and gives Ragnar more direct control over X11 interactions.

The Makefile shows how the migration landed in practice. The link line includes a set of XCB libraries, namely xcb, xcb-keysyms, xcb-icccm, xcb-cursor, xcb-randr and xcb-xfixes, and it also links X11, X11-xcb and config. Both are present, which is normal for a codebase in transition: Xlib appears for the pieces that have not been ported, and X11-xcb provides the bridge between the two worlds. If you are reading the dependencies section of the README, that list is the reason libx11 is still required even though the project has moved to XCB.

The build itself is a plain Makefile. The compiler is cc, the optimisation flag defaults to -O2, and the warning flags are -Wall -Wextra -pedantic with the api/include directory added as a system include path. The sources are every .c file under ./src and ./src/ipc, compiled into a binary named ragnar, with the output landing in ./bin. The project also ships a PKGBUILD, so distribution packaging is a supported path rather than something you have to write, and the README points at it for the optional dependencies that vary by distribution.

One detail in the Makefile is a small lesson in build hygiene. CFLAGS is declared with ?= rather than a plain assignment, with a comment explaining that an exported CFLAGS from a distribution build replaces it wholesale, while the warning flags stay separate so a packaging build cannot accidentally drop them.

## IPC is a binary socket with a separate client library

Ragnar includes an abstracted IPC API for plugin development and external control. The IPC system communicates through a socket using binary data, which the README says allows external programs to interact with the window manager in a structured way.

The repository layout separates the two sides of that. The window manager side lives in ipc/socket.h and ipc/socket.c, which implement socket handling for IPC clients. The client side is a separate library under the api/ directory, and the Makefile has dedicated targets for it: make api builds it and make install-api installs it. The comment in the Makefile is explicit that the window manager links none of it, only the headers under api/include are needed to build, and that it is opt-in, for writing external clients.

That design choice has a practical consequence. If you want a script or panel that drives Ragnar, you compile a small client against the api library and talk to the socket with binary messages. You do not need to rebuild the window manager, and you do not need the window manager to carry a scripting language. The cost is that the protocol is binary rather than text, so a shell one-liner cannot speak to it directly.

The source tree is documented file by file, which is unusual and useful. funcs.h holds documented function declarations used throughout the window manager and explicitly does not contain the keybinding callbacks. keycallbacks.h holds the documented definitions of the callback functions that can be assigned to keybindings in the configuration file. ragnar.c is the main translation unit and holds the application loop, event handling, window management logic, layout calculations and the system-level window manager behaviour. structs.h carries the shared structures, and config.c and config.h handle loading and parsing the configuration through libconfig.

## libconfig for the config file, and Super+C to reload it

Ragnar uses libconfig to load an external configuration file, which gives you a real structured file rather than a script that the window manager evaluates. The default location is system-wide.

```console
# by default, system-wide:
/etc/ragnarwm/ragnar.cfg
# or mkdir -p and cp the default per user.
~/.config/ragnarwm/ragnar.cfg
```

The second path is the one to use if you want your configuration to survive a reinstall. The Makefile comment on the install targets makes the same point: there is no user config target, because ragnar reads $HOME/.config/ragnarwm/ragnar.cfg first and falls back to the copy installed below, and an override is a plain copy.

The configuration is loaded on startup and can be reloaded while the window manager is running, typically through the Super+C keybinding. Because the keybindings themselves live in the configuration file, the callbacks they point at are the ones documented in keycallbacks.h, and that split between the two header files is the clearest picture of how the project expects you to extend it.

The interface is also part of the configuration. By default it uses alacritty, bound to Super+Return, and dmenu, bound to Super+S, and the README notes that both of these need a fonts file, for instance ttf-dejavu. The defaults are sensible and the documentation is honest that changing them is expected.

A separate file, realtime.c, holds infrastructure for faster response time of keybinds, which is worth knowing if you are chasing latency between a key press and the window moving.

## Two steps to install, then a session entry point in .xinitrc

Installation is described as two steps. The first is the build dependencies, which are the X11 and XCB libraries the Makefile links, plus the server pieces and the config parser.

```console
libxcb \
libx11 \
xcb-util-keysyms \
xcb-util-cursor \
xcb-util-wm \
xorg-server \
xorg-xinit \
libconfig
```

The second step is running the installation script from the project root.

```console
./install.sh
```

That is the whole procedure, and the repository also carries a Makefile, a PKGBUILD for distribution packaging, a flake.nix with a flake.lock for Nix users, and a clean.sh.

To actually use it, the session is started from an .xinitrc. The README gives an example.

```console
feh --bg-fill ~/Downloads/nerd.jpg;
xset s off -dpms;
picom -b; polybar &
exec ragnar
```

The last line is the important one: ragnar is exec'd, so it becomes the session and the window manager takes over. The lines before it are the usual companions, a wallpaper, a screensaver setting, a compositor and a bar, and they are shown as an example of what a working desktop around Ragnar looks like rather than as a requirement.

Then you start the session with startx, and stop it with pkill xinit. The repository also has a ragnarwm.install file, which is the format used by install scripts on some distributions, and the install.sh in the root does the copying.

## A debug build with sanitizers and an Xephyr harness

The Makefile has a second build target that is worth more attention than most projects give theirs, because a window manager is exactly the kind of program where memory errors surface as mysterious crashes.

The debug target compiles with -O1 and -g, with -fno-omit-frame-pointer, and with the address and undefined behaviour sanitizers enabled, through -fsanitize=address,undefined. The Makefile comment explains the -O1 choice: it is for readable ASAN traces, and it is kept separate from CFLAGS because that variable uses ?= and a distribution build must not pick these flags up.

There is also a leak sanitizer note, and it is a small but genuinely useful piece of advice for anyone debugging a session. LSan only reports on a normal exit, so you should quit ragnar through its own keybind, because a SIGKILL prints nothing. If you kill the process the hard way, the leak report you were hoping for never appears.

The build is run and then exercised with a script called debug, which the comment describes as an Xephyr script sharing the name with the make target, which is why the target is marked .PHONY. Without that, make would consider the target up to date and skip it.

```console
make debug && ./debug
```

Running the window manager inside Xephyr means the sanitized build is exercised in a nested display rather than on your real session, which is the correct way to reproduce a crash without taking your desktop down with it.

## GPL-3.0, and a 2.0 line that outran the 1.5 tag

The licence is GPL-3.0, and the repository carries a LICENSE file at the root. You can read, modify and redistribute the code, and if you distribute a modified version you owe the copyleft obligations of that licence, including publishing the source of the derivative and keeping the licence text. That is a licensing fact rather than legal advice, and for a window manager distributed as a binary it is a decision for your legal team rather than a blocker for most people.

The version story is the confusing part, and a reader should know it before installing. The most recent tags are 1.5 from 2024-08-17, 1.4 from 2023-08-17 and 1.3.1 from 2023-08-02. Yet the README describes version 2.0 as the current line, and it is the version that uses the XCB API. In other words, the headline feature of the project lives in a 2.0 line that has not produced a tagged release in the visible record.

Activity itself is current. The repository is not archived, the default branch is main, and the last push was on 2026-09-10. The development is in the main branch, and the tag cadence was two releases two weeks apart in 2023, then 1.5 a full year later, which reads like a project that ships in bursts when there is something to ship.

The upgrade cost is therefore mostly about source builds rather than packages. You compile it, you run the install script, and you keep your own configuration in ~/.config/ragnarwm/ragnar.cfg so that a reinstall does not overwrite it.

## Conclusion

Ragnar fits an X11 user who wants a small, readable window manager with predictable preset tilings, a real config file in libconfig syntax, and a documented IPC socket to drive it from scripts, and who is willing to sit on a development version because the 2.0 line is where the XCB work lives. It does not fit someone who wants a manual tree layout, since the project states outright that it does not use one, and it does not fit a Wayland user, because the project is X11 only. Before installing, build the dependencies, run ./install.sh, and copy the default configuration to ~/.config/ragnarwm/ragnar.cfg so your own edits survive a reinstall.

## FAQ

### How do I install Ragnar?

Install the build dependencies, which include libxcb, libx11, xcb-util-keysyms, xcb-util-cursor, xcb-util-wm, xorg-server, xorg-xinit and libconfig, then run the installation script from the project root with ./install.sh. The repository also ships a PKGBUILD for distribution packaging and a flake.nix for Nix.

### Does Ragnar use a tree-based tiling layout?

No. The README states that client windows are stored in a doubly linked list and that Ragnar does not use a tree-based layout system, instead providing preset layouts with predictable structure. Layouts are still adjustable at runtime through keybindings that resize the master and slave areas.

### Where does Ragnar read its configuration from and how do I reload it?

Ragnar uses libconfig to load /etc/ragnarwm/ragnar.cfg by default, or ~/.config/ragnarwm/ragnar.cfg per user, and it reads the user file first. The configuration is loaded on startup and can be reloaded while the window manager runs, typically with the Super+C keybinding.

### How does Ragnar's IPC work?

The IPC system communicates through a socket using binary data, with an abstracted API for plugin development and external control. The window manager side is in ipc/socket.c, and a separate client library under api/ can be built with make api and installed with make install-api, without the window manager linking any of it.

### How do I start a Ragnar session?

Put exec ragnar in your .xinitrc, after the wallpaper, compositor and bar commands you want, then start the session with startx. To stop it, use pkill xinit. By default the keybindings launch alacritty on Super+Return and dmenu on Super+S, and both need a fonts file such as ttf-dejavu.

## Sources

- [cococry/ragnar on GitHub](https://github.com/cococry/ragnar)
- [Issues](https://github.com/cococry/ragnar/issues)
- [License: GPL-3.0](https://github.com/cococry/ragnar/blob/main/LICENSE)
- [README](https://github.com/cococry/ragnar/blob/main/README.md)
- [Releases](https://github.com/cococry/ragnar/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cococry-ragnar
