Musings from kb8ojh.net

Sun, 28 Jun 2015

Getting out of the way

by on :

I’m fairly picky about software that I use a lot. I tend to find something that I like, or that comes very close to what I want, tweak it into place as best I can and then use it for a very long time. Good examples of this are mutt and FVWM, which I have been using since the early-to-mid-90s, and rxvt-unicode, which I have been using for a decade or more, since rxvt started showing its age with respect to multi-byte encodings. The primary thing I ask out of such software is that it gets out of my way … if I have to fiddle with it a often, and I use it a lot, that’s a lot of fiddling. Recently, changes in my usage habits have caused my window manager (FVWM, which is on this list) to require some fiddling. That means it’s time to explore some alternatives, which I have done, and I’ll talk about here.

Some Background

First of all, some X11 history for those who might not be aware — which includes those who have grown up on these new-fangled “desktop environments” — or might not have thought about its consequences. Early on, X11 adopted the motto “mechanism, not policy,“ and sought to provide a way to draw a GUI without really dictating how that GUI should look, function, or feel. This was largely because, in the 80s, it wasn’t at all clear what a GUI should be like, and there were several competing paradigms.

This mechanism-not-policy design had both upsides and downsides (enough to fill a book, really), but the one that is most interesting here is the idea of window management. While most GUI systems provide their applications with a drawing area that is managed by the GUI system, by which we mean that size and placement of the window, functions like iconifying and hiding, and similar actions are sort of baked into the system, X11 does no such thing. This means that the management of windows is up to just another application, which we call (logically) a window manager. There have been dozens or hundreds of window managers over the years, often embodying essentially the same principles but with slightly different implementations and feature sets that vary around the edges. For many years these window managers were primarily of the familiar floating window type, which means that application windows are movable, resizeable rectangles that can be stacked atop one another with some sort of border and title bar enabling their identification and manipulation. This is the only kind of user interface that desktop operating systems such as Mac OS X and Microsoft Windows provided for many years, although recent incarnations of both are breaking this mold (primarily in the form of full-screen applications).

One such floating-window window manager is FVWM, which came about in the adolescence of X11 as an improvement on TWM, the default(ish) window manager of the day, bundled with a terminal application from the same author. It was designed to be more featureful than TWM while being smaller and faster than the more capable competitors, so as to run it on a PC of the era with its relatively wimpy processor and RAM and low-resolution display (in comparison to Unix workstations). I picked up FVWM when it was relatively young (some time in the Spring of 1994), and have been using it ever since, with brief excursions in the late 90s and early 2000s (to Enlightenment and then Sawfish) that ultimately left me back on FVWM. FVWM is a relatively mature and featureful implementation of a classic floating-windows window manager, having a lot of features that are familiar to old-time Unix users (and increasingly familiar to Mac OS X users, over the past few years, such as multiple desktops or pages) and providing a mousing-friendly interface that does its best to keep manual window interaction to a minimum. It’s good at placing windows so that they don’t interfere with each other, handles focus in a sane manner, and has a number of useful and robust tools such as toolbars and pagers associated with it.

Changing habits

One thing that FVWM has always handled with only moderate capability (in my opinion) is X11 displays with multiple monitors. X11 can be configured to manage multiple monitors in several ways, which basically boil down to either a) stitching them all together at the edges in some sort of non-overlapping rectangle-bounded layout, such that windows can extend off one edge of one display and onto the edge of another, logically adjacent, display; or b) placing them in a similar logically adjacent pattern, but treating them as separate displays with their own windows and window management, such that windows are wholly constrained to one monitor [1] and cannot be simply moved between them, but the mouse pointer can.

