# FreeBSD and dwl on a 2010 ThinkPad 


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](https://docs.freebsd.org/en/books/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
    

```plaintext
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

```plaintext
sudo sysrc seatd_enable="YES"
sudo service seatd start

# Add to .profile
export LIBSEAT_BACKEND="seatd"
```

Add your user to the video/input groups

```plaintext
sudo pw groupmod video -m [your_username]
sudo pw groupmod input -m [your_username]
```

Enable audio server

```plaintext
sudo sysrc sndiod_enable="YES"
sudo service sndiod start
```

Load GPU driver

```plaintext
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

```plaintext
sudo ln -s /usr/local/include/linux /usr/include/linux
```

Enable UTF-8 for foot

```plaintext
# 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.

```plaintext
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](https://codeberg.org/dwl/dwl-patches) as needed. For reference, here is the list of patches I applied in this setup:

*   `attachbottom`, `movestack`, `pertag` for my preferred **dwl** behavior.
    
*   `bar` - necessary patch for a status-bar
    

The command to patch:

```plaintext
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.

```c
// 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.

```c
/* 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.

```plaintext
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.

```plaintext
# 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`.

```plaintext
#!/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](https://github.com/awklab/FreeBSD-dwl) repository. The wallpaper is AI-generated. Screenshots are shown below.

![FreeBSD with dwl, neovim, violet theme](https://cdn.hashnode.com/uploads/covers/6977b73612a913b189a167d8/3bcb562b-e3c0-4a3f-a8db-2dc14cfe865c.png align="center")

<br>

![FreeBsd with dwl, tiling setup, foot, htop, neofetch, neovim](https://cdn.hashnode.com/uploads/covers/6977b73612a913b189a167d8/1cc220b6-f6c3-4d8a-a280-99bb435105e1.png align="center")

## 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.
