[2025-jun-17] The SlackDocs Wiki has moved to a new server, in order to make it more performant.
Table of Contents
dwm config.h Quick Reference
A practical guide to customising dwm without knowing C.
Based on vanilla dwm (no patches).
What is config.h?
config.h is the configuration file for dwm. It is a C source file, but you do not need to know C to edit it.
To start, copy the template:
cp config.def.h config.h
Before making larger changes, create a backup:
cp config.h config.h.bak
After every change, recompile and restart dwm:
cd ~/dwm make sudo make install
Then restart dwm (Alt+Shift+q if you do not have a session manager handling it, then re-login or re-run your .xinitrc).
git pull, always compare your config.h with the updated config.def.h to catch new options:diff config.def.h config.h
Installing dwm on Slackware
For installation basics, see the dwm getting-started guide.
This page covers two additional cases:
SlackBuild overlay for -current
For Slackware -current, a maintained overlay is available at:
https://git.sr.ht/~r1w1s1/slackbuilds-overlay/tree/main/item/desktop/dwm
Building from source
Clone the upstream repository and build:
git clone https://git.suckless.org/dwm cd dwm make sudo make install
By default, sudo make install puts dwm in /usr/local/bin/dwm (vs. /usr/bin/dwm from the SlackBuild).
Which dwm Is Running?
If you have used more than one installation method (for example, SlackBuild package + source build), two binaries can coexist:
- SlackBuild →
/usr/bin/dwm - Source
make install→/usr/local/bin/dwm
To find every dwm binary on your system:
whereis dwm
To see which one your shell will launch from $PATH:
which dwm
To check which one your session actually starts, look at your .xinitrc (or the SlackBuild-provided /etc/X11/xinit/xinitrc.dwm) for the line that calls dwm. If it is just exec dwm, it follows $PATH. If it is an absolute path like exec /usr/bin/dwm, it always launches that specific binary regardless of $PATH.
A common source of confusion: editing and recompiling the source tree while .xinitrc is hardcoded to launch the SlackBuild version. Recompile all you want — nothing changes on screen.
Do I Need to Know C?
No.
For basic customisation, you usually only change:
- numbers (like
borderpx = 1) - strings inside quotes (like
“monospace:size=10”) - color hex values (like
“#222222”) - key symbols (like
XK_p,XK_Return)
You are not writing functions. You are not changing algorithms. You are only editing values.
If you can edit a .conf file, you can edit config.h.
Dependencies
dwm itself has no runtime dependencies beyond Xlib, Xft, and fontconfig, but the default bindings expect two external programs to be installed:
dmenu— launched byAlt + pst— launched byAlt + Shift + Return
Both are suckless projects and follow the same make && sudo make install process. If either is missing, the binding fails silently — dwm will not crash.
Source: https://tools.suckless.org
Colors
Five color variables are defined near the top of config.h:
static const char col_gray1[] = "#222222"; /* bar background */ static const char col_gray2[] = "#444444"; /* unfocused border */ static const char col_gray3[] = "#bbbbbb"; /* normal text */ static const char col_gray4[] = "#eeeeee"; /* selected text */ static const char col_cyan[] = "#005577"; /* focused border + bar bg */
To change a color, replace the hex value. The variable names are arbitrary. You may rename them, but if you do, update every reference inside colors[] too.
The colors[] table assigns those variables to states:
static const char *colors[][3] = { /* fg bg border */ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, /* unfocused */ [SchemeSel] = { col_gray4, col_cyan, col_cyan }, /* focused */ };
SchemeNorm applies to unfocused windows and the bar.
SchemeSel applies to the focused window and the selected dmenu entry.
Font
static const char *fonts[] = { "monospace:size=10" }; static const char dmenufont[] = "monospace:size=10";
monospace is a generic fontconfig alias that resolves to whatever monospace font is installed on the system. It works out of the box without installing anything extra.
Replace the font name and size to taste. Both fonts[] and dmenufont should use the same value for consistency.
Finding the Correct Font Name
The display name and the fontconfig name often differ. To find the exact name as fontconfig sees it:
fc-list | grep -i "fontname"
Some examples:
“JetBrains Mono NF”may be known as“JetBrainsMono Nerd Font Regular”“Iosevka”may be known as“Iosevka Term”
Once you have the correct name:
static const char *fonts[] = { "Iosevka Term:size=11:antialias=true" }; static const char dmenufont[] = "Iosevka Term:size=11:antialias=true";
Fonts on Slackware
Slackware users can find both fonts on SlackBuilds.org:
- JetBrains Mono: https://slackbuilds.org/repository/15.0/system/JetBrainsMono/
- Iosevka (full, 400MB+): https://slackbuilds.org/repository/15.0/system/Iosevka/
- Iosevka-core (minimal subset, sufficient for dwm and st): https://slackbuilds.org/repository/15.0/system/Iosevka-core/
Iosevka-core contains only the essential font files. If you only need Iosevka for dwm and st, use Iosevka-core instead of the full package.
On other distributions, look for packages named iosevka or fonts-iosevka in your package manager.
Border & Bar
static const unsigned int borderpx = 1; /* border width in pixels */ static const int showbar = 1; /* 1 = show bar, 0 = hide */ static const int topbar = 1; /* 1 = top, 0 = bottom */
Tags (Workspaces)
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
Tags can be renamed to any string:
static const char *tags[] = { "web", "term", "edit", "mail", "5", "6", "7", "8", "9" };
Rules (Application Placement)
Rules define where an application opens and whether it floats. Without a rule, a window opens on whatever tag is currently active. With a rule, it always opens on a specific tag regardless of where you are.
A practical example: you want Firefox to always open on tag 1. You are on tag 2. You launch Firefox. It opens on tag 1. You switch to tag 1 to use it. The other tags have no rules — windows there follow normal behaviour.
static const Rule rules[] = { /* class instance title tags mask isfloating monitor */ { "Firefox", NULL, NULL, 1 << 0, 1, -1 }, { "feh", NULL, NULL, 0, 1, -1 }, };
tags mask controls which tag the window opens on. 1 « 0 means tag 1, 1 « 1 means tag 2, 1 « 8 means tag 9. 0 means no specific tag — just respect isfloating.
isfloating 1 makes the window always float.
monitor -1 means follow the current monitor.
Windows with no matching rule open on the current active tag, tiled.
To find a window's class name, run:
xprop | grep WM_CLASS
then click the window. Use the second value returned (the class, not the instance).
Layouts
static const float mfact = 0.55; /* master area size: 0.05 to 0.95 */ static const int nmaster = 1; /* number of windows in master area */ static const Layout layouts[] = { { "[]=", tile }, /* tiling - first entry is the default */ { "><>", NULL }, /* floating */ { "[M]", monocle }, /* monocle */ };
Adjust mfact to change how much screen the master area takes. 0.55 means the master takes 55% of the screen width.
Keybindings
For the full list of default keybindings, see Key Shortcuts in the dwm getting-started guide.
This section covers how to change them.
MODKEY is defined near the top of config.h:
#define MODKEY Mod1Mask /* Alt key (default) */ /* #define MODKEY Mod4Mask Super / Windows key - uncomment to use instead */
Using Two Modifier Keys
Some users prefer to split bindings across two modifiers — one for window management and one for application launchers. This is a personal workflow choice, not a requirement.
#define MODKEY Mod1Mask /* Alt - window management */ #define MODKEY2 Mod4Mask /* Super - application launchers */
Then use MODKEY2 selectively inside keys[]:
{ MODKEY, XK_j, focusstack, {.i = +1 } }, /* Alt+j focus next window */ { MODKEY2, XK_f, spawn, {.v = browsercmd } }, /* Super+f launch browser */
Adding a Keybinding
Find the keys[] array and add a line following this pattern:
static const Key keys[] = { /* modifier key function argument */ { MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, };
To launch a custom program, add a command array and a binding:
static const char *browsercmd[] = { "firefox", NULL }; { MODKEY, XK_w, spawn, {.v = browsercmd } },
Key symbols (XK_p, XK_w, etc.) are defined in the X11 keysym headers (usually /usr/include/X11/keysymdef.h).
Mouse Bindings
/* click mod button function */ { ClkClientWin, MODKEY, Button1, movemouse }, /* MOD + left drag = move */ { ClkClientWin, MODKEY, Button2, togglefloating }, /* MOD + middle = toggle float */ { ClkClientWin, MODKEY, Button3, resizemouse }, /* MOD + right drag = resize */ { ClkTagBar, 0, Button1, view }, /* click tag = switch tag */ { ClkTagBar, 0, Button3, toggleview }, /* right click tag = toggle tag */
dmenu Colors
dmenu is launched via the dmenucmd[] array, which passes dwm's color variables to dmenu as flags:
static const char *dmenucmd[] = { "dmenu_run", "-nb", col_gray1, /* normal background */ "-nf", col_gray3, /* normal foreground */ "-sb", col_cyan, /* selected background */ "-sf", col_gray4, /* selected foreground */ NULL };
By default, dmenu inherits dwm's colors. For the meaning of each flag and how to customise dmenu independently, see the dmenu page.
Common Tasks at a Glance
| Want to change | Where to look |
|---|---|
| Window border color | col_gray2 (unfocused), col_cyan (focused) |
| Bar background | col_gray1 and col_cyan in colors[] |
| Font | fonts[] and dmenufont |
| Correct font name | fc-list | grep -i “name” |
| Bar position | topbar |
| Master area size | mfact |
| Default layout | first entry in layouts[] |
| App always floating | isfloating 1 in rules[] |
| App opens on tag N | 1 « (N-1) in rules[] |
| Modifier key | #define MODKEY |
| Two modifier keys | define MODKEY2 with a second Mod*Mask |
| Add a launcher | new const char *cmd[] + entry in keys[] |
| Find a window class | xprop | grep WM_CLASS |
See Also
- dwm — getting started guide — installation, starting dwm, basic usage
Keep your config.h in sync with upstream config.def.h after updates.
Sources
- Originally written by r1w1s1