In the first case, where the monitors basically form one large contiguous desktop, FVWM cannot treat the individual monitors separately when it comes to changing pages. (Pages are sort of, but not quite, like Spaces on OS X; they are logically adjacent areas that windows can overlap, but can be switched between to rapidly change the set of windows currently visible on the screen.) This means that changing pages on one monitor necessarily changes pages on the other monitor, which is often undesirable. For example, if I have my editor visible more-or-less full screen on the right-hand monitor, I may want to alternate displaying a PDF viewer or web browser for documentation on the left-hand monitor with some terminals for compilation and file management without messing with the editor.

In the second case, where the monitors are basically distinct windowing environments that happen to lie adjacent to one another, FVWM can switch pages independently but windows cannot be moved from one monitor to the other. This is the tradeoff I used for a long time, and in fact it turns out that I very seldom actually want to move a window from one monitor to the other. It does occur, however, and this scenario typically requires exiting the application entirely and restarting it on the other monitor.

Another thing that FVWM doesn’t handle very well (and indeed most floating window managers do not) is creating and destroying a lot of windows in arbitrary sequence. This is because once a window is created, placed, and sized, FVWM doesn’t mess with it unless you manually adjust it. It does a fairly good job of placing and sizing newly-created windows, but without adjusting the existing windows this is constrained by the currently-visible applications and their disposition. For a very long time I didn’t chafe at this restriction, for whatever reason, due to my workflow. Most of my pages had several non-overlapping terminal windows (typically four), while the remaining pages had a web browser (that I had to fiddle with occasionally, but not a huge amount) or my editor (which pretty much just has its own dedicated place and never has to be messed with).

Lately, however, this has changed; I can’t say exactly why, but I’m spending more time creating and destroying windows for various document viewers and graphics-editing applications. These windows tend to require some fiddling — and, given that my pages are typically tiled with terminals already, figuring out where I should put them so as to minimally disrupt those terminals is tricky. In addition, I use multiple browser profiles to separate concerns (and increase privacy), which entails juggling a number of large windows that each occupy more than half of the physical screen at a time.

Couple that with the re-addition of a second monitor to my primary laptop display and the implications thereof (non-ideal handling by FVWM, divergent FVWM configuration between my desktop and laptop, etc.), and it was time to go window manager shopping again.

Finding a replacement

In looking for a replacement WM, I had a definite desiderata:

  • Gracefully multi-monitor: Since this was a pain point for FVWM, I certainly wanted to address it with a new WM. In particular, I would like to be able to stitch my monitors together as a single X11 screen while coherently managing windows between the screens with a minimum of fuss — including page-flipping on a single monitor. Handling the addition and removal of external displays (such as when performing a presentation on a laptop, for example) with alacrity would be a big bonus.
  • Programmable: I am a huge fan of programmability; my editors have always been programmable, my IRC and IM applications are programmable, etc., and I had a rather pleasant experience with the programmable Sawfish a decade or so ago. I don’t recall precisely why I stopped using Sawfish (I think it was actually multi-monitor support), but I do recall that I developed a number of lines of lisp to manage my windows for me, and found it useful to do so. (Sawfish was extensible in some dialect or another of lisp, or maybe Scheme.)
  • Not too rigid: I’ve never gotten along well with the default window managers of the various desktop environments out there, because they are invariably too rigid for me. I have habits that have been developed and deeply ingrained over twenty years or so, and often they fail to be configurable in some particular point that is a deal-breaker for me. Programmability likely meets this criteria in most cases, but it’s surprising what people bake into software at times.
  • Supports a community: This is probably the weakest of my requirements; however, I have found over the years that a software project with a supporting community is much more likely to meet my needs over the long run. It can even evaporate in five or ten years and I’ll probably be fine, because by then I’ll have things hammered into shape. However, continued progress ensures that things like distro-provided packages will be available when I want them, and generally reduces my need to babysit the software.

