Linux Goodies

In Pursuit Of The Perfect O/S



A Review And Tutorial Of The DWM Window Manager

Zazzle Linux Gifts

What Is The DWM Window Manager?

The dwm window manager for Linux is an incredibly small and efficient window manager for X. Like ratpoison, it is an ultra-lite Linux window manager, runs amazingly well in Linux, and in spite of its small size, has more features than is at first obvious.

Dwm is a tiling window manager, meaning that it arranges the multiple open windows on a computer screen in a tile manner. The windows fit tightly together and do not overlap. It's about using up all the screen surface area with window content -- not frills. It's also about being able to quickly move between the windows.

Dwm is written entirely in the c programming language. In fact, the code is entirely in one rather small c file. Yet dwm can do screen display in three modes: monocle where each window takes the entire computer screen, tiled where windows take up the entire screen in adjacent tiles, and floating where windows may be moved, resized, and overlap. Quick key commands make the switch between these display modes.

The default mode is the tiled mode. While in ratpoison tiles are created manually, in dwm tiling is automatic. If one computer computer computer computer computer computer computer computer application is running, its window takes the entire screen. Add another application and the screen splits into two columns. The left column, by default, is the master frame. It will always be full height, and can resized in width. Check the man file for which are the resize keys. In the source version, the grow and shrink commands are alt-l and alt-h respectively.

The right column will contain the rest of the open windows in a vertical stack, with the column divided equally between the number of windows beyond the one in the master frame. Each newly launched application will occupy the master frame.

You can swap any focused window with that in the master frame just by entering alt-enter. Entering alt-space will change the display mode to floating. In this mode, the mouse can be used to move and resize windows, letting the windows violate the tiling restrictions. Holding down the alt key and the mouse button1 will let you move windows. The alt key and the mouse button3 will let you resize windows.

The alt-m key will switch the display to the monocle mode, where the screen is taken up by a single window. The alt-j and alt-k keys are used to step forward and back through the different windows to let them be the one displayed. In the floating and tile modes, the alt-j and alt-k keys move focus to the next or previous frame.

Dwm supports a multiple workspace concept with its tag system. When in a tag workspace, newly opened windows will become part of that tag. The windows will thus be visible only when the user in in that tag. A focused window can be moved to a different tag with the alt-shift-n key sequence, where n is the tag number. Entering alt-shift-0 while on a focused window will make that window visible on all tags.

To remove a focused window from a tag, enter alt-cntl-shift-n. You can check the man files and see how to also assign and remove windows from tags with mouse controls.

One limitation of dwm is that all tags will have the same display mode. That is, if you switch to the tiled mode in a tag, then move to another tag, the windows there will also be in the tile mode. This is unlike the ratpoison augmented with rpws windows manager, in which each workspace's tile arrangement is retained. But -- check out the patches section listed later.

In my Debian Etch Linux distribution, I was able to install dwm by doing apt-get install dwm. But if you want to be able to tune dwm to your liking, I suggest you get the entire package from the dwm link, from where you can download the source code and man file. This is useful because the tuning of dwm is done by making changes to the config.h header file and recompiling.

You may shudder at the thought of working with source code. I've had some bad experiences myself. It often seems that getting some complex, multi-file coded application to successfully compile is a monumental task. But dwm is different. It's a single file that compiles quickly and easily.

The DWM Window Control Methods

dwm screenshot

Above is a screenshot of dwm in the tile mode. Clicking on the image will show a full-sized version. The running applications include the web browser dillo, the xcalendar utility, and the xosview utility.

Notice that the left most column is full height. It is the master frame, adjustable in width. The other windows are stacked vertically in the right column. Of course if you increase the width of the master frame, you will decrease the width of the other column as a result.

dwm window manager monocle mode

The above display shows the same loaded windows in the dwm monocle mode. In this mode, only one window at a time is shown, and it takes the entire screen. Key sequences alt-j and alt-k step forward or backward through the other windows, bringing them to the top to be displayed.

The xcalendar and xosview applications are still running in this example, but their windows are covered by the full-sized dillo window.

dwm window manager floating window mode

The above display shows the dwm floating window mode. In this mode, holding down the alt-button1 keys (that's alt on keyboard, button1 on mouse) allows you to move a window around with the mouse. The alt-button3 sequence allows mouse motions to resize a window.

In this example, you now see the float-able xosview and xcalendar windows on top of the dillo display.

How To Customize DWM

For such a simple window manager, dwm presents a considerable number of customizations. Almost any key sequence can be redefined to be more to your liking. If you download the source package from the dwm web page, you also get the dwm man page. By editing the config.h file (and recompiling) and editing the man page to reflect your changes, you'll have a running version tailored to your needs and documentation to match.

Below is a segment of the config.h file showing some key definitions that you can easily change:

static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY, XK_x, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_s, setmfact, {.f = -0.05} },
{ MODKEY, XK_g, setmfact, {.f = +0.05} },
{ MODKEY, XK_Return, zoom, {0} },
{ MODKEY, XK_Tab, view, {0} },
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
{ MODKEY, XK_space, setlayout, {0} },
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
{ MODKEY, XK_0, view, {.ui = ~0 } },
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
{ MODKEY, XK_period, focusmon, {.i = +1 } },
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },

