This howto is aimed at anyone from low-intermediate level upwards. You will need to be familiar with the terminal, root vs normal user commands and the basic Debian file-system structure (but the less you know now, the more you learn as you go, right? )
This howto also assumes that you are familiar with using a window manager, such as openbox, as opposed to a Desktop Environment like Gnome, KDE or XFCE.
Substitute 'apt-get' for 'aptitude' if you prefer.
Any commands with a # at the start means “as root”.
Overview:
Part 1: Preparation
Part 2: Configuration
Part 3: Installation
* Note: This howto will discuss two ways of installing dwm: the generic, quick-and-dirty “make install” way, and the ‘proper’ APT/Debian way. Both ways have their ups and downs; as always, it’s your system, just be aware of your choices.
***************************************************************
Part 1: Preparation
Before we start, let’s get the dependencies: (they are probably already on your system if you’re using X anyway)
Code: Select all
# aptitude install libc6 libx11-6 libxinerama1
Code: Select all
# aptitude build-dep dwm
# aptitude install make gcc
Code: Select all
# aptitude install suckless-tools
Code: Select all
# aptitude install xfonts-terminus
So, make a directory to put the dwm source into, for example:
Code: Select all
mkdir ~/Build
Code: Select all
cd ~/Build
apt-get source dwm
cd dwm_6.0 # (or whatever it is)
But what we really want to do is customise this baby, so...
*****************************************************************
Part 2: Configuration
Copy the default config file to config.h then open it.
Use whatever editor you prefer to modify config.h, but I would recommend using one that allows syntax highlighting to help you understand what you’re doing
Code: Select all
cp config.def.h config.h
vim config.h
Code: Select all
/* See LICENSE file for copyright and license details. */
/* appearance */
static const char font[] = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*";
static const char normbordercolor[] = "#cccccc";
static const char normbgcolor[] = "#cccccc";
static const char normfgcolor[] = "#000000";
static const char selbordercolor[] = "#0066ff";
static const char selbgcolor[] = "#0066ff";
static const char selfgcolor[] = "#ffffff";
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
static const Bool showbar = True; /* False means no bar */
static const Bool topbar = True; /* False means bottom bar */
The selected window has a one-pixel border by default, of color #0066ff (red, I think)
The background and foreground colors refer to the status bar.
Code: Select all
/* tagging */
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
static const Rule rules[] = {
/* class instance title tags mask isfloating monitor */
{ "Gimp", NULL, NULL, 0, True, -1 },
{ "Firefox", NULL, NULL, 1 << 8, False, -1 },
};
The rules define how certain windows get treated, e.g. Gimp is always floating (not tiled or monocle/fullscreen) as it doesn't work properly otherwise.
The “tags mask” defines which tag the window appears on. Basically read the “<<“ as “+”, so “1 << 8” means Firefox will be on tag 9.
0 means any tag.
Code: Select all
/* layout(s) */
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static const Bool resizehints = True; /* True means respect size hints in tiled resizals */
static const Layout layouts[] = {
/* symbol arrange function */
{ "[]=", tile }, /* first entry is default */
{ "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
};
Above that you can select the amount of the screen that the master window takes up.
Code: Select all
/* key definitions */
#define MODKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
The TAGKEYS set what happens if you press the number for a tag along with a modifier, so Alt-3 will take you to tag 3, while Alt-Shift-3 will tag (attach) a window to tag 3.
Code: Select all
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
Now we get to the guts of it, the commands:
Code: Select all
/* commands */
static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
static const char *termcmd[] = { "uxterm", NULL };
static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
{ MODKEY, XK_l, 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 } },
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
TAGKEYS( XK_4, 3)
TAGKEYS( XK_5, 4)
TAGKEYS( XK_6, 5)
TAGKEYS( XK_7, 6)
TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8)
{ MODKEY|ShiftMask, XK_q, quit, {0} },
};
XK_p means the button ’p’, etc.
If instead of ‘MODKEY’ you put ‘0’, that would mean ‘no modifier’.
‘focusstack’ means next or previous window, depending on the +1 or -1
‘setmfact’ means set the size of the master window in tiling mode
‘zoom’ is move a window to the master window in tiling mode
‘setlayout’ chooses a layout based on the order defined earlier, starting numbering from 0
The TAGKEYS select the tags - note that the tags as far as dwm is concerned number from 0-8.
Lastly, Alt-Shift-q quits dwm and takes you back to a tty.
Code: Select all
/* button definitions */
/* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static Button buttons[] = {
/* click event mask button function argument */
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
{ ClkTagBar, 0, Button1, view, {0} },
{ ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
};
‘ClkLtSymbol’ means ‘click layout symbol’.
**********************************************************
As you can see, there are a lot of options. The default config basically chucks them all in so you can use what you need and ditch what you don’t.
I have found that I don’t need most of the options, so here is my config.h for reference after I took to it with a knife and added a couple of tricks:
Code: Select all
/* See LICENSE file for copyright and license details. */
/* appearance */
static const char font[] = "7x14";
static const char normbordercolor[] = "#000000";
static const char normbgcolor[] = "#cccccc";
static const char normfgcolor[] = "#000000";
static const char selbordercolor[] = "#cccccc";
static const char selbgcolor[] = "#0066ff";
static const char selfgcolor[] = "#ffffff";
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
static const Bool showbar = True; /* False means no bar */
static const Bool topbar = True; /* False means bottom bar */
Code: Select all
/* tagging */
static const char *tags[] = { "Here", "There" };
static const Rule rules[] = {
/* class instance title tags mask isfloating monitor */
{ NULL, NULL, NULL, 0, False, -1 },
};
Code: Select all
/* layout(s) */
static const float mfact = 0.5; /* factor of master area size [0.05..0.95] */
static const Bool resizehints = False; /* True means respect size hints in tiled resizals */
static const Layout layouts[] = {
/* symbol arrange function */
{ "[ ]", monocle }, /* first entry is default */
{ "[]=", tile },
};
‘resizehints = false’ so terminal windows don’t leave odd gaps around the edges.
Code: Select all
/* key definitions */
#define MODKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
#include <X11/XF86keysym.h>
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
Code: Select all
/* commands */
static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
static const char *termcmd[] = { "xterm", "-rv", "-fn", font, NULL };
static const char *chromiumcmd[] = { "chromium-browser", "--proxy-server=172.31.232.250:3128", NULL };
static const char *play[] = { "mocp", "-G", NULL };
static const char *stop[] = { "mocp", "-x", NULL };
static const char *prev[] = { "mocp", "-r", NULL };
static const char *next[] = { "mocp", "-f", NULL };
static const char *mute[] = { "amixer", "-q", "set", "Master", "toggle", NULL };
static const char *volumedown[] = { "amixer", "-q", "set", "Master", "2%-", "unmute", NULL };
static const char *volumeup[] = { "amixer", "-q", "set", "Master", "2%+", "unmute", NULL };
static const char *eject[] = { "eject", NULL };
Also you need to define what command each of your XF86 keys will execute.
Code: Select all
static Key keys[] = {
/* modifier key function argument */
{ 0, XF86XK_Launch1, spawn, {.v = dmenucmd } },
{ 0, XK_F6, spawn, {.v = termcmd } },
{ 0, XK_F7, spawn, {.v = chromiumcmd } },
{ 0, XF86XK_AudioPlay, spawn, {.v = play}},
{ 0, XF86XK_AudioStop, spawn, {.v = stop}},
{ 0, XF86XK_AudioPrev, spawn, {.v = prev}},
{ 0, XF86XK_AudioNext, spawn, {.v = next}},
{ 0, XF86XK_AudioMute, spawn, {.v = mute}},
{ 0, XF86XK_AudioLowerVolume, spawn, {.v = volumedown}},
{ 0, XF86XK_AudioRaiseVolume, spawn, {.v = volumeup}},
{ 0, XF86XK_Eject, spawn, {.v = eject}},
{ MODKEY, XK_Tab, focusstack, {.i = +1 } },
{ MODKEY, XK_space, setlayout, {0} },
{ MODKEY, XK_z, zoom, {0} },
{ MODKEY, XK_q, killclient, {0} },
{ MODKEY|ControlMask, XK_q, quit, {0} },
TAGKEYS( XK_comma, 0)
TAGKEYS( XK_period, 1)
};
The XF86 key "Launch1" for dmenu is actually the Super/Windows key, which I remap in ~/.xinitrc (see near the end of this howto)
Alt-space simply toggles between monocle and tiling modes, as they are the only modes I specified earlier.
Alt-comma and alt-period are for "Here" and "There" tags.
Code: Select all
static Button buttons[] = {
/* click event mask button function argument */
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkWinTitle, 0, Button1, spawn, {.v = dmenucmd } },
{ ClkWinTitle, 0, Button3, spawn, {.v = termcmd } },
{ ClkTagBar, 0, Button1, view, {0} },
{ ClkTagBar, ControlMask, Button1, toggleview, {0} },
{ ClkTagBar, 0, Button3, tag, {0} },
{ ClkTagBar, ControlMask, Button3, toggletag, {0} },
};
Click on a tag name to view it; right-click on a tag name to send a window to that tag.
So that’s mine; go to town, or just try the default first, whatever. When you're done there, it’s time for…
*******************************************************************
Part 3: Installation
a) The generic quick-and-dirty method
This is the method from the README file. It will put dwm into /usr/local/bin which is good for two reasons: that directory is empty by default in Debian, and it is already in your $PATH
The disadvantage of this method is that APT will not be aware of its existence, so you have been warned.
The advantage is that it is, well, quick:
Code: Select all
# make clean install
b) The ‘proper’ APT/Debian way
Once you have it set up how you want, you can make a .deb and install it properly.
This is straightforward too; just run this to make the .deb (from in the ~/Build/dwm_6.0 directory):
Code: Select all
dpkg-buildpackage -us -uc
When it finishes you should find your .deb in the parent directory, so cd up one level and install like so (as root):
Code: Select all
cd ..
# dpkg -i dwm*.deb
Don’t forget to uninstall the file at /usr/local/bin/dwm (if you used the quick-and-dirty method) like this:
Code: Select all
cd ~/Build/dwm_6.0
# make uninstall
Code: Select all
# aptitude hold dwm
**************************
You need to make (or alter) the executable file ~/.xinitrc to start dwm
The last line in it should be
Code: Select all
exec [...] dwm
Code: Select all
#!/bin/sh
. ~/.fehbg # set wallpaper
unclutter -root & # hide cursor when unused
# Turn Super/Windows key into XF86Launch1
xmodmap -e "keycode 133 = XF86Launch1"
# Turn CapsLock into Control
xmodmap -e "clear lock" -e "keycode 66 = Control_R" -e "add Control = Control_R"
# Show memory use, volume %, battery % and time in status bar
while xsetroot -name "$(free -m | awk '/cache:/ { print $3"MB" }') Vol:$(amixer get Master | tail -1 | awk '{ print $5 }' | tr -d '[]') Batt:$(acpi | awk '{ print $4 }' | tr -d ',') $(date +%R)"
do
sleep 1
done &
# Launch system-wide stuff first, then dwm...
exec ck-launch-session dbus-launch dwm
Code: Select all
chmod 755 ~/.xinitrc
Code: Select all
startx
**************************
Some sources:
http://dwm.suckless.org/tutorial
http://dwm.suckless.org/customisation/
http://www.xsnake.net/howto/dwm/dwm-eng.php
http://wiki.archlinux.org/index.php/Dwm
http://lubutu.com/rant/dwm-faq
You can also extend dwm with patches to add features like new layouts, such as b.stack (horizontal stacking, good for non-widescreens); see http://dwm.suckless.org/patches
Have fun!
Any errors in this howto are mine, and if you point them out I can fix them
(Edited many times for clarity and freshness)