Tiling addiction

Posted on

So I have this problem ... Well it's not really a problem - I can stop whenever I want, really I can. My problem is that I have a thing for tiling window managers (WMs)1. I love the efficient window management, keyboard focussed operation, extensive customisability and lightweight feel that most tiling WMs offer. For the X Window System 2 there's an awful lot to choose from, and I've been obsessed for some time now with finding a great tiling WM that works for me and then configuring it to perfection.

I've spent an embarrassing amount of time installing, learning about, configuring and tinkering with tiling WMs. Over the last 6 years I've tried out, with at least some seriousness, all of the following:

  • various versions of Ion: my first love. The project is pretty well dead now due to the author having various issues with the free software community.
  • dwm (and various forks): Written in C, configured by editing the C source. Super fast. An inspiration for many other tiling WMs.
  • Musca: Fairly minimal. The project hasn't been worked on for a long time.
  • Ratpoison: The closest thing to GNU Screen for X Windows. I used it for ages.
  • Stumpwm: Ratpoison but re-written by the same author in Common Lisp. Also very good.
  • euclid-wm
  • wmii: Very modular. Takes a lot of ideas from the Plan 9 OS.
  • xmonad: Popular and mature. Written and configured in Haskell. Requires a good grasp of Haskell in order to do anything beyond the basics.
  • qtile: A promising tiling WM written in Python. I would have looked at it more seriously if I could get to it run on the ancient Linux distro we use at work.
  • awesome (versions 2 and 3): I happily used the stable and simple awesome 2 for ages but version 3 is definitely a big step up.

These tiling WMs all have their pros and cons but I've ended up settling3 on awesome (version 3) as it is stable (i.e. not someone's project that was never finished and hasn't been touched in years), highly customisable (almost everything can be changed using Lua), sane to configure with sensible defaults, handles multiple monitors well and lacks irritating bugs.

I use awesome both at home and at work, and until recently I'd been maintaining two separate configurations. After being frustrated by the process of repeatedly synchronising changes between the two configurations, I decided to merge the two and clean up a bunch of stuff at the same time.

The result can be seen on GitLab at: https://gitlab.com/menn0/awesome-config

My goals for the new configuration were:

  • A single configuration for multiple hosts: My work and home awesome configurations are mostly the same, however at home I use a laptop and at work I use a workstation with four monitors. The configuration needs to be able to dynamically handle such differences.
  • Allow for per-host customisation where needed: At work, I need a widget to monitor production environments as well as clocks for other time zones. My laptop needs a battery widget. Obviously, the way the panels at the top of each screen are put together is host specific. My laptop and work machine also have quite different keyboards so some bindings need to be different (although most bindings are identical).
  • Modularisation and abstraction: Most people's awesome configurations involve a single lengthy, poorly organised Lua file (rc.lua). After some organic evolution such a configuration tends toward difficult-to-understand spaghetti code. I've also seen configurations where the same patterns are copy-and-pasted over and over - this screams out for abstraction. I wanted to apply some basic software development principles because when you work on your awesome configuration you're actually doing software development 4.

Some highlights from my configuration:

  • A very short rc.lua and many small modules: Instead of being a huge, monolithic Lua file, rc.lua simply imports a handful of modules which in turn end up using other modules. This makes it easier to find things and to see the overall structure.
  • Per host configuration: Configuration parameters, extra keyboard bindings and the panel setup are loaded from different modules based on the local hostname. I've written a simple helper function called require_by_host to do the hostname-based dynamic loading of modules.
  • Minimal global state: In Lua, variables and functions are global by default so it's possible to introduce subtle bugs through unintended shadowing or sharing of state. I've tried to minimise this through the (hopefully correct) use of modules. I'm sure this could be improved in some areas.

Note that I'm by no means a Lua expert. I'd love to hear feedback on what I've done from more experienced Lua developers and awesome users.

If you're new to tiling window managers, I hope this post has piqued your interest (or at least hasn't put you off them!). If you're already using awesome, I hope I may have encouraged you to re-think your configuration. I know I'm obsessive about these things, but I think there's much to gain from optimising the way you interact with the software you use the most, and your window manager certainly meets that criteria.

Update: As requested, a screenshot of how my config looks (on my laptop).

The panel at the top has from left to right: a button for the application launcher menu, the tag (workspace) list, a window list for the current tag, CPU and memory usage graphs, a battery widget, volume widget, system tray (containing the Dropbox and Network Manager icons), a clock and a awesome layout indicator applet. Most/all of the UI elements are implemented in Lua.

Three application windows are shown in the tag, organised using the "tile" layout. Chrome in the "master" position with Emacs and a shell off to the right.


If you're unsure what tiling window managers are about, or why you'd considering using one, there are a few useful pages around.


I use Linux almost exclusively.


By "settled" I mean, "have used exclusively for about a year now".


The same goes for your editor configuration, but that's another story.