Dwm: Difference between revisions

From ArchWiki
m (→‎Installation: remove duplicate instructions)
m (→‎Installation: Demote note to tip)
 
(25 intermediate revisions by 9 users not shown)
Line 14: Line 14:
== Installation ==
== Installation ==


The prescribed way to install dwm is as follows:
dwm can be installed with the packages {{AUR|dwm}} or {{AUR|dwm-git}}. Make any required [[#Configuration|configuration]] changes '''before''' building and installing, see [[makepkg]].


$ git clone git://git.suckless.org/dwm
{{Tip|[https://git.suckless.org/dwm/file/README.html Upstream instructions] can also be followed, but will install files without having [[pacman]] keeping track of them.}}
$ cd dwm
$ make
# make install
 
dwm can also be installed with the AUR packages {{AUR|dwm}} or {{AUR|dwm-git}}. Make any required [[#Configuration]] changes '''before''' building and installing, see [[makepkg]].


=== Configuration ===
=== Configuration ===


dwm is configured at compile-time by editing some of its source files, specifically {{ic|config.h}}. For detailed information on these settings see the included, well-commented {{ic|config.def.h}} as well as the [https://dwm.suckless.org/customisation/ customisation section] on the dwm website.
dwm is configured at compile-time by editing some of its source files, specifically {{ic|config.h}}. For detailed information on these settings, see the included, well-commented {{ic|config.def.h}} as well as the [https://dwm.suckless.org/customisation/ customisation section] on the dwm website.


The official website has a number of [https://dwm.suckless.org/patches/ patches] that can add extra functionality to dwm. These patches primarily make changes to the {{ic|dwm.c}} file but also make changes to the {{ic|config.h}} file where appropriate. For information on applying patches, see the [[Patching packages]] article.
The official website has a number of [https://dwm.suckless.org/patches/ patches] that can add extra functionality to dwm. These patches primarily make changes to the {{ic|dwm.c}} file but also make changes to the {{ic|config.h}} file where appropriate. For information on applying patches, see the [[Patching packages]] article.
Line 43: Line 38:
=== Statusbar configuration ===
=== Statusbar configuration ===


For more examples of status bars see [https://dwm.suckless.org/status_monitor/].
For more examples of status bars, see [https://dwm.suckless.org/status_monitor/].


{{Note|The following requires the {{Pkg|xorg-xsetroot}} package to be installed.}}
{{Note|The following requires the {{Pkg|xorg-xsetroot}} package to be installed.}}
Line 50: Line 45:


The information that you want dwm to show in the statusbar should be defined with {{ic|xsetroot -name ""}} command in {{ic|~/.xinitrc}} or {{ic|~/.xprofile}} (if you are using a [[display manager]]). For example:  
The information that you want dwm to show in the statusbar should be defined with {{ic|xsetroot -name ""}} command in {{ic|~/.xinitrc}} or {{ic|~/.xprofile}} (if you are using a [[display manager]]). For example:  
{{bc|xsetroot -name "Thanks for all the fish!"}}
 
xsetroot -name "Thanks for all the fish!"


Dynamically updated information should be put in a loop which is forked to background - see the example below:
Dynamically updated information should be put in a loop which is forked to background - see the example below:
{{bc|
{{bc|
# Statusbar loop
# Statusbar loop
Line 65: Line 62:
exec dwm
exec dwm
}}
}}
In this case the date is shown in [[wikipedia:ISO_8601|ISO 8601]] format and [[PCManFM]] is launched at startup.


{{note|It is not recommended to set the update interval equal to zero or remove the "sleep" line entirely since this will cause CPU usage to rise substantially (you can assess the effect with ''top'' and [[powertop]]).}}
In this case the date is shown in [[RFC:3339]] format and [[PCManFM]] is launched at startup.
 
{{Note|It is not recommended to set the update interval equal to zero or remove the "sleep" line entirely since this will cause CPU usage to rise substantially (you can assess the effect with ''top'' and [[powertop]]).}}


==== Conky statusbar ====
==== Conky statusbar ====


[[Conky]] can be printed to the statusbar with {{Ic|xsetroot -name}}:
[[Conky]] can be printed to the statusbar with {{ic|xsetroot -name}}:
 
  (conky | while read LINE; do xsetroot -name "$LINE"; done) &
  (conky | while read LINE; do xsetroot -name "$LINE"; done) &
  exec dwm
  exec dwm


If you do not want to spawn too many PIDs by 'xsetroot' command, you can compile this C program:
If you do not want to spawn too many PIDs by 'xsetroot' command, you can compile this C program:
#include <string.h>
 
#include <stdlib.h>
{{bc|1=
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char * argv[])
#include <X11/Xlib.h>
{
 
        Display * dpy = NULL;
int main(int argc, char * argv[])
        Window win = 0;
{
        size_t length = 0;
        Display * dpy = NULL;
        ssize_t bytes_read = 0;
        Window win = 0;
        char * input = NULL;
        size_t length = 0;
        ssize_t bytes_read = 0;
        dpy = XOpenDisplay(getenv("DISPLAY"));
        char * input = NULL;
        if (dpy == NULL)
 
        {
        dpy = XOpenDisplay(getenv("DISPLAY"));
                fprintf(stderr, "Can't open display, exiting.\n");
        if (dpy == NULL)
                exit(1);
        {
        }
                fprintf(stderr, "Can't open display, exiting.\n");
        win = DefaultRootWindow(dpy);
                exit(1);
        }
        while ((bytes_read = getline(&input, &length, stdin)) != EOF)
        win = DefaultRootWindow(dpy);
        {
 
                input[strlen(input) - 1] = '\0';
        while ((bytes_read = getline(&input, &length, stdin)) != EOF)
                XStoreName(dpy, win, input);
        {
                XFlush(dpy);
                input[strlen(input) - 1] = '\0';
                fprintf(stderr, "Input: %s", input);
                XStoreName(dpy, win, input);
                fprintf(stderr, "\nbytes read: %ld\n", bytes_read);
                XFlush(dpy);
        }
                fprintf(stderr, "Input: %s", input);
        free(input);
                fprintf(stderr, "\nbytes read: %ld\n", bytes_read);
        return 0;
        }
}
        free(input);
        return 0;
}
}}


Save this code to file dwm-setstatus.c, compile:
Save this code to file dwm-setstatus.c, compile:
  $ gcc dwm-setstatus.c -lX11 -o dwm-setstatus
  $ gcc dwm-setstatus.c -lX11 -o dwm-setstatus
move 'dwm-setstatus' within your $PATH (/usr/local/bin, for example)
 
move 'dwm-setstatus' within your $PATH ({{ic|/usr/local/bin}}, for example)
 
  # mv dwm-setstatus /usr/local/bin
  # mv dwm-setstatus /usr/local/bin
and run:
and run:
  $ conky | dwm-setstatus
  $ conky | dwm-setstatus


To do this, conky needs to be told to output text to the console only. The following is a sample conkyrc for a dual core CPU, displaying several usage statistics:
To do this, conky needs to be told to output text to the console only. The following is a sample conkyrc for a dual core CPU, displaying several usage statistics:
{{bc|
 
<nowiki>conky.config = {
{{bc|<nowiki>
conky.config = {
out_to_console = true,
out_to_console = true,
out_to_x = false,
out_to_x = false,
Line 128: Line 136:
conky.text = [[
conky.text = [[
$mpd_smart :: ${cpu cpu1}% / ${cpu cpu2}%  ${loadavg 1} ${loadavg 2 3} :: ${acpitemp}c :: $memperc% ($mem) :: ${downspeed eth0}K/s ${upspeed eth0}K/s :: ${time %a %b %d %I:%M%P}
$mpd_smart :: ${cpu cpu1}% / ${cpu cpu2}%  ${loadavg 1} ${loadavg 2 3} :: ${acpitemp}c :: $memperc% ($mem) :: ${downspeed eth0}K/s ${upspeed eth0}K/s :: ${time %a %b %d %I:%M%P}
]];</nowiki>
]];
}}
</nowiki>}}


For icons and color options, see [[dzen]].
For icons and color options, see [[dzen]].
Line 136: Line 144:


To restart dwm without logging out or closing applications, change or add a startup script so that it loads dwm in a ''while'' loop, for example:
To restart dwm without logging out or closing applications, change or add a startup script so that it loads dwm in a ''while'' loop, for example:
{{bc|
{{bc|
while true; do
while true; do
Line 147: Line 156:
dwm can now be restarted without destroying other X windows by pressing the usual Mod-Shift-Q combination.
dwm can now be restarted without destroying other X windows by pressing the usual Mod-Shift-Q combination.


It is a good idea to place the above startup script into a separate file, {{ic|~/bin/startdwm}} for instance, and execute it through {{ic|~/.xinitrc}}. Consider running the script with {{ic|exec}} to avoid security implications with remaining logged in after the X server is terminated; see [[Xinit#Autostart X at login]] for more information. From this point on, when you wish to end the X session, simply execute {{Ic|pkill dwm}}, or bind it to a convenient keybind. Alternatively, you could setup your dwm session script so that it relaunches dwm only if the binary changes.  This could be useful in the case where you change a setting or update the dwm code base.
It is a good idea to place the above startup script into a separate file, {{ic|~/bin/startdwm}} for instance, and execute it through {{ic|~/.xinitrc}}. Consider running the script with {{ic|exec}} to avoid security implications with remaining logged in after the X server is terminated; see [[Xinit#Autostart X at login]] for more information. From this point on, when you wish to end the X session, simply execute {{ic|pkill dwm}}, or bind it to a convenient keybind. Alternatively, you could setup your dwm session script so that it relaunches dwm only if the binary changes.  This could be useful in the case where you change a setting or update the dwm code base.


{{bc|1=
{{bc|1=
Line 169: Line 178:
=== Bind the right Alt key to Mod4 ===
=== Bind the right Alt key to Mod4 ===


When using Mod4 (the Super/Windows Key) as the {{Ic|MODKEY}}, it may be equally convenient to have the right {{ic|Alt}} key ({{ic|Alt_R}}) act as {{ic|Mod4}}. This will allow you to perform otherwise awkward keystrokes one-handed, such as zooming with {{ic|Alt_R}}+{{ic|Enter}}.  
When using Mod4 (the Super/Windows Key) as the {{ic|MODKEY}}, it may be equally convenient to have the right {{ic|Alt}} key ({{ic|Alt_R}}) act as {{ic|Mod4}}. This will allow you to perform otherwise awkward keystrokes one-handed, such as zooming with {{ic|Alt_R}}+{{ic|Enter}}.  


First, find out which keycode is assigned to {{ic|Alt_R}}:
First, find out which keycode is assigned to {{ic|Alt_R}}:
xmodmap -pke | grep Alt_R


Then simply add the following to the startup script (e.g. {{ic|~/.xinitrc}}), changing the keycode ''113'' if necessary to the result gathered by the previous {{Ic|xmodmap}} command:
$ xmodmap -pke | grep Alt_R
  xmodmap -e "keycode 113 = Super_L" # reassign Alt_R to Super_L
 
  xmodmap -e "remove mod1 = Super_L" # make sure X keeps it out of the mod1 group
Then simply add the following to the startup script (e.g. {{ic|~/.xinitrc}}), changing the keycode ''113'' if necessary to the result gathered by the previous {{ic|xmodmap}} command:
 
Reassign {{ic|Alt_R}} to {{ic|Super_L}}:
 
  xmodmap -e "keycode 113 = Super_L"
 
Make sure X keeps it out of the "mod1" group:
 
  xmodmap -e "remove mod1 = Super_L"


After doing so, any functions that are triggered by the {{ic|Super_L}} key press will also be triggered by an {{ic|Alt_R}} key press.
After doing so, any functions that are triggered by the {{ic|Super_L}} key press will also be triggered by an {{ic|Alt_R}} key press.


{{note|There is a {{ic|#define}} option in [[#Configuration|config.h]] which also allows you to switch the modkey.}}
{{Note|There is a {{ic|#define}} option in [[#Configuration|config.h]] which also allows you to switch the modkey.}}


=== Use both Alt keys as Meta in DWM ===
=== Use both Alt keys as Meta in DWM ===


:Use xmodmap to assign Alt_L as a secondary meta key in DWM (provided already using Mod1Mask (Alt_R))
Use xmodmap to assign {{ic|Alt_L}} as a secondary meta key in DWM (provided already using Mod1Mask (Alt_R))


{{hc|~/.xinitrc|<nowiki>
{{hc|~/.xinitrc|2=
/usr/bin/xmodmap -e "clear mod5"
/usr/bin/xmodmap -e "clear mod5"
/usr/bin/xmodmap -e "keycode 108 = Alt_L"
/usr/bin/xmodmap -e "keycode 108 = Alt_L"
</nowiki>}}
}}
{{User:cirrus|00:25, 24 November 2020 (GMT)}}


=== Space around font in dwm's bar ===
=== Space around font in dwm's bar ===


By default, dwm's bar adds 2px around the size of the font. To change this, modify the following line in {{ic|dwm.c}}:
By default, dwm's bar adds 2px around the size of the font. To change this, modify the following line:
{{bc|1=bh = dc.h = dc.font.height + 2;}}
 
{{hc|dwm.c|2=bh = dc.h = dc.font.height + 2;}}


=== Disable focus follows mouse ===
=== Disable focus follows mouse ===


To disable focus follows mouse behaviour comment out the following line in definiton of struct handler in {{ic|dwm.c}}
To disable focus follows mouse behaviour, comment out the following line in definition of struct handler:
{{bc|1=[EnterNotify] = enternotify, }}
 
Note that this change can cause some difficulties; the first click on an inactive window will only bring the focus to it. To interact with window contents (buttons, fields etc) you need to click again. Also, if you have several monitors, you may notice that the keyboard focus does not switch to another monitor activated by clicking.
{{hc|dwm.c|2=[EnterNotify] = enternotify, }}
 
Note that this change can cause some difficulties; the first click on an inactive window will only bring the focus to it. To interact with window contents (buttons, fields etc), you need to click again. Also, if you have several monitors, you may notice that the keyboard focus does not switch to another monitor activated by clicking.


=== Floating layout for some windows ===
=== Floating layout for some windows ===
Line 207: Line 225:
For some windows, such as preferences dialogs, it does not make sense for these windows to be tiled - they should be free-floating instead. For example, to make Firefox's preferences dialog float, add the following to your rules array in {{ic|config.h}}:
For some windows, such as preferences dialogs, it does not make sense for these windows to be tiled - they should be free-floating instead. For example, to make Firefox's preferences dialog float, add the following to your rules array in {{ic|config.h}}:


  { "Firefox",    NULL,      "Firefox Preferences",        1 << 8,        True,    -1 },
{ "Firefox",    NULL,      "Firefox Preferences",        1 << 8,        True,    -1 },


=== Using Tilda with dwm ===
=== Using Tilda with dwm ===
Line 215: Line 233:
  { "Tilda",        NULL,      NULL,                        0,              True,      -1 },
  { "Tilda",        NULL,      NULL,                        0,              True,      -1 },


Launch tilda with -C option:
Launch tilda with {{ic|-C}} option:


  $ tilda -C
  $ tilda -C
Line 221: Line 239:
Now you can configure Tilda, the following options are provided as a recommendation:
Now you can configure Tilda, the following options are provided as a recommendation:


{{bc|Font: Clean 9
{{bc|
Font: Clean 9
Appearance: Height: 50%, Width: 70%, Centered Horizontally
Appearance: Height: 50%, Width: 70%, Centered Horizontally
Extras: Enable Transparency Level 15
Extras: Enable Transparency Level 15
Line 230: Line 249:
}}
}}


Here is what the configuration looks like after those settings in {{ic|~/.config/tilda/config_0}}:
It is important you enable the pulldown-animation, otherwise Tilda will keep jumping down each time you unhide it, must be a dwm issue.
 
=== Taking screenshots ===
 
Install the {{Pkg|scrot}} package. Next create two scripts:
 
{{hc|/path/to/scripts/screenshot.sh|2=
#!/bin/sh
mkdir -p /path/to/pics && scrot /path/to/pics/%m-%d-%Y-%H%M%S.png
}}
 
for making screenshots and
 
{{hc|/path/to/scripts/screenshotsel.sh|2=
#!/bin/sh
mkdir -p /path/to/pics && scrot /path/to/pics/%m-%d-%Y-%H%M%S.png --select --line mode=edge
}}
 
for making screenshots with a selection box.
Give them [[executable]] permissions. In {{ic|config.h}} add the following:


{{bc|1=
{{bc|1=
tilda_config_version = "0.9.6"
static const Key keys[] = {
# image = ""
      ...
# command = ""
     
font = "Clean 9"
      { 0,        XK_Print, spawn, SHCMD("/path/to/scripts/screenshot.sh") },
key = "F9"
      { ShiftMask, XK_Print, spawn, SHCMD("/path/to/scripts/screenshotsel.sh") },
title = "Tilda"
     
background_color = "white"
      ...
# working_dir = ""
};
web_browser = "firefox"
lines = 2000
max_width = 956
max_height = 384
min_width = 1
min_height = 1
transparency = 15
x_pos = 205
y_pos = 1
tab_pos = 0
backspace_key = 0
delete_key = 1
d_set_title = 3
command_exit = 2
scheme = 1
slide_sleep_usec = 1500
animation_orientation = 0
scrollbar_pos = 0
back_red = 0
back_green = 0
back_blue = 0
text_red = 0
text_green = 65535
text_blue = 0
scroll_background = true
scroll_on_output = false
notebook_border = false
antialias = true
scrollbar = false
use_image = false
grab_focus = true
above = true
notaskbar = true
bold = true
blinks = true
scroll_on_key = true
bell = false
run_command = false
pinned = true
animation = true
hidden = true
centered_horizontally = true
centered_vertically = false
enable_transparency = true
double_buffer = false
}}
}}


It is important you enable the pulldown-animation, otherwise Tilda will keep jumping down each time you unhide it, must be a dwm issue.
This maps taking screenshots to the print key and taking screenshots with a selection box to the shift + print keys.
 
=== Mapping multimedia keys ===
 
Add to the top of {{ic|config.h}},
 
#include <X11/XF86keysym.h>
 
to [[Xmodmap#Keymap table|use multimedia keys]]. Now we can map common tasks to these keys.
 
==== Adjusting volume ====
 
Install the {{Pkg|pipewire}} package. Now in {{ic|config.h}} we may add commands for mute and volume increase/decrease.
 
{{bc|1=
static const char *up_vol[]  = { "pactl", "set-sink-volume", "@DEFAULT_SINK@", "+10%",   NULL };
static const char *down_vol[] = { "pactl", "set-sink-volume", "@DEFAULT_SINK@", "-10%",  NULL };
static const char *mute_vol[] = { "pactl", "set-sink-mute",  "@DEFAULT_SINK@", "toggle", NULL };
...
 
static const Key keys[] = {
      ...
     
      { 0, XF86XK_AudioMute,        spawn, {.v = mute_vol } },
      { 0, XF86XK_AudioLowerVolume, spawn, {.v = down_vol } },
      { 0, XF86XK_AudioRaiseVolume, spawn, {.v = up_vol } },
     
      ...  
};
}}


== Troubleshooting ==
==== Adjusting brightness ====


=== Fixing misbehaving Java applications ===
Install the {{Pkg|brightnessctl}} package. Now in {{ic|config.h}} we may add commands for dimming and brightening the screen.


Try setting {{ic|1=export _JAVA_AWT_WM_NONREPARENTING=1}}.
{{bc|1=
Setting {{ic|1=wmname "LG3D"}} using {{Pkg|wmname}} may help too.
static const char *brighter[] = { "brightnessctl", "set", "10%+", NULL };
Also see the [[Java#Gray window, applications not resizing with WM, menus immediately closing|Java]] page.
static const char *dimmer[]  = { "brightnessctl", "set", "10%-", NULL };
...


=== Fixing gaps around terminal windows ===
static const Key keys[] = {
      ...
     
      { 0, XF86XK_MonBrightnessDown, spawn, {.v = dimmer } },
      { 0, XF86XK_MonBrightnessUp,  spawn, {.v = brighter } },
     
      ...
};
}}


If there are empty gaps of desktop space outside terminal windows, it is likely due to the terminal's font size. Either adjust the size until finding the ideal scale that closes the gap, or toggle {{Ic|resizehints}} to ''0'' in {{ic|config.h}}.
=== Autostart ===


This will cause dwm to ignore resize requests from all client windows, not just terminals. The downside to this workaround is that some terminals may suffer redraw anomalies, such as ghost lines and premature line wraps, among others.
A [https://dwm.suckless.org/patches/autostart/ patch] is available. It runs {{ic|~/.dwm/autostart_blocking.sh}} and {{ic|~/.dwm/autostart.sh &}} before entering the handler loop. One or both of these files can be omitted.


Alternatively, if you use the [[st]] terminal emulator, you can apply the [https://st.suckless.org/patches/anysize/ anysize] patch and recompile st.
== Troubleshooting ==


== Known issues ==
=== Fixing misbehaving Java applications ===


=== Crashes due to Emojis in some fonts ===
See [[Java#Gray window, applications not resizing with WM, menus immediately closing]].


Emojis in title bars may cause dwm to crash with an error similar to the following:
=== Fixing gaps around terminal windows ===


dwm: fatal error: request code=140, error code=16
If there are empty gaps of desktop space outside terminal windows, it is likely due to the terminal's font size. Either adjust the size until finding the ideal scale that closes the gap, or toggle {{ic|resizehints}} to ''0'' in {{ic|config.h}}.
X Error of failed request: BadLength (poly request too large or internal Xlib length error)
  Major opcode of failed request: 140 (RENDER)
  Minor opcode of failed request: 20 (RenderAddGlyphs)
  Serial number of failed request: 4319
  Current serial number in output stream: 4331


This only occurs with some fonts, such as {{pkg|noto-fonts-emoji}} and {{AUR|bdf-unifont}}. See [https://lists.suckless.org/dev/1608/30245.html], [https://lists.suckless.org/dev/1610/30710.html], [https://bbs.archlinux.org/viewtopic.php?id=226928], [https://www.reddit.com/r/archlinux/comments/703ayu/anyone_with_dwm_and_notofontsemoji/], and the upstream bug report [https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6]. Possible workarounds are using a different font or the patch in [https://lists.suckless.org/dev/1610/30720.html].
This will cause dwm to ignore resize requests from all client windows, not just terminals. The downside to this workaround is that some terminals may suffer redraw anomalies, such as ghost lines and premature line wraps, among others.


An upstream fix has been proposed [https://gitlab.freedesktop.org/xorg/lib/libxft/merge_requests/1], but as of writing has not been merged. See {{AUR|libxft-bgra}} and {{AUR|lib32-libxft-bgra}} for patched versions of libXft, properly displaying emoji without crashing.
Alternatively, if you use the [[st]] terminal emulator, you can apply the [https://st.suckless.org/patches/anysize/ anysize] patch and recompile st.


== See also ==
== See also ==

Latest revision as of 08:02, 31 January 2024

dwm is a dynamic window manager for Xorg. It manages windows in tiled, stacked, and full-screen layouts, as well as many others with the help of optional patches. Layouts can be applied dynamically, optimizing the environment for the application in use and the task being performed. dwm is extremely lightweight and fast, written in C and with a stated design goal of remaining under 2000 source lines of code. It provides multihead support for xrandr and Xinerama.

Installation

dwm can be installed with the packages dwmAUR or dwm-gitAUR. Make any required configuration changes before building and installing, see makepkg.

Tip: Upstream instructions can also be followed, but will install files without having pacman keeping track of them.

Configuration

dwm is configured at compile-time by editing some of its source files, specifically config.h. For detailed information on these settings, see the included, well-commented config.def.h as well as the customisation section on the dwm website.

The official website has a number of patches that can add extra functionality to dwm. These patches primarily make changes to the dwm.c file but also make changes to the config.h file where appropriate. For information on applying patches, see the Patching packages article.

Starting

Select Dwm from the menu in a display manager of choice. Alternatively, to start dwm with startx append exec dwm to ~/.xinitrc and prepend other programs to execute them as well, for example:

redshift -O3500; xset r rate 300 50; exec dwm

Usage

See the dwm tutorial for information on basic dwm usage.

Tips and tricks

Statusbar configuration

For more examples of status bars, see [1].

Note: The following requires the xorg-xsetroot package to be installed.

dwm reads the name of the root window and redirects it to the statusbar. The root window is the window within which all other windows are drawn and arranged by the window manager. Like any other window, the root window has a title/name, but it is usually undefined because the root window always runs in the background.

The information that you want dwm to show in the statusbar should be defined with xsetroot -name "" command in ~/.xinitrc or ~/.xprofile (if you are using a display manager). For example:

xsetroot -name "Thanks for all the fish!"

Dynamically updated information should be put in a loop which is forked to background - see the example below:

# Statusbar loop
while true; do
   xsetroot -name "$( date +"%F %R" )"
   sleep 1m    # Update time every minute
done &

# Autostart section
pcmanfm & 

exec dwm

In this case the date is shown in RFC:3339 format and PCManFM is launched at startup.

Note: It is not recommended to set the update interval equal to zero or remove the "sleep" line entirely since this will cause CPU usage to rise substantially (you can assess the effect with top and powertop).

Conky statusbar

Conky can be printed to the statusbar with xsetroot -name:

(conky | while read LINE; do xsetroot -name "$LINE"; done) &
exec dwm

If you do not want to spawn too many PIDs by 'xsetroot' command, you can compile this C program:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xlib.h>

int main(int argc, char * argv[])
{
        Display * dpy = NULL;
        Window win = 0;
        size_t length = 0;
        ssize_t bytes_read = 0;
        char * input = NULL;

        dpy = XOpenDisplay(getenv("DISPLAY"));
        if (dpy == NULL)
        {
                fprintf(stderr, "Can't open display, exiting.\n");
                exit(1);
        }
        win = DefaultRootWindow(dpy);

        while ((bytes_read = getline(&input, &length, stdin)) != EOF)
        {
                input[strlen(input) - 1] = '\0';
                XStoreName(dpy, win, input);
                XFlush(dpy);
                fprintf(stderr, "Input: %s", input);
                fprintf(stderr, "\nbytes read: %ld\n", bytes_read);
        }
        free(input);
        return 0;
}

Save this code to file dwm-setstatus.c, compile:

$ gcc dwm-setstatus.c -lX11 -o dwm-setstatus

move 'dwm-setstatus' within your $PATH (/usr/local/bin, for example)

# mv dwm-setstatus /usr/local/bin

and run:

$ conky | dwm-setstatus

To do this, conky needs to be told to output text to the console only. The following is a sample conkyrc for a dual core CPU, displaying several usage statistics:

conky.config = {
out_to_console = true,
out_to_x = false,
background = false,
update_interval = 2,
total_run_times = 0,
use_spacer = 'none',
};
conky.text = [[
$mpd_smart :: ${cpu cpu1}% / ${cpu cpu2}%  ${loadavg 1} ${loadavg 2 3} :: ${acpitemp}c :: $memperc% ($mem) :: ${downspeed eth0}K/s ${upspeed eth0}K/s :: ${time %a %b %d %I:%M%P}
]];

For icons and color options, see dzen.

Restart dwm

To restart dwm without logging out or closing applications, change or add a startup script so that it loads dwm in a while loop, for example:

while true; do
    # Log stderror to a file 
    dwm 2> ~/.dwm.log
    # No error logging
    #dwm >/dev/null 2>&1
done

dwm can now be restarted without destroying other X windows by pressing the usual Mod-Shift-Q combination.

It is a good idea to place the above startup script into a separate file, ~/bin/startdwm for instance, and execute it through ~/.xinitrc. Consider running the script with exec to avoid security implications with remaining logged in after the X server is terminated; see Xinit#Autostart X at login for more information. From this point on, when you wish to end the X session, simply execute pkill dwm, or bind it to a convenient keybind. Alternatively, you could setup your dwm session script so that it relaunches dwm only if the binary changes. This could be useful in the case where you change a setting or update the dwm code base.

# relaunch DWM if the binary changes, otherwise bail
csum=""
new_csum=$(sha1sum $(which dwm))
while true
do
    if [ "$csum" != "$new_csum" ]
    then
        csum=$new_csum
        dwm
    else
        exit 0
    fi
    new_csum=$(sha1sum $(which dwm))
    sleep 0.5
done

Bind the right Alt key to Mod4

When using Mod4 (the Super/Windows Key) as the MODKEY, it may be equally convenient to have the right Alt key (Alt_R) act as Mod4. This will allow you to perform otherwise awkward keystrokes one-handed, such as zooming with Alt_R+Enter.

First, find out which keycode is assigned to Alt_R:

$ xmodmap -pke | grep Alt_R

Then simply add the following to the startup script (e.g. ~/.xinitrc), changing the keycode 113 if necessary to the result gathered by the previous xmodmap command:

Reassign Alt_R to Super_L:

xmodmap -e "keycode 113 = Super_L"

Make sure X keeps it out of the "mod1" group:

xmodmap -e "remove mod1 = Super_L"

After doing so, any functions that are triggered by the Super_L key press will also be triggered by an Alt_R key press.

Note: There is a #define option in config.h which also allows you to switch the modkey.

Use both Alt keys as Meta in DWM

Use xmodmap to assign Alt_L as a secondary meta key in DWM (provided already using Mod1Mask (Alt_R))

~/.xinitrc
/usr/bin/xmodmap -e "clear mod5"
/usr/bin/xmodmap -e "keycode 108 = Alt_L"

Space around font in dwm's bar

By default, dwm's bar adds 2px around the size of the font. To change this, modify the following line:

dwm.c
bh = dc.h = dc.font.height + 2;

Disable focus follows mouse

To disable focus follows mouse behaviour, comment out the following line in definition of struct handler:

dwm.c
[EnterNotify] = enternotify,

Note that this change can cause some difficulties; the first click on an inactive window will only bring the focus to it. To interact with window contents (buttons, fields etc), you need to click again. Also, if you have several monitors, you may notice that the keyboard focus does not switch to another monitor activated by clicking.

Floating layout for some windows

For some windows, such as preferences dialogs, it does not make sense for these windows to be tiled - they should be free-floating instead. For example, to make Firefox's preferences dialog float, add the following to your rules array in config.h:

{ "Firefox",     NULL,       "Firefox Preferences",        1 << 8,         True,     -1 },

Using Tilda with dwm

Tilda works best when added to all tags, and configured to be floating. To do so, add the following to your rules array in config.h:

{ "Tilda",        NULL,       NULL,                         0,              True,       -1 },

Launch tilda with -C option:

$ tilda -C

Now you can configure Tilda, the following options are provided as a recommendation:

Font: Clean 9
Appearance: Height: 50%, Width: 70%, Centered Horizontally
Extras: Enable Transparency Level 15
Animated Pulldown: 1500 usec, Orientation: Top
Colors: Built-in Scheme "Green on Black"
Scrolling: Scrollbar is on the left, 2000 lines scrollback
Key Binding: F9

It is important you enable the pulldown-animation, otherwise Tilda will keep jumping down each time you unhide it, must be a dwm issue.

Taking screenshots

Install the scrot package. Next create two scripts:

/path/to/scripts/screenshot.sh
#!/bin/sh
mkdir -p /path/to/pics && scrot /path/to/pics/%m-%d-%Y-%H%M%S.png

for making screenshots and

/path/to/scripts/screenshotsel.sh
#!/bin/sh
mkdir -p /path/to/pics && scrot /path/to/pics/%m-%d-%Y-%H%M%S.png --select --line mode=edge

for making screenshots with a selection box. Give them executable permissions. In config.h add the following:

static const Key keys[] = {
       ...
       
       { 0,         XK_Print, spawn, SHCMD("/path/to/scripts/screenshot.sh") },
       { ShiftMask, XK_Print, spawn, SHCMD("/path/to/scripts/screenshotsel.sh") },
       
       ...
};

This maps taking screenshots to the print key and taking screenshots with a selection box to the shift + print keys.

Mapping multimedia keys

Add to the top of config.h,

#include <X11/XF86keysym.h>

to use multimedia keys. Now we can map common tasks to these keys.

Adjusting volume

Install the pipewire package. Now in config.h we may add commands for mute and volume increase/decrease.

static const char *up_vol[]   = { "pactl", "set-sink-volume", "@DEFAULT_SINK@", "+10%",   NULL };
static const char *down_vol[] = { "pactl", "set-sink-volume", "@DEFAULT_SINK@", "-10%",   NULL };
static const char *mute_vol[] = { "pactl", "set-sink-mute",   "@DEFAULT_SINK@", "toggle", NULL };
...

static const Key keys[] = {
       ...
       
       { 0, XF86XK_AudioMute,        spawn, {.v = mute_vol } },
       { 0, XF86XK_AudioLowerVolume, spawn, {.v = down_vol } },
       { 0, XF86XK_AudioRaiseVolume, spawn, {.v = up_vol } },
       
       ... 
};

Adjusting brightness

Install the brightnessctl package. Now in config.h we may add commands for dimming and brightening the screen.

static const char *brighter[] = { "brightnessctl", "set", "10%+", NULL };
static const char *dimmer[]   = { "brightnessctl", "set", "10%-", NULL };
...

static const Key keys[] = {
       ...
       
       { 0, XF86XK_MonBrightnessDown, spawn, {.v = dimmer } },
       { 0, XF86XK_MonBrightnessUp,   spawn, {.v = brighter } },
       
       ...
};

Autostart

A patch is available. It runs ~/.dwm/autostart_blocking.sh and ~/.dwm/autostart.sh & before entering the handler loop. One or both of these files can be omitted.

Troubleshooting

Fixing misbehaving Java applications

See Java#Gray window, applications not resizing with WM, menus immediately closing.

Fixing gaps around terminal windows

If there are empty gaps of desktop space outside terminal windows, it is likely due to the terminal's font size. Either adjust the size until finding the ideal scale that closes the gap, or toggle resizehints to 0 in config.h.

This will cause dwm to ignore resize requests from all client windows, not just terminals. The downside to this workaround is that some terminals may suffer redraw anomalies, such as ghost lines and premature line wraps, among others.

Alternatively, if you use the st terminal emulator, you can apply the anysize patch and recompile st.

See also