With these things in mind, I went out and looked at the window managers that people are using today. Tiling window managers (as opposed to floating-window window managers, tiling WMs automatically place and size windows on your screen in some sort of minimally-overlapping configuration that is rearranged as windows are created and destroyed) have become quite popular in the past few years, while they were really in their infancy the last time I looked around. In particular, several hybrid tiling window managers that allow some windows to be tiled while others are floated have received quite a lot of attention. Additionally, a return-to-minimalism sentiment (perhaps driven by the ever-increasing complexity of desktop environments) has spawned several projects of a design style that I quite approve of — a small, compiled core with basic functionality fleshed out by an interpreted configuration and extension language.

I was first introduced to this application design strategy in editors (via Jed, which I still use for some limited purposes), but I first saw it codified in a way that I could really identify with in USENIX paper , which describes a simple command-based language for extending native-code applications in programmable ways. When I read this article, it clicked for me that not only is this a reasonable way to design GUI frontends for utility libraries (the major thrust of the article, though it certainly describes the use I found compelling), but that it is generally a good way to design all large programs. In fact, we’ve seen that paradigm increasingly adopted, with web browsers largely implemented as core native code glued together by JavaScript possibly being the most obvious example.

Several new-ish window managers immediately stood out as embodying the principles I was looking for in one way or another. In particular, the family of window managers derived from or inspired by dwm, including xmonad and awesome, and the ultimate form of the Ion (now defunct) window manager, Notion. (There are a lot of other possible WMs out there, some of which I looked at, but each of them either failed to meet a point of my desiderata or simply did not impress me for some reason. If your favorite WM isn’t here, that doesn’t mean I didn’t look at it. In particular, several interesting candidates were not as pervasively programmable as these three.) To make a long story short, I ultimately decided (based on perusing documentation, recommendations from people I trust, and not being written in Haskell [2]) to invest some time into awesome.

The awesome window manager

The window manager is a hybrid tiling/floating WM, allowing windows to be either tiled or floated on an individual basis. It has a small core implemented in C using the (more) modern XCB X11 libraries and essentially all of its behavior is defined in Lua configuration files — to the extent that it does nothing at all if you do not provide it with a Lua configuration. It actively manages new and existing windows using a set of rules implemented in Lua that can move, resize, hide, etc. windows as required by the current circumstances.

For my purposes, it meets all four points of my desiderata; it has multi-monitor support as a primary development goal, it is not only programmable in but largely implemented in Lua, it provides relatively little policy on its own and is extremely flexible, and it has an active and interested community. It has a quite usable panel API that can provide a window list, system tray, clock, and other useful tools. It also provides some interesting features I haven’t gotten around to investigating, such as D-bus connectivity.

I was never particularly drawn to “true” tiling window managers when they first came around, as there are certain windows that I prefer to have a particular size and position and that my window manager not mess that up. For example, the window in which I read email is an 80×24 terminal, and I expect it to stay that way. However, modern hybrid tiling/floating window managers can handle this just fine — such windows simply float, perhaps even on a page co-located with tiled windows. Awesome lets me conveniently handle this on either a per-page or per-window (or both) basis. For example, my preferred layout (for now; it’s a port of the FVWM configuration I’ve been using for the past seven or ten years) is six pages, logically arranged in a 2×3 grid. Of those pages, three are fair tiling (for development terminals), one is floating (for my mail and other communication software), one is a tiling rule set I modified myself (for web browsing), and one is full-screen (for my editor).

One advantage of a programmatically-defined configuration is the ability to make configuration decisions based on the machine on which you are running or its properties. For example, I want a battery state indicator to be displayed at the top of the screen on my laptop, which has a battery, but not on my desktop, which does not. In awesome, it turns out that that is simple:


bat = io.open("/sys/class/power_supply/BAT0/status")
if bat then
    -- Create battery widget here
end

This takes advantage of information available to the kernel and presented in the /sys filesystem to determine whether a battery is present or not, and act accordingly. This sort of configurability was possible with FVWM, too, but in practice it rapidly became painful and I handled it by having somewhat divergent configurations on various machines — a practice that I cannot recommend!

