This post is part of a series.
Previous post: << Event Handling
In my last post, I set up a basic event-handling framework; in this one, I’m going to start using it to control wmii. Most of wmii’s mouse controls are built-in, but the keyboard controls are handled by the configuration script. wmii emits a “Key” event when a key is pressed, but only if that key is already bound. wmii only binds the keys listed in its /keys file; all key combinations listed in that file will be intercepted by wmii, and other programs will not be able to receive them.
Of course, the /keys file is, like every other part of wmii’s virtual filesystem, modifiable at runtime. So it’s possible to change the keybindings while wmii is running. This opens up the possibility of key modes, something that is used by other tiling WMs (like i3) to allow for easy keyboard-only resizing of tiled windows. With a resize mode, we could just press Mod4+r, use the arrow keys to adjust a window’s size, then press ESC or Mod4+r again to return to the default mode.
(For readers who are new to tiling window managers, Mod4 is another name for the Super or Windows key. Most wmii keybindings use this key as a modifier, since very few other programs use it.)
Here is a simple Node module that handles setting key bindings, reading key events, and switching key modes:
Simply require-ing this file and binding some keys or creating and setting a mode will automatically handle wmii key events. With key events working, we have almost everything we need to get a bare-bones wmii environment running. Before we do, however, let’s set up a few more basic functions and organize the project files in a sensible way.
One thing that will be very useful in this project is error reporting. Console messages don’t work very well for a window manager, because the console that launched it is never visible. The default wmii config uses dialog boxes to communicate with the user, but it uses xmessage to generate them… xmessage is ugly, and its scrollbar is confusing. I’m going to use zenity instead. (Install it with your package manager if you don’t have it.) This module should take care of all of our dialog box needs:
In order to make a working wmii config out of these scripts, they need to be in the ~/.wmii-hg folder, and they need to be called from an executable script named wmiirc. Below is what the ~/.wmii-hg folder structure should look like, with files that I haven’t written yet prefixed with an asterisk (*):
.wmii-hg/ lib/ dialog.js wmii_events.js *wmii.js wmii_keys.js wmiir.js *wmiirc.js *wmiirc
The missing * files are core files, which will be very complex by the time this config is done. For now, I will write skeleton versions of them that will allow me to test the key-event-handling code.
This file is the core of the wmii config. It should handle core events (like errors), displaying menus, and providing an interface to some of the wmii filesystem’s core files (like /ctl, /rules, and /colrules). For now, I will implement error messages and two features of the standard wmii config: the actions menu (Mod4+a) and the programs menu (Mod4+p).
This file is the real wmiirc file; it’s the file that users of the config would edit if they wanted to change their keybindings, menus, etc. For now, I will define one mode (“default”) and some standard wmii keybindings, as well as a single action (“quit”) that can be accessed through the Mod4-a action menu.
wmii expects an executable script with this name, so I’ll write a simple shell script that launches Node. In the future, I may modify it to relaunch Node if/when it crashes.
Make sure to set this file as executable with
chmod +x wmiirc! If this file is not executable, wmii will ignore it and use its default configuration.
Running wmii in Xephyr
The config is now usable, but it doesn’t provide a full wmii environment; it’s still missing tag support, and, if it crashes, it’s easy to get stuck in wmii without a way to exit. The safe way to test it is to use another window manager (I’m going to use icewm), and to start wmii in a nested X server in a window. This can be done using Xephyr.
Running wmii in a window also allows me to view its console output, which will be very useful for debugging. If my config crashes (which it did several times as I was trying to work out bugs in the scripts), I can just insert console.log statements to print debugging information to the console, and use that to diagnose the problem(s).
First, start Xephyr on display 2:
% Xephyr :2
Then, in another terminal, launch wmii on display 2:
% DISPLAY=:2 wmii
If you remembered to
chmod +x wmiirc, and if all of the files are under ~/.wmii-hg with the correct filenames, then you should see an empty tan-colored bar appear on the bottom of the Xephyr window. (If the bar is not empty, and you also get a welcome popup, then wmii is using its default config, which means something is wrong.) You can start urxvt with Mod4+Enter…
…or open the programs menu with Mod4+p. (Ignore the console debug output in both screenshots; it’s from a different version of the code than what I’ve posted on this blog.)
Some of these key shortcuts may not work unless Xephyr has captured the keyboard and mouse. To exit wmii, open the Actions menu with Mod4+a, then select quit (the only option). If wmii hangs or crashes, you can use Ctrl-C to stop it from the terminal.
In my next blog post, I will expand on this config by adding support for tags (wmii’s version of virtual desktops), window rules, and context menus.