croffle

Why

Ever since I started using Linux about 8 years ago, I've been fascinated by the freedom it offers its users; more specifically, the freedom of customization. I used to frequent spaces like r/unixporn and r/unixart, looking at beautiful screenshots of setups and getting inspired to keep tinkering with my own. Are you even a real Linux user™ if you've never written a compton picom config?

My memories of that period are a bit fuzzy, but some time after trying my hand at writing an X11 window manager with the most important feature others seemed to lack — vertical window title bars — I discovered Wayland and Sway, fixed a few bugs in the latter, then some more, and before I knew it, became a wlroots team member.

A small terminal emulator window with a title bar on the left.

This is what I wanted. A cropped screenshot from u/ilovecookieee's post.

croissant's initial commit dates back to June 26, 2023, but that's not the first commit… I may or may not have accidentally removed my entire ~/src before pushing the code anywhere, oops. More than just a Wayland compositor to me, it was the culmination of everything I had learned. It offered stacking window management with some weird system with 4 static window groups, which got completely replaced later with a static tiling approach; it spawned libsfdo because I wanted to have window icons; it had a window switcher with live previews, not something you would often see in a non-mainstream desktop environment; and of course, it had vertical title bars. Slowly but steadily, it was shaping into what I had envisioned from the start.

At the same time in real life, I was getting closer to finishing my bachelor's degree. I decided to kill two stones with one bird, or however the saying goes, and reused croissant as my thesis project (with great success). In the end, I finished my compositor, I got my diploma, I fulfilled a long-time wish of that kid who spent most of his free time writing configs and reading ArchWiki… and I felt burned out. It didn't take long for croissant to stop being something important and turn into just a 20000-lines-of-C behemoth I didn't really want to maintain, or touch at all. There was no goal to work towards anymore, and only a void remained.

A bit later, I quit wlroots and stopped working on Wayland software for a while.

How

Fast forward to a few weeks ago. I had grown tired of my Fedora setup filled with lots of ancient garbage on a very inconveniently partitioned drive, and so I decided to just nuke everything and go for a clean Arch install, as <your preferred deity> intended. This created an opportunity to try out river, a modular compositor that allows (or rather, requires) users to bring their own window manager. Of course, I had to write it myself.

A window manager in river is just a special Wayland client that uses a bunch of private protocols to, well, manage windows. As Wayland clients tend to be single-threaded programs with manual object lifetime management, I naturally reached for Go, and after taking a small detour to write a Wayland client package for it and a tinyrwm implementation and picking a name for the project, I got to work on croffle.

One nice thing about not writing a whole Wayland compositor is that you don't have to care about the boring-but-important stuff like synchronizing simultaneous window updates, managing layer surfaces, and so on. On the other hand, it means that sometimes the tools you are offered can be limiting, but hey, creativity flourishes under constraints, and even if they end up being too tight, Isaac, river's developer, is open to suggestions and feature requests. As such, it didn't take me long before I had a working WM tailored to my needs.

What

croffle is actually two separate programs: crofflewm, a window manager, and croffleim, an input device manager. The latter is about as boring as it can be, so let's focus on the former.

Just like its ontological ancestor, crofflewm is a static tiling WM, which means that opening or closing a window doesn't resize everything else. You can add or remove tiles manually.

A croffle screenshot with three tiles; one of them has a Zed window with croffle code, and the other two are empty.
The first empty tile is purple because it's focused.

You can also resize the "main" tile (the first one), and that's about all the control you have over the layout, really.

My reasons for preferring this somewhat unorthodox window management approach are pretty simple:

  1. Most of the time, I just want to have one maximized window.
  2. With a maximized window open, a new window must either be floating, or maximized too. "Resize the first window and show both side by side" is rarely what I actually want to see.
  3. When I do want to have two side-by-side windows, it must be a deliberate decision, and opening yet another window absolutely shouldn't break the existing delicate structure.
  4. In the rare case I need to have three tiled windows open, one of them can usually be designated as the main one, and the sizes of the other two don't matter.
  5. As far as science can tell, nobody has ever needed more than three tiled windows.

If you've heard of Notion (not the "AI workspace" or whatever it's being marketed as these days, the other one), it's similar to that, except tiles are stored as a list (and not a tree), tabs don't exist, and all the currently hidden windows are stored in one per-workspace list, which not only simplifies the whole model, but also allows me to avoid adding extra UI and controls. Win-win!

When it comes to workspaces, or just spaces in crofflewm parlance, having a static number of them has always felt strangely limiting to me, be it 4, 10, or 32, although as I'm writing this now, I feel like this can be attributed to the general rigidity of dynamic tiling window managers without support for hidden windows, which makes their users say nonsense like "workspace 6 is for communication". Sure, i3 has scratchpad, but that's not even remotely It.

In crofflewm, a space exists as long as it has at least one window in it or is focused; it's there only if you need it.

The final piece of the puzzle is a window switcher which I find very convienient as I prefer temporal navigation ("focus the previous window") over spatial ("focus a window to the right") when it comes to focus management. In croissant, getting this right involved doing some funny business with a custom no-op wlr_backend and wlr_output which ultimately worked pretty well and provided live previews for all targets; crofflewm just gives you one static translucent preview of the current selection, striking a nice balance between clarity and implementation simplicity.

All in all, crofflewm is a pretty weird beast in its category.

A photo of a croffle with some vanilla ice cream and whipped cream with dusted cocoa
powder.

Not quite what my window manager looks like, but it's pretty close. A photo by 까만앨리스, licensed under CC BY-SA 2.0 KR.

Conclusion

The freedom Linux promised was just a bait to get me to spend my teen years and then some on a relatively niche OS and its quirky windowing system. Good bait, though, I'd bite again.

Go write a river WM, it's fun. And maybe check out croffle too.