Similarly, configuration decisions can be made depending on the display properties, such as the number of attached monitors (which awesome calls screens, though more than one awesome screen may actually be present on a single X11 screen). In the aforementioned 2×3 grid, on a single monitor, I place all six pages on that monitor. On a dual-monitor setup, the left column is on the left monitor while the right column is on the right monitor. This allows my keybindings and navigation to remain the same regardless of physical monitor layout. In practice I do use a single monitor somewhat differently from a dual-monitor workstation, of course, but keeping things as parallel as possible is comfortable for me.

Probably the most broadly useful programmable feature of awesome is the layout engine. This engine controls not only how windows are initially disposed (to which monitor, at what size and location, floating or tiled, etc.), but also how they are affected by the creation and destruction of subsequent windows. For example, the most basic tiling window layout, awful.layout.suit.tile, places one or more master windows on the left side of the screen, with a configurable width and heights that occupy the entire height of the display in a non-overlapping fashion, with the remaining windows in a configurable number of columns to the right.

three windows managed by the tile layout

The tile layout managing three windows.

This is great for managing windows that a) can be readily resized without greatly affecting their functionality, and b) can happily coexist while using less than the full screen. If the master window column width is set very wide, then one of the windows can occupy most of the screen while you’re working with it, while other windows are shoved off to the side out of the way. If it is somewhat narrower, than multiple usefully-sized windows can be present at the same time. I find it handy to have a single terminal about 1/2 of the width of the screen as the master window, with several terminals stacked in the other column. (Indeed, this is a classic use for the tile manager.)

It’s not so great for windows that you don’t want to occupy the full width of the screen, however, and that may not be sharing the screen with any other windows at any given point in time. If only a single window is tiled, it takes up the full screen. For a web browser or terminal, for example, this may make columns of text much wider than is comfortable to scan. In the case of a terminal (if you’re like me, anyway), you probably don’t have only one on screen at any given time. A web browser, you might.

Which brings us back around to programmability. Wouldn’t it be nice if the tiling window manager could limit a window to the master column width even if only one window were present? Sounds good, let’s bust out some Lua. It turns out that accomplishing this was a matter of opening up the tile layout, changing approximately four lines of code and some names, and dropping it into the awesome config directory. In fact, you can find that code here.

Presto, a single web browser window has a configurable width, but adding additional windows to the screen (for example, other profiles in the browser, which is my typical use case) tiles unused windows nicely off to the side where they can be seen but they are not in the way.

It’s not just layouts and the menu/window bar at the top of the screen that can be customized this way … it’s everything. Keys can be bound to arbitrary Lua functions, as can mouse buttons. Incoming D-bus events can cause the WM to respond. New windows obviously get a callback, and that one has a fair amount of infrastructure around it. Arbitrary properties (as well as properties that have meaning to the awesome internals) can be applied to windows based on their characteristics (such as the application they belong to, their title, etc.), and those properties can be queried by functions that deal with the window later on down the line — or those functions can add properties, themselves.

I reserve the right to flee back to FVWM if something surprises me in a bad way, but I’ve been using (and modifying) awesome for about a week now and I think it’s a keeper. My workflow isn’t quite what it was on FVWM, but … isn’t that the point? There are some features I miss, such as edge flip (FVWM can change pages when the mouse passes the logical edge of the screen), but I’m finding comfortable alternatives to most of them. If any of them remain pain points, a little bit of Lua will probably fix the majority; some of them (again, edge flip) may require recourse to C, but the advantages of awesome may make that practical. Or at least not so impractical.

Then again, I also reserve the right to plunge even farther down the rabbit hole, and mix and match my tags instead of treating them like pages, or abandon the pretense that my pages are laid out on a grid, or … but let’s not get too wild, yet.

1 Sort of … that’s close enough for this discussion. Applications can choose to interact with more than one screen on the X11 display, but it gets complicated and many applications that do choose to do so do not handle it very well at all.

2 I joke, I joke. Almost.

tags: floss, software, x11
path: / | permalink | Comments

[ | | ]