Howto: dwm configuration and installation

Share your HowTo, Documentation, Tips and Tricks. Not for support questions!.
3 posts • Page 1 of 1
Loomx
Posts: 55
Joined: 2010年09月28日 01:11

Howto: dwm configuration and installation

Post by Loomx »

dwm (dynamic window manager) is a minimalist tiling window manager, famous for being ultra-lightweight and infamous for needing to be recomplied every time you make changes to the configuration. This has led to it gaining a reputation as "experts only", but the aim of this howto is to show that this is not necessarily the case. For me, after using openbox, fluxbox, ratpoison, evilwm, icewm, I found that I knew what features I wanted and what I didn’t, and dwm just does its job with minimal fuss and maximum speed.

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
We’ll need the build-dependencies, and also make and gcc:

Code: Select all

# aptitude build-dep dwm
# aptitude install make gcc
Also, we’ll want an application launcher like dmenu, although you could use gmrun or similar. dmenu is part of this package:

Code: Select all

# aptitude install suckless-tools
The default font for the status bar is Terminus, so if you want that you'll need this package:

Code: Select all

# aptitude install xfonts-terminus
dwm can be installed as a normal package, but that would kind of defeat the purpose as you wouldn’t be able to customise it :D

So, make a directory to put the dwm source into, for example:

Code: Select all

mkdir ~/Build
Then move into that directory, download the source, then move into the new dwm directory:

Code: Select all

cd ~/Build
apt-get source dwm
cd dwm_6.0 # (or whatever it is)
Have a look at what you have now; check out the README in particular.
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
It’s pretty well commented, but we'll take a look through it bit by bit:

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 */
You can define the font the way you would for an xterm. The bottom two lines define whether it will be hidden and where it will be. Easy huh?
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 },
};
dwm has multiple desktops, but they’re called tags and work slightly differently. By default they are numbered 1-9, but you can rename them however you want, just put the names in quotes.
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 },
};
dwm has three layouts: tiling, floating (normal 'Windows' mode) and monocle (fullscreen). Here you can set the default layout, and the funky little symbol that will appear in the status bar.
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} },
By default the modifier key is Alt ("Mod1Mask"). You could change it to Super/Windows by using "Mod4Mask" if you preferred.
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 } }
I think this part speaks for itself :)


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} },
};
The first two commands in the long list spawn commands; note how those commands are defined above that, with each separate part of the command in quotes and with NULL at the end. So any commands you wanted to add would need to be defined under ‘commands’, then called in the ‘keys’ section.
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} },
};
Here you define what happens when you click in various places, with and without the mod keys.
‘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 */
Different font; selected window border is white.

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 },
};
Two tags, "Here" and "There"; I don’t tend to run many windows at once. No rules as I haven’t found I needed any (but you still need to keep this line in here with ‘NULL’)

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 },
};
Monocle (fullscreen) mode by default, and if I switch to tiling it’s usually with two windows so I split the screen 50:50
‘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 } }
Note the line added in here (‘#include <X11/XF86keysym.h>’) - this means you can refer to your XF86 keys in the next section.

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 };
Most apps I run from dmenu, but if you need to use something regularly with command line options, like chromium with a proxy server, you can define it here to call with a keybind.
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)
};
I’ve tried to stick to keybinds that don’t interfere with other apps, e.g. Alt-p is used to select ‘print’ on a print dialog page, so I've avoided that.
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 the layout symbol to toggle tiling mode; click the status bar text and dmenu starts; right-click to get a terminal.
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
If you plan to tinker with your config.h a bit, each time you just need to run this command from the ~/Build/dwm_6.0 directory, then exit dwm (Alt-Ctrl-q in my case) and ‘startx’ again.


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
This will spit out lots of output; the options given mean it shouldn't prompt you about unsigned files.
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
Done! Now it’s official.

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
You might also want to run

Code: Select all

# aptitude hold dwm
so your version doesn't get overwritten by an update if you're running testing or sid.

**************************

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
Here’s mine as an example; :

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
Don’t forget to make it executable:

Code: Select all

chmod 755 ~/.xinitrc
Then just run

Code: Select all

startx
to get the whole show started.

**************************

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)
Last edited by Loomx on 2013年04月10日 09:32, edited 14 times in total.
Loomx
Posts: 55
Joined: 2010年09月28日 01:11

Re: Howto: dwm configuration and installation

Post by Loomx »

Ahhh, thanks...

(and this relates to dwm how?) :?
dmhdlr
Posts: 266
Joined: 2011年04月17日 23:44
Location: Philadelphia

Re: Howto: dwm configuration and installation

Post by dmhdlr »

I think it's spam. Great post BTW. This is exactly what I was looking for a couple of weeks ago when I considered giving dwm a try. But I didn't as I ...login to view the rest of this post
[formerly known as Deckard]
"Emacs: making you posthuman since 1976"
Axiom #1: Emacs is a text interface prosthesis
Axiom #2: Org-mode gives you super cyborg organizational powers
cf. Why Emacs | Emacs-fu | EmacsWiki | Worg

This topic has 41 more replies

You must be a registered member and logged in to view the replies in this topic.


Register Logout
3 posts • Page 1 of 1

Return to "Docs, HowTos, Tips & Tricks"

  • Newest Posts
    Top Active Users
    Newest Users