In the code example, the MODKEY definition represents the alt key. The XK definitions represent keyboard keys. For example, the XK_j, focusstack line is defining alt-j to focus on the next window in the stack.

Changing these definitions will let you find a more natural configuration for you to use. On my old laptop, for example, I use an external mini-track ball mouse to replace the non-functioning original mouse. With that arrangement, the alt-button3 resize operation for a floating window was very awkward to accomplish.

So I modified the config.h definition so the resize operation could be accomplished with a alt-shift-button1 operation. I also altered the key sequence designed to launch dmenu to launch ratmenu instead, since I already had a well defined ratmenu layout to support the ratpoison window manager.

Customizing DWM -- The Next Level

Adding Your Own Shortcut Keys

It's not only possible to change the default control keys and mouse usage for window controls, you can add some of your own custom shortcut keys. The following snippet from the config.h file shows the default command definitions for launching an xterm and for launching dmenu:

/* ********** Default Command Definitions ********** */

static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
static const char *termcmd[] = { "uxterm", NULL };

/* ********** Some Additional Definitions ********** */

static const char *browsercmd[] = { "/usr/local/seamonkey/seamonkey", NULL };
static const char *packagecmd[] = { "links2", "-g", "", NULL };

/* ********** Attaching A Shortcut Key To The Commands ********* */

static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_h, spawn, {.v = dmenucmd } },
{ MODKEY, XK_x, spawn, {.v = termcmd } },
{ MODKEY, XK_w, spawn, {.v = browsercmd } },
{ MODKEY, XK_p, spawn, {.v = packagecmd } },

The technique for defining a shortcut key to launch a task in dwm is to first define a string constant that holds the command, such as the *dmenucmd string. Then in the static Key keys section, add the definition that combines the key you want with the spawning of the application. The launcher for dmenucmd and termcmd were already in the config.h, and they provide the examples of how it is done.

I just created a couple of other command strings for launching my favorite applications -- one for launching the seamonkey browser, and one for launching the links2 browser and passing it the url that has a search engine for searching the Debian archives. Then in the keys definition section, I added the necessary lines to spawn my applications. If you examine the example, you can see that I use alt-w to run my browser, and alt-p to run the links2 Debian search.

Defining Rules For Specific Applications

Another thing you can do is take advantage of the ability to define rules for some specific applications. The following is an example of the rules section of the config.h file:

