After 3 years, my xmonad configuration now uses GNOME

Nearly three years ago, Spencer Janssen and I started work on xmonad, a tiling window manager for unix that would do what we want, automatically, so we could just concentrate on hacking code, without the window manager getting in the way. The project’s been quite successful — the most downloaded app on Hackage for the last couple of years, and thousands of users. It even has its own twitter, blogreddit and facebook accounts.

Originally I thought of this project something as the anti-GNOME: small, learn, and every part just does one thing only, but well – in the Unix tradition. And it has stayed lean. Around two thousand lines of Haskell for the core system, but with the benefit of hundreds of extensions in the contributor’s library — everyone’s config file is potentially a library module new users can import.

Over the years, GNOME and xmonad have started playing well together to the point that there’s relatively seemless interop between the two projects: you can use the full GNOME environment, and swap in xmonad as your window manager, or use a minimal environment with xmonad, adding in GNOME tools that help you.

Playing well with others is good for your open source software.

I’ve now finally switched my xmonad configuration to use a number of gnome apps, to support the core dynamic tiling provided by xmonad. Here’s my config file:

import XMonad
import XMonad.Config.Gnome
import XMonad.Layout.NoBorders
main = xmonad
    gnomeConfig {
            terminal = "term"
          , layoutHook  = smartBorders (layoutHook gnomeConfig)
    }

Yeah, that’s it. import XMonad.Config.Gnome, add smart borders, and overide the terminal to be my urxvt wrapper. xmonad is configured in Haskell, or languages Haskell can interoperate with.

My session is started up from .xinitrc as:

gitit &
gnome-panel &
gnome-power-manager &
dbus-launch --exit-with-session xmonad

I use gitit as my personal wiki, and then put a few things in the gnome-panel.

I’m really happy with how easy it now is to use xmonad with all the regular GNOME apps that people would like to see. This kind of friendliness to the dominate tools of the day is good for the project — and good for our users.

xmonad: a success for pure functional data and QuickCheck

So, after 2 months of activity:

From a whole bunch of developers, and unabated growth in the code base ..

;) Actually, unabated growth in comments in the code base:

xmonad 0.2 is released! Yay, a proper tiling window manager in Haskell, ready to use. It’s been a lot of fun working on this project, and I think it’s been a real success so far. We’ve been able to develop very quickly and apply good Haskell methodologies, such as strong typing, QuickCheck, and Neil’s cool `catch’ pattern verifier, to a real-world program.

In fact, it has been remarkable how several times that, after large refactoring and rewrites have taken place, once the code type checks and the QuickChecks pass, the application hums along as if nothing changed. We rewrote the entire core over a weekend a little while ago, and the code just worked. It was scary!

There are lessons here, I think, for `agile’ development. We spent a bit of time early on building up a large set of generic window manager properties, stated as QuickCheck predicates. Once this was in place, it gave us the confidence to try out experimental changes, because as long as the types check, and the QC properties hold, things seem to just work. Making code experiments safe really improves the development experience. You feel more comfortable playing with the code, and pushing it in unusual or radical directions. With strong types, and automated testing, you have the machine support to move the code faster and further..

We’ve been able to use a lot of automated testing because, although xmonad would appear to be a very eventful, imperative program — a window manager — it all runs on top of a purely functional core (the xmonad `zipper’ data structure). The imperative layer of the window manager — that part that talks to the X server — is just a skin over a referentially transparent core (which models the desktop state). And with such a core, we can do a lot of automated testing. The core window manager can be tested without even needing an X server (so we run automated tests on each darcs commit). Keep your code pure, so you can test harder, and the bugs will stay far away.

Another interesting point: once we found the right data structure — a zipper of workspaces (an xmonad workspace is a one hole context of a window list) — the code got far simpler (see the drop in the lines of code count around patch 300), the QC properties got stronger, and more invariants were determined statically by the data structure itself. Pick a data structure that embeds the semantics of the domain you’re modelling and your life will be easier.

I doubt we would have attempted such a radical experiment as the zipper rewrite, without the QC properties in place first — and for purely political reasons: with the QC tests it is easier to gain the trust of the other developers that the wacky idea of a complete rewrite, would be safe. Other devs need not trust you, they can look at the QC properties, and check for themselves that the code is ok. QuickCheck helps you win friends and influence people ;-).

So, I think xmonad is now a serious, highly usable tiling window manager. If you like dwm-style tiling, but need proper full screen, or Xinerama support (or just like hacking Haskell), xmonad is the logical choice, in this area. And weighing in at 1/40th the size of the Ion window manager is a bonus.

And now, thanks to Jason Creighton, xmonad supports a true floating layer per-workspace, as well:

The future looks pretty bright for xmonad, I think. Its remarkably stable, small and simple. And becoming quite well documented. You can now tile your windows, purely functionally!