FreeBSD and dwl on a 2010 ThinkPad
A Minimalist Wayland Setup on Aging Hardware

FreeBSD is a Unix operating system with a long history of stability, clean design, and excellent documentation. Older hardware tends to run it particularly well: mature driver support and a lean base system make aging machines surprisingly capable. Old does not necessarily mean obsolete, provided the hardware is paired with the right OS and the software stack remains minimal.
This write-up covers a 2010 ThinkPad L412 with an Intel Core i3-350M and 8 GB RAM running FreeBSD 15.0 with dwl as the Wayland compositor. dwl is the Wayland equivalent of dwm, the well-known X11 window manager from the suckless project. It is minimal, efficient, and follows the Unix philosophy — you start with the bare minimum and add only what you need. The result is a modern Wayland desktop running on sixteen-year-old hardware that remains usable for everyday tasks.
For installation, I followed the FreeBSD Handbook and installed FreeBSD 15.0 with only the base system, sh shell and lib32 on a UFS filesystem. The installation itself was straightforward. The only notable limitation was Wi-Fi: on this hardware the driver works reliably only on the 2.4 GHz band. The 5 GHz band proved highly unstable and was practically unusable.
The following section walks through the dwl installation process in enough detail to reproduce this setup.
Required packages for dwl
wayland, wayland-protocols
drm-kmod (GPU driver)
wlroots019 (for dwl-0.8)
foot (terminal)
dejavu (my preferred font)
wmenu (dmenu equivalent)
wl-clipboard, grim, slurp (clipboard and screenshots)
swaybg (for background image)
mako (notification daemon)
neovim (editor)
gmake, gcc, pkgconf, evdev-proto (for compliation)
fcft, tllist
wget, firefox , neovim
sudo pkg install wayland wayland-protocols drm-kmod wlroots019 foot dejavu
sudo pkg install wmenu wl-clipboard grim slurp swaybg mako neovim
sudo pkg install gmake gcc pkgconf evdev-proto fcft tllist wget firefox
Note: sudo is not included in the base system on FreeBSD, so install it first (pkg install sudo) or run commands as root.
System configuration
Enable seatd
sudo sysrc seatd_enable="YES"
sudo service seatd start
# Add to .profile
export LIBSEAT_BACKEND="seatd"
Add your user to the video/input groups
sudo pw groupmod video -m [your_username]
sudo pw groupmod input -m [your_username]
Enable audio server
sudo sysrc sndiod_enable="YES"
sudo service sndiod start
Load GPU driver
sudo kldload /boot/modules/i915kms.ko
# Make it permanent adding to /etc/rc.conf
sudo sysrc kld_list+="/boot/modules/i915kms.ko"
Update evdev-proto header path
sudo ln -s /usr/local/include/linux /usr/include/linux
Enable UTF-8 for foot
# Add to .profile
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
Note: logout-login to take effect.
Building dwl
Download dwl 0.8 and slstatus 1.1 from their respective repositories and extract them.
wget https://codeberg.org/dwl/dwl/archive/v0.8.tar.gz
wget https://dl.suckless.org/tools/slstatus-1.1.tar.gz
tar xvf v0.8.tar.gz
tar xvf slstatus-1.1.tar.gz
To customize dwl, edit config.def.h and apply patches as needed. For reference, here is the list of patches I applied in this setup:
attachbottom,movestack,pertagfor my preferred dwl behavior.bar- necessary patch for a status-bar
The command to patch:
patch -i bar.patch
Note: If a patch fails to apply cleanly, the compiler output will indicate what needs to be adjusted, and the changes must be applied manually.
Unlike dwm, the dwl patches does not include a focusadjacenttag patch, so I implemented the modification myself. This mod adds two functions: one to focus the tag immediately to the left or right of the currently active tag, and another to move the focused window to the adjacent tag in either direction.
// Equivalent to focusadjacenttag dwm patch
// Add to dwl.c
static void viewtoadjacent(const Arg *arg);
static void tagtoadjacent(const Arg *arg);
void
viewtoadjacent(const Arg *arg)
{
unsigned int newtag;
unsigned int curtag = selmon->tagset[selmon->seltags];
if (arg->i > 0) // Cycle Right
newtag = (curtag << 1);
else // Cycle Left
newtag = (curtag >> 1);
// Wrap around logic for standard 9 tags
if (newtag >= (1 << TAGCOUNT)) newtag = 1;
if (newtag <= 0) newtag = (1 << (TAGCOUNT - 1));
view(&(Arg){.ui = newtag});
}
void
tagtoadjacent(const Arg *arg)
{
Client *c = focustop(selmon);
unsigned int newtag;
unsigned int curtag;
if (!c)
return;
curtag = c->tags;
if (arg->i > 0) // Shift Right
newtag = (curtag << 1);
else // Shift Left
newtag = (curtag >> 1);
// Wrap around logic for standard 9 tags
if (newtag >= (1 << TAGCOUNT)) newtag = 1;
if (newtag <= 0) newtag = (1 << (TAGCOUNT - 1));
tag(&(Arg){.ui = newtag});
}
// Add to config.def.h
/* tagging */
#define TAGCOUNT 9
/* modifier key function argument */
{ MODKEY, XKB_KEY_Left, viewtoadjacent, {.i = -1} },
{ MODKEY, XKB_KEY_Right, viewtoadjacent, {.i = +1} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left, tagtoadjacent, {.i = -1} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right, tagtoadjacent, {.i = +1} },
For screenshots, use grim and slurp with the following settings in config.def.h. Screenshots are copied to the clipboard via wl-copy and also saved in the ~/Pictures/Screenshots directory.
/* Region Screenshot with Notification */
static const char *scrregion[] = { "sh", "-c", "grim -g \"\((slurp)\" - | tee ~/Pictures/Screenshots/\)(date +%Y-%m-%d_%H-%m-%s).png | wl-copy && notify-send 'Region Saved'", NULL };
/* Full Screen Screenshot with Notification */
static const char *scrfull[] = { "sh", "-c", "grim - | tee ~/Pictures/Screenshots/$(date +%Y-%m-%d_%H-%m-%s).png | wl-copy && notify-send 'Full Screen Saved'", NULL };
/* modifier key function argument */
{ MODKEY, XKB_KEY_p, spawn, {.v = scrfull } },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_p, spawn, {.v = scrregion } },
To customize keybindings and appearance, edit config.def.h t, then copy it to config.h . Build and install.
cp config.def.h config.h
sudo gmake clean install
Slstatus is can be customized the same way. For FreeBSD `config.mk` has to be modified.
# Add to config.mk
LDLIBS = -lX11 -lkvm -lsndio
Startup script
In $HOME/bin create sdwl script (with chmod +x) to launch dwl. You can set your wallpaper there, displayed using swaybg.
#!/bin/sh
export $(dbus-launch)
mako &
slstatus -s | dwl -s "sh -c 'swaybg -i ~/Pictures/BSDviolet.png &'"
Configuration
I use the Dracula color scheme for foot and Neovim, with the vim-startify and vim-airline plugins. mako is also configured for Wayland notifications. The setup uses the DejaVu font. No gaps, no Nerd Fonts, no icons on the status bar. It’s purely functional and minimal, keeping the desktop clean and efficient.
All configuration files, including the wallpaper, are available in my GitHub repository. The wallpaper is AI-generated. Screenshots are shown below.
Conclusion
FreeBSD with dwl results in a usable and surprisingly snappy system on this old, modest hardware. On a fresh start, total memory usage (Active + Wired + Laundry) stays under 700 MB, disk usage is 8 GB. Hopefully this guide proves useful for anyone looking to revive older machines with a minimal Wayland setup.





