How to patch DWL
So you want to patch DWL, the dynamic wayland- nevermind. This guide will teach you how to do exactly that, plus how to use git to save your config!
Getting DWL itself
First, you’ll want to grab a copy of the DWL repository from Codeberg. You could get a source tarball, but I’m going to use Git to get the repo.
1$ git clone https://codeberg.org/dwl/dwl
2$ cd dwl/
First, configure config.mk
to enable Xwayland support.
1# paths
2PREFIX = /usr
3MANDIR = $(PREFIX)/share/man
4DATADIR = $(PREFIX)/share
5
6# Uncomment to build XWayland support
7XWAYLAND = -DXWAYLAND
8XLIBS = xcb xcb-icccm
Now run make
to compile the program for the first time. If you get any errors about missing libraries, install DWL’s required dependencies. (They’re all listed in the README.md
file.) You’ll notice a lot of *.o
files generated after the compilation. Run make clean
to clear up all the junk, because you probably don’t want to install DWL without any patches installed or configuration changes. What you want is the config.h
file, NOT the config.def.h
file. This file should not be modified manually. When you patch DWL, that file will be edited, and you need to port those changes to config.h
.
Configuring DWL
Now edit config.h
to your heart’s content. It should be pretty simple to understand, but I will guide you through some things.
Don’t edit the COLOR(hex)
function thing, because I’m pretty sure that’s whats converting the colors in the config.
For all the libinput stuff, I don’t mess with it, except for one setting:
1static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
2static const double accel_speed = 0.1;
Because my mouse behaves weirdly with the adaptive profile.
Do NOT leave any of the rules empty. (window rules, monitor rules) Not doing this will lead to problems. See https://codeberg.org/dwl/dwl/issues/656.
A Note on Git
Before continuing with patching DWL, I would like to ask you to backup your build with Git.
What is Git? From the git website:
Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.
Basically we’re going to be using Git as a backup and versioning system here. This will allow us to selectively delete changes without deleting everything. For example, if you patch something but decide to remove it and patch -R
doesn’t work, you’re going to have to restart everything. Git prevents this (if you have your changes committed!)
If you downloaded the DWL repo via tarball, do git init
to initialize a new git repo.
gitignore
Add/edit your .gitignore
to leave out junk *.o
files and other unneeded files. A gitignore file makes git literally ignore the files when doing git add
, which I’ll go into more detail later.
dwl
*.o
*-protocol.c
*-protocol.h
.ccls-cache
*.rej
*.orig
This is what I have in my .gitignore
. For people who git clone
‘ed the repo, edit the file to add the last two lines because those leftover files from patching are annoying.
Adding Files and Committing them
Now, we need to add the changed files into Git’s staging area. I usually just do git add .
, but you can add files one by one if you would like to be extra careful. As I mentioned earlier, the files listed in your .gitignore
will not be added to the staging area even if you manually add them, since they’re basically nonexistent in the eyes of Git.
Check the staged changes with git diff --staged
.
Once you’re sure everything is great, commit the changes with git commit
. It’ll open your default text editor (neovim for me) and you can enter a commit message. If you want to skip that, do git commit -m "<messge here>"
.
Patching DWL
Patching DWL means adding new functionality to it, such as gaps or a bar!
To get started, head to the dwl-patches repo. You’ll notice that there are two folders _STALE_PATCHES/
and patches/
.
Stale Patches
_STALE_PATCHES/
are patches that:
- Do not apply cleanly;
- Are abandoned;
- Retired;
- Or do not work.
You can try your luck applying these patches, but most of them do not even work. I’ve found only 3 that work but don’t apply cleanly.
Actually doing the patching
First, grab the patch from the repo and I recommend putting patches in a patches/
directory in the DWL repo.
There are two patching programs, Git and GNU Patch. You can apply patches with git am -3
or patch -p1
.
You apply patches with patch -p1 foo.patch
using GNU Patch.
WARNING Note the “<” in
patch -p1 < foo.patch
. I’m not sure what happens if you put a “>”, but I think bad things will happen if you put a “>”.
If you’re lucky, the patch will apply cleanly. GNU Patch is not a dumb program, and will still apply the patch if the line is off by a few lines. However, it will fail if the lines surrounding the line changed are different than the lines surrounding the lines changed in the patch file.
For example, I’m applying the gaps patch made by sewn.
1$ patch -p1 < gaps.patch
2patching file config.def.h
3Hunk #2 succeeded at 138 (offset 1 line).
4patching file dwl.c
5Hunk #1 succeeded at 201 (offset 1 line).
6Hunk #2 succeeded at 340 (offset 1 line).
7Hunk #3 succeeded at 941 (offset 3 lines).
8Hunk #4 succeeded at 2633 (offset 3 lines).
9Hunk #5 succeeded at 2642 (offset 3 lines).
10Hunk #6 succeeded at 2688 (offset 3 lines).
As you can see, GNU Patch still applies the patch even though the changes are offset by a few lines.
Now, let’s try to apply another patch, say minimalborders!
1$ patch -p1 < minimalborders.patch
2patching file config.def.h
3Hunk #1 succeeded at 10 with fuzz 2 (offset 3 lines).
4patching file dwl.c
5Hunk #1 succeeded at 107 (offset 2 lines).
6Hunk #2 succeeded at 321 (offset 8 lines).
7Hunk #3 succeeded at 415 (offset 8 lines).
8Hunk #4 succeeded at 485 (offset 8 lines).
9Hunk #5 succeeded at 548 with fuzz 2 (offset 22 lines).
10Hunk #6 FAILED at 1936.
11Hunk #7 succeeded at 2182 with fuzz 2 (offset 97 lines).
12Hunk #8 succeeded at 2214 (offset 103 lines).
131 out of 8 hunks FAILED -- saving rejects to file dwl.c.rej
Oh no! It seems like there’s one hunk that failed, number 6 at line 1938. Unfortunately, patch can’t do anything for you anymore, and we need to edit the file dwl.c
ourselves.
Open up dwl.c.rej
in your text editor and see what needs to be chanegd:
1--- dwl.c
2+++ dwl.c
3@@ -1936,8 +1989,13 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
4 struct timespec now;
5
6 if ((!active_constraint || active_constraint->surface != surface) &&
7- sloppyfocus && time && c && !client_is_unmanaged(c))
8- focusclient(c, 0);
9+ sloppyfocus && time && c && !client_is_unmanaged(c)) {
10+ if (c->isfloating || c->isfullscreen) {
11+ focusclient(c, 0);
12+ } else {
13+ focusclient(c, 1);
14+ }
15+ }
16
17 /* If surface is NULL, clear pointer focus */
18 if (!surface) {
The lines with “-” need to be deleted and “+” needs to be added.
And this is the exact part in dwl.c
:
1void
2pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
3 uint32_t time)
4{
5 struct timespec now;
6
7 if (surface != seat->pointer_state.focused_surface &&
8 sloppyfocus && time && c && !client_is_unmanaged(c))
9 focusclient(c, 0);
10
11 /* If surface is NULL, clear pointer focus */
12 if (!surface) {
As you can see, there’s one line that was changed entirely, which confused patch and made it fail.
Now, we can changed the lines according to the patch!
This is the fixed version:
1void
2pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
3 uint32_t time)
4{
5 struct timespec now;
6
7 if (surface != seat->pointer_state.focused_surface &&
8 sloppyfocus && time && c && !client_is_unmanaged(c)) {
9 if (c->isfloating || c->isfullscreen) {
10 focusclient(c, 0);
11 } else {
12 focusclient(c, 1);
13 }
14 }
15
16 /* If surface is NULL, clear pointer focus */
17 if (!surface) {
Now once we’re done with patching, we can run make
and see it compile successfu-
Oh wait nevermind, for some patches, it might error out, because the patch might’ve modified config.def.h
to add extra configuration options, and since your config.h
does not include the options, the compilation errors out. What you need to do is to backport the changed to config.h
.
Saving your changes
See here to save your changes with Git.
What happens if you want to reverse your changes but you’ve already committed them? Well, you can do git reset --soft HEAD~1
to reset the latest commit without delete your changes made. If you want to delete all changes too, git reset --hard HEAD~1
exists. If you want to delete/edit a commit that’s not the latest commit, use git rebase -i <hash of your commit>
. Doing this is more complicated than I can explain, (I don’t even understand how git rebase even works :3) but there’s a Stack Overflow post that explains it pretty well.
Conclusion
Credits:
- Oak for corrections
Now you know how to patch DWL, and software in general. I hope you found this guide useful! If you want to learn more about patching and diff files, there’s a Luke Smith video that explains it: