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.
After every change, recompile and restart dwm:
cd ~/dwm
make
make install
Before making larger changes, create a backup:
cp config.h config.h.bak
To start, copy the template:
cp config.def.h config.h
Important: after a git pull, always compare your config.h with
the updated config.def.h to catch new options:
diff config.def.h config.h
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, but the default bindings expect two external programs to be installed:
-
dmenu— launched byAlt + p -
st— launched byAlt + Shift + Return
Both are suckless projects and follow the same make && 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 every
reference inside colors[] must be updated accordingly.
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.
fonts[] accepts multiple entries. dwm tries each in order and falls back
to the next if a glyph is missing. This is useful for mixing a text font
with a symbol or emoji font:
static const char *fonts[] = {
"Iosevka Term:size=11",
"Noto Color Emoji:size=11"
};
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 */
static const int resizehints = 1; /* 1 = respect size hints, 0 = ignore */
resizehints 1 lets terminal windows dictate their own size, which can
leave gaps between windows and screen edges in tiling mode.
Most users set this to 0 to fill the screen completely.
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
MODKEY is defined near the top:
#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 */
Default Bindings
Alt + p launch dmenu
Alt + Shift + Return launch terminal (st)
Alt + b toggle bar
Alt + j / k focus next / previous window
Alt + i / d increase / decrease windows in master
Alt + h / l resize master area left / right
Alt + Return toggle window between master and stack
Alt + Tab switch to previous tag
Alt + Shift + c close focused window
Alt + t tiling layout
Alt + f floating layout
Alt + m monocle layout
Alt + Space toggle between last two layouts
Alt + Shift + Space toggle floating on focused window
Alt + 0 show all tags
Alt + 1..9 switch to tag 1..9
Alt + Shift + 1..9 move focused window to tag 1..9
Alt + Comma / Period focus previous / next monitor
Alt + Shift + q quit dwm
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 } },
Each argument must be a separate string in the array. Do not put the full command inside a single string:
/* wrong — dwm will not parse spaces */
static const char *browsercmd[] = { "firefox --private-window", NULL };
/* correct */
static const char *browsercmd[] = { "firefox", "--private-window", NULL };
Key symbols (XK_p, XK_w, etc.) are defined in the X11 keysym headers
(usually /usr/include/X11/keysymdef.h).
To find the symbol for any key, use xev:
xev | grep keysym
Press the key in the xev window and read the symbol from the output.
Launching a Program and Keeping the Terminal Open
Some terminals support a --hold flag to keep the window open after the command exits.
st does not. Use the shell instead:
static const char *fetchcmd[] = { "st", "-e", "sh", "-c", "fastfetch; read", NULL };
{ MODKEY, XK_F5, spawn, {.v = fetchcmd} },
read pauses until you press Enter.
Keep st minimal — let the shell handle it.
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 picks up the color variables directly:
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
};
To change dmenu colors independently from the rest of dwm, replace the variable references with literal hex strings:
"-sb", "#e0b800",
Common Tasks at a Glance
Want to change |
Where to look |
Window border color |
|
Bar background |
|
Font |
|
Correct font name |
|
Bar position |
|
Master area size |
|
Default layout |
first entry in |
App always floating |
|
App opens on tag N |
|
Modifier key |
|
Two modifier keys |
define |
Add a launcher |
new |
Find a window class |
|
Find a key symbol |
|
Remove tiling gaps |
|
Project repository: https://git.suckless.org/dwm
Based on the vanilla config.def.h.
Keep your config.h in sync with upstream config.def.h after updates.
Slackware
Slackware users may alternatively build dwm using a SlackBuild
and include their custom config.h during the build process.
A minimal SlackBuild example (without additional patches) is available at: https://github.com/r1w1s1/slackbuilds/tree/master/OVERLAY/desktop/dwm