static const Rule rules[] = {
/* class instance title tags mask isfloating monitor */
{ "Gimp", NULL, NULL, 0, True, -1 },
{ "Seamonkey-bin", NULL, NULL, 0, True, -1 },
{ "XEphem", NULL, NULL, 0, True, -1 },

Notice the comment line that indicates what the arguments are for the entries. The Gimp line was already in the original config.h as an example. Firefox was as well, and I just changed Firefox to Seamonkey-bin. Then, following the examples, I added an entry for xephem.

Use the following procedure to get the right string for the class argument of the rules table:

Run the application
While it's up, in an xterm run the xprop utility, then click on the application for which you want the class string.
Look for the 2nd string listed in the WM_CLASS parameter.

Once you get the proper class name with xprop, enter that into the class argument of the table.

The tags mask lets you enter 0, which allows the task to open under whatever tag you're under when you run it, or a binary tag position indicator like 1<<8. The shift nomenclature in this instance puts a 1 in the ninth binary position. That indicates tag 9, so the launched application would start in tag 9. A 1<<3 argument would indicate tag 4 for the application (a 1 in the 4th binary position).

The main reason I use the rules table is to specify that certain products be ran in floating windows, indicated by True under the isfloating argument of the table. That way, even though I'm working in my preferred tile windowing mode, the applications that are listed in the rules section of the config.h will run as floating windows. Otherwise I'd have to switch windowing modes to run those products.

You could just as easily use the rules table to make an application run under a certain tag, or on a specific screen (if you had a multi-monitor setup). Once you figure out how to use the rules table, you'll find it a handy extension to the dwm system.

Some More DWM Features

DWM tags

Above you see an expanded section of the upper left-hand corner of the dwm screen. It's part of the status bar that extends along the top of the screen. The numbers 1 through 9 are tag numbers. As mentioned earlier in this article, the tag mechanism functions much like workspaces on more advanced window managers.

The small square next to numbers 1, 2, and 3 indicate that windows are open in those workspaces. The tag with the filled in small box indicates that it's the currently selected tag. Clicking on one of the tag numbers will bring you to the windows of that tag. The key sequences alt-1 through alt-9 also move you to the respective tags.

The []= symbols on the right side of the image indicate that the screen is in tile mode. The ><> symbols would indicate that the screen is in float mode. A number in a bracket, like [2], would indicate monocle mode, with window 2 of the stack being displayed.

Some Handy Available Patches

As described in the previous portions of this web page, dwm is amazing for its ultra-lite size. But it has a couple of limitations that its bigger brothers have solved. One is that dwm has only one tile mode, with the screen being broken up to have a master column, and the remainder of the windows stacked in another column. Second, the selected display mode for dwm is global, applying to all workspaces.

Luckily, there are many dwm patches that you can apply to increase dwm's utility or appeal. You can see the patch options at the top of the indicated link's page.

Add Some New Tiling Layouts

Since I'm using dwm primarily on an old, limited resource laptop, I'm only interested in increased utility. One patch that I especially like is the bottom stack subroutines. These are two small c files that you can download, and simply include by reference in the config.h file. The instructions are pretty clear, but here's a couple segments of my config.h that handle the inclusion and utilization of these functions:

In the config.h layouts area:
#include "bstack.c"
#include "bstackhoriz.c"

static const Layout layouts[] = {
/* symbol arrange function */
{ "TTT", bstack },
{ "[]=", tile }, /* first entry is default */
{ "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
{ "===", bstackhoriz },

In the keys[] definition area:
{ MODKEY, XK_u, setlayout, {.v = &layouts[0]} },
{ MODKEY, XK_t, setlayout, {.v = &layouts[1]} },
{ MODKEY, XK_f, setlayout, {.v = &layouts[2]} },
{ MODKEY, XK_m, setlayout, {.v = &layouts[3]} },
{ MODKEY, XK_y, setlayout, {.v = &layouts[4]} },

The first set of additions are the includes for the new routines bstack.c and bstackhoriz.c, causing them to be included in future compiles. Next are additional entries into the layouts[] array for the new routines. The layouts additions associate 3 character symbols to show on panel and the code used for the layout modes. I used TTT to indicate the tiling method that splits into two rows then subdivides the non-master row into columns, and the === symbol to indicate the all-rows tiling method. You can certainly your own choice of symbols.

In the keys[] array portion of config.h, I added a couple of key definitions to trigger my new tiling options. These key definitions refer to the previously defined layouts table by index. I did a bit of rearranging here to get one of the horizontal layouts as the default. My new key definitions are alt-u for the horizontal/vertical tiling method, and alt-y for the all horizontal tiling method. Recompile and restart dwm, and you're all set with additional tiling layouts.

dwm bstack layout

The image above is screenshot of bstack layout routine. It uses the top row of the screen as the master frame. The bottom row is then tiled into horizontally separated frames as more applications are executed.

dem bstackhoriz layout

The above image is a screenshot of the bstackhoriz layout routine. It breaks the screen repeatedly into rows, with the top row being the master, resizable (vertically) row. Additional tasks cause more horizontal tiles in the bottom row.

Make Workspaces Retain Their Layout Configuration

Another great patch is the pertag patch. Be sure to pick the one that matches your version of dwm. This patch is done by downloading into the directory where your dwm.c file is, and doing a patch command as indicated in the simple directions that come with the patch. Then, of course, recompile. With this patch, each dwm workspace retains its own display configuration.

I, being greedy, wanted both the new layouts, and the utility of having workspaces (tags) retain their specific layouts. But I found that the two patches didn't play well together. The make command resulted in many errors. However, there was a fairly simple way to bring it all together. If you're not a coder you might be nervous, but you can get this to work. Just remember to make backup copies of the config.h and dwm.c files before doing any patches, and you can always get back to square one.

Basically, to get the two patches to work together, you must do 2 things.

  • Move the #include "bstack.c" and #include "bstackhoriz.c" lines from the config.h and put in the dwm.c file just after the struct Monitor{ ... } definition.

  • Add prototypes for the bstack and bstackhoriz routines to the prototype area (near the beginning) of the dwm.c file. I put mine just after the restack prototype as follows:

  • static void restack(Monitor *m);
    /* Added references to bstack and bstackhoriz */
    static void bstack(Monitor *m);
    static void bstackhoriz(Monitor *m);

    With these small modification, you can get both the new tiling methods, bstack and bstackhoriz, and the workspace display retention functions to work in your dwm configuration. And the increase in size is trivial. What else could you want?

    This is admittedly a superficial view of the workings of the dwm window manager, but hopefully it's enough to give you an idea of whether it's something for you to try. I tried it, and found it very useful on my old laptop. I switched from the light-weight fluxbox to the ultra-lite dwm to complement the ratpoison window manager that I use on the laptop. While ratpoison gives more elaborate manual control of the screen tiles and more configuration capability of hot keys, dwm gives the handiness of auto-tiling and allows floating windows. Between the two, I can do about anything I want on my laptop without paying the price for even a light-weight window manager.