Thornton 2 Library of Scraps
1K384

Minimalist Window Manager: wmx

This is part of how I made useful and minimalist desktops for my home and work computers.

The wmx window manager is very nearly as minimalist as a window manager can be. On my FreeBSD amd64 systems, it uses only 14 MB of RAM (with less than 9 MB resident) and only 178 KB of disk space (including docs), and the dependencies are equally light. The only heavy aspect of it is the need for shaped windows, but virtually every X server since X11R4 (released in 1989) has that feature built in. I could've chosen the even lighter and more minimalist wm2, but the basic root menu and multi-desktop features of wmx are too essential in my mind to omit.

In FreeBSD, the packages are x11-wm/wmx and x11-wm/wm2 respectively. They have similar names in Linux and other Unix distributions. Most distributions have ready-made binaries, but wmx especially is better compiled from modified source files, because that's almost the only way to configure the few things it lets you.

Using wmx

Starting wmx

The usual way to start wmx, like most window managers without full integrated desktop environments, is to add it to the ~/.xsession script. (This presumes your display manager looks for ~/.xsession and runs it as part of logging in; xdm is one that does, but ~/.xsession must have the execute permission set.) Before adding anything else in, mine looked like this:

#!/bin/sh

# Stuff to run that makes a useful desktop goes here later.

# Finally, start the window manager, & quit X when it exits.
exec wmx
#exec twm

I left in the "exec twm" comment because, if anything I did broke the ability to install wmx, I could just comment out wmx, uncomment twm, and get back to a functioning GUI desktop. (I also considered using twm instead of wmx, and I might switch sometime in the future, but creating a good twmrc is time-consuming.)

Once wmx is running, all you will have is a blank screen and a pointer. That's normal.

Managing windows

Holding down the left mouse button on the background will pop up a menu with a permanent option ("New"), a list of all the windows on the current screen, and, depending on where you click, an "[Exit wmx]" option. The windows shown on the screen are listed flush right, and the windows currently hidden are listed flush left. To select a window or item, move the pointer until the option you want is highlighted, then let up on the left button. If you decide not to choose anything, then move the pointer out of the menu before letting up. Any partially hidden windows will momentarily float to the top while you hover over its menu item, so you can tell similarly named windows apart.

The "New" option will start a new xterm window, and the "[Exit wmx]" option will immediately quit wmx. There's no "are you sure" confirmation step; wmx will just exit because you told it to. The "[Exit wmx]" option will only appear if you click within 3 pixels of the screen's bottom edge.

Every window has a tab, which shows the window title along the left edge and has a single open box in the upper-left corder. The focused window also has a button in the box, a border along the top and left edges, and a triangular resize widget in the lower-right corner.

By default, wmx uses focus-follows-mouse, also called sloppy focus, to determine which window is focused, even if it's not on top of the stack of windows. Moving the mouse into a window automatically focuses it and blurs the previous window, but moving the mouse out of all windows and onto the background doesn't blur the window the pointer was last in. (No visual blurring takes place; it's just a term for the opposite of "focusing.")

Clicking in the window won't raise it to the top of the stack, but clicking on its tab, top border, left border, or resize widget will.

Right-clicking on the desktop warps the pointer to the tab of the currently focused window. Right-clicking on a window tab raises the window on the bottom of the stack to the top, focuses that window, and warps the pointer to its tab. Repeated right-clicking on window tabs will cycle through all the currently open windows, one at a time.

Move windows by dragging its tab, dragging either of its borders, or dragging anywhere in the window while holding down the left Super or Windows key. Resize windows by dragging the resize widget, or resize on only one axis by dragging the extreme ends of the border.

Clicking on the box in the window's tab hides the window; it does not delete the window or quit its program. However, click-holding on the box does delete the window; hold the button until the pointer changes to an X, then let up.

Rolling the mouse wheel while the pointer is on the desktop cycles from one desktop to the next or previous, wrapping around to the first/last on an empty desktop. Rolling the mouse wheel while the pointer is on a window's tab, border, or resize gadget does the same thing, but the window comes along for the ride. Be careful when rolling the mouse wheel because an empty space on one desktop may be a window's border on the next.

Managing the custom menu

Holding down the middle button while the pointer is on the desktop will pop up a custom menu consisting of whatever directories and executable files are in the ~/.wmx/ directory, if it exists. Like the window management menu, highlight an item then let up on the middle button in order to select it.

Any subdirectories are listed flush left, and any executable files are listed flush right. Subdirectories are listed above files, and both are listed in alphabetical order. Selecting a directory does nothing, but moving the pointer to the right end of a subdirectory entry opens a new pop-up menu with the subdirectory's contents.

Executable files can be binaries, shellscripts, or symlinks to them. For example, to create an item in the main menu called "Reset Cursor" that changes the mouse pointer to a Windows-like or Mac-like pointer, create and edit the file ~/.wmx/Reset\ Cursor and give it the following two lines:

#!/bin/sh
xsetroot -cursor_name left_ptr

Then run chmod u+x ~/.wmx/Reset\ Cursor to make it executable. (The backslashes are needed to shell-escape the embedded space in the file's name. Also, the default wmx cursor can be set by replacing "left_ptr" with "top_left_arrow".)

Other notes

There are a surprising number of other ways to manage windows, and most of them are documented in the wmx readme file.

Customizing wmx

background.xpm

The first file worth configuring is the background image. By default, wmx uses this image as a tile in window title bars, window borders, and menu backgrounds. The file must be an XPM3 image (which most image editors should use automatically when an image is saved with the ".xpm" extension), it must be named "background.xpm", and it must be named "background" internally.

XPM images are text files, and the wmx source code includes it as a C++ character array. Being named "background" internally means that the line starting with static char * or static const char * in background.xpm must be either static char *background[] = { or static const char *background[] = {. After unpacking the wmx source code, run less background.xpm in the source code directory for an example.

Config.h

This is the file where most of the customization can take place.

The only change I needed to make from the default is swapping what the middle and right buttons do. By default, the middle button brings up the desktop menu if one is configured, and the right button cycles through all the open windows on the current desktop. Every menu in wmx is a drag-to-use menu; you have to click, drag the pointer to your selection, and not let up until your selection is highlighted. Since I use wheel mice, that means I have to click the wheel and avoid rolling it by accident in the default configuration.

In my copy of wmx-8, the options are on lines 263 and 264. The default settings are:

#define CONFIG_COMMANDMENU_BUTTON Button2
#define CONFIG_CIRCULATE_BUTTON   Button3 // switch window, when over frame

I need them to be instead:

#define CONFIG_COMMANDMENU_BUTTON Button3
#define CONFIG_CIRCULATE_BUTTON   Button2 // switch window, when over frame

I didn't need or want to make any other customizations, but reading the comments helped me understand what this minimalist window manager is really capable of.

Here is the Config.h that came with my copy of wmx. It's a C++ header file; that means comments start with doubled slashes, not hashmarks like in shellscripts.