diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index bba41804e3e3c96f6c790a706109337f19234644..0424753704e1bf4d8a7674f8edab6ae4d8702647 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,14 +1,13 @@
-build-buffyboard:
+build-and-test-buffyboard:
   image: alpine:3.19
   tags:
     - saas-linux-small-amd64
   script:
-    - apk -q add git build-base meson linux-headers inih-dev libinput-dev eudev-dev
+    - apk -q add git bash build-base meson linux-headers inih-dev libinput-dev eudev-dev
     - git submodule init
     - git submodule update
     - cd buffyboard
-    - meson _build
-    - meson compile -C _build
+    - ./test/test-all.sh
 
 build-and-test-unl0kr-with-drm:
   image: alpine:3.19
@@ -31,3 +30,13 @@ build-and-test-unl0kr-without-drm:
     - git submodule update
     - cd unl0kr
     - ./test/test-without-drm.sh
+
+build-iskey:
+  image: alpine:3.19
+  tags:
+    - saas-linux-small-amd64
+  script:
+    - apk -q add git bash build-base meson linux-headers libevdev-dev
+    - cd iskey
+    - meson setup _build
+    - meson compile -C _build
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cec4697d05354e5d75a7aa5da36a14ed73658637..6313c5515f03b000a80cb93cb27c42bfb9517a21 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,15 +10,21 @@ If a change only affects particular applications, they are listed in parentheses
 
 ## Unreleased
 
+- feat: Add adwaita-dark theme (thanks @topjor)
+- feat: Add Nord themes
+
+## 3.1.0 (2024-04-10)
+
 - feat(buffyboard): Handle input device connection/disconnection at runtime; adds new dependency libudev
 - feat(buffyboard): Allow choosing theme via config and add all themes from unl0kr
 - feat(buffyboard): Add fbdev force-refresh quirk via config
 - feat(buffyboard): Allow disabling input devices via config
 - feat(buffyboard): Add CLI flags for overriding geometry & DPI
+- feat(buffyboard): Add CLI flag for verbose logging
 - fix(unl0kr): Shutdown message box doesn't close on decline
 - fix(unl0kr): Shutdown message box buttons and label are unstyled
 - fix(unl0kr): Build fails when DRM is disabled
-- misc: Update lvgl to git master (2023-03-30)
+- misc: Update lvgl to git master (2023-04-10)
 
 ## 3.0.0 (2024-03-22)
 
diff --git a/README.md b/README.md
index ade831eef4505788e70f564341937ae8c7b09443..92cad1710f661f5142b818616392c28d6d12631f 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,8 @@ BuffyBox is a suite of graphical applications for the terminal.
 
 **[squeek2lvgl]** – Converter for transforming [Squeekboard] layouts into [LVGL]-compatible C code
 
+**[iskey]** - A utility for checking for key presses in bash scripts.
+
 **[shared]** – Internal code that is shared by some or all applications in the suite but not meant to be used externally 
 
 ## Contributing
@@ -44,6 +46,7 @@ For the license of bundled images and fonts, see [shared/cursor] and [shared/fon
 [LVGL]: https://github.com/lvgl/lvgl
 [shared]: ./shared
 [squeek2lvgl]: ./squeek2lvgl
+[iskey]: ./iskey
 [Squeekboard]: https://gitlab.gnome.org/World/Phosh/squeekboard
 [shared/cursor]: ./shared/cursor
 [shared/fonts]: ./shared/fonts
diff --git a/buffyboard/README.md b/buffyboard/README.md
index 648d4642ba019141ddaabdb17585c98af0bd9a16..9683077d02f7aa179a8a096d92c445f8bf7cfdf3 100644
--- a/buffyboard/README.md
+++ b/buffyboard/README.md
@@ -59,6 +59,7 @@ Mandatory arguments to long options are mandatory for short options too.
                             * 2 - upside down orientation (180 degrees)
                             * 3 - counterclockwise orientation (270 degrees)
   -h, --help                Print this message and exit
+  -v, --verbose             Enable more detailed logging output on STDERR
   -V, --version             Print the buffyboard version and exit
 ```
 
@@ -108,7 +109,15 @@ Buffyboard uses [squeekboard layouts] converted to C via [squeek2lvgl]. To regen
 $ ./regenerate-layouts.sh
 ```
 
-from the root of the repository.
+## Generating screenshots
+
+To generate screenshots in a variety of common sizes, install [fbcat], build buffyboard and then run
+
+```
+$ sudo ./regenerate-screenshots _build/buffyboard
+```
+
+where `_build/buffyboard` is the location of the buffyboard binary.
 
 # Acknowledgements
 
@@ -126,6 +135,7 @@ Buffyboard was inspired by [fbkeyboard].
 [LVGL]: https://lvgl.io
 [arrow-alt-circle-up]: https://fontawesome.com/v5.15/icons/arrow-alt-circle-up?style=solid
 [buffyboard.conf]: ./buffyboard.conf
+[fbcat]: https://github.com/jwilk/fbcat
 [fbkeyboard]: https://github.com/bakonyiferenc/fbkeyboard
 [inih]: https://github.com/benhoyt/inih
 [libinput]: https://gitlab.freedesktop.org/libinput/libinput
diff --git a/buffyboard/command_line.c b/buffyboard/command_line.c
index 747aa9c8138e648158b60307fdd9d3be08b08abd..b8498763ac7703e890caac9a13e0e796d1be1106 100644
--- a/buffyboard/command_line.c
+++ b/buffyboard/command_line.c
@@ -45,6 +45,7 @@ static void init_opts(bb_cli_opts *opts) {
     opts->y_offset = 0;
     opts->dpi = 0;
     opts->rotation = LV_DISPLAY_ROTATION_0;
+    opts->verbose = false;
 }
 
 static void print_usage() {
@@ -71,6 +72,7 @@ static void print_usage() {
         "                            * 2 - upside down orientation (180 degrees)\n"
         "                            * 3 - counterclockwise orientation (270 degrees)\n"
         "  -h, --help                Print this message and exit\n"
+        "  -v, --verbose             Enable more detailed logging output on STDERR\n"
         "  -V, --version             Print the buffyboard version and exit\n");
         /*-------------------------------- 78 CHARS --------------------------------*/
 }
@@ -89,13 +91,14 @@ void bb_cli_parse_opts(int argc, char *argv[], bb_cli_opts *opts) {
         { "dpi",             required_argument, NULL, 'd' },
         { "rotate",          required_argument, NULL, 'r' },
         { "help",            no_argument,       NULL, 'h' },
+        { "verbose",         no_argument,       NULL, 'v' },
         { "version",         no_argument,       NULL, 'V' },
         { NULL, 0, NULL, 0 }
     };
 
     int opt, index = 0;
 
-    while ((opt = getopt_long(argc, argv, "C:g:d:r:hV", long_opts, &index)) != -1) {
+    while ((opt = getopt_long(argc, argv, "C:g:d:r:hvV", long_opts, &index)) != -1) {
         switch (opt) {
         case 'C':
             opts->config_files = realloc(opts->config_files, (opts->num_config_files + 1) * sizeof(char *));
@@ -145,6 +148,9 @@ void bb_cli_parse_opts(int argc, char *argv[], bb_cli_opts *opts) {
         case 'h':
             print_usage();
             exit(EXIT_SUCCESS);
+        case 'v':
+            opts->verbose = true;
+            break;
         case 'V':
             fprintf(stderr, "buffyboard %s\n", BB_VERSION);
             exit(0);
diff --git a/buffyboard/command_line.h b/buffyboard/command_line.h
index b8dc3992e0d411bcb6fa0c8c7beb990debd40f6d..009b44fcb0a38ef3e12426cb77bfb34b0f397e7d 100644
--- a/buffyboard/command_line.h
+++ b/buffyboard/command_line.h
@@ -29,6 +29,8 @@ typedef struct {
     int dpi;
     /* Display rotation */
     lv_display_rotation_t rotation;
+    /* Verbose mode. If true, provide more detailed logging output on STDERR. */
+    bool verbose;
 } bb_cli_opts;
 
 /**
diff --git a/buffyboard/main.c b/buffyboard/main.c
index 1599c0373059ea5dbf88647e18d80bc59a79f0b7..317445fd0c7db80a6fea0f945a82b9d8b7fec719 100644
--- a/buffyboard/main.c
+++ b/buffyboard/main.c
@@ -14,6 +14,7 @@
 #include "lvgl/lvgl.h"
 
 #include "../shared/indev.h"
+#include "../shared/log.h"
 #include "../shared/theme.h"
 #include "../shared/themes.h"
 #include "../squeek2lvgl/sq2lv.h"
@@ -180,6 +181,11 @@ int main(int argc, char *argv[]) {
     /* Parse command line options */
     bb_cli_parse_opts(argc, argv, &cli_opts);
 
+    /* Set up log level */
+    if (cli_opts.verbose) {
+        bbx_log_set_level(BBX_LOG_LEVEL_VERBOSE);
+    }
+
     /* Parse config files */
     bb_config_init_opts(&conf_opts);
     bb_config_parse_file("/etc/buffyboard.conf", &conf_opts);
diff --git a/buffyboard/meson.build b/buffyboard/meson.build
index 246bced9d691014cb19720b887ebb5375ba307fd..5f5f49a48802cac155a1e8312155112c32a220f6 100644
--- a/buffyboard/meson.build
+++ b/buffyboard/meson.build
@@ -5,7 +5,7 @@
 project(
   'buffyboard',
   'c',
-  version: '3.0.0',
+  version: '3.1.0',
   default_options: 'warning_level=1',
   meson_version: '>=0.53.0'
 )
diff --git a/buffyboard/regenerate-screenshots.sh b/buffyboard/regenerate-screenshots.sh
index 5e7625505ec84d66f29e6e029b33e50dc2ca9159..3848f7151a7278b97558242e7f5d9647c1e7de3f 100755
--- a/buffyboard/regenerate-screenshots.sh
+++ b/buffyboard/regenerate-screenshots.sh
@@ -7,14 +7,8 @@ executable=$1
 outdir=screenshots
 config=buffyboard-screenshots.conf
 
-themes=(
-    breezy-light
-    breezy-dark
-    pmos-light
-    pmos-dark
-    nord-light
-    nord-dark
-)
+root=$(git rev-parse --show-toplevel)
+themes_c=$root/shared/themes.c
 
 resolutions=(
     # Nokia N900
@@ -34,6 +28,11 @@ resolutions=(
     1920x1080
 )
 
+if ! which fbcat > /dev/null 2>&1; then
+    echo "Error: Could not find fbcat" 1>&2
+    exit 1
+fi
+
 if [[ ! -f $executable || ! -x $executable ]]; then
     echo "Error: Could not find executable at $executable" 1>&2
     exit 1
@@ -63,7 +62,7 @@ readme="# Buffyboard themes"$'\n'
 
 clear # Blank the screen
 
-for theme in ${themes[@]}; do
+while read -r theme; do
     write_config $theme
 
     readme="$readme"$'\n'"## $theme"$'\n\n'
@@ -74,8 +73,11 @@ for theme in ${themes[@]}; do
 
         sleep 3 # Wait for UI to render
 
-        ../../fbcat/fbcat /dev/fb0 > "$outdir/$theme-$res.ppm"
-        convert -size $fb_res \
+        fbcat /dev/fb0 > "$outdir/$theme-$res.ppm"
+        kill -15 $pid
+
+        convert \
+            -size $fb_res \
             $outdir/$theme-$res.ppm \
             screenshot-background.png \
             -crop $res+0+0 \
@@ -84,12 +86,11 @@ for theme in ${themes[@]}; do
             "$outdir/$theme-$res.png"
 
         rm "$outdir/$theme-$res.ppm"
-        kill -15 $pid
 
         readme="$readme<img src=\"$theme-$res.png\" alt=\"$res\" height=\"300\"/>"$'\n'
 
         sleep 1 # Delay to prevent terminal mode set / reset interference
     done
-done
+done < <(grep "name =" "$themes_c" | grep -o '".*"' | tr -d '"' | sort)
 
 echo -n "$readme" > "$outdir/README.md"
diff --git a/buffyboard/screenshots/README.md b/buffyboard/screenshots/README.md
index 0677e8388be88fd2b7eca93d558cf6a12c0108ea..1319e078a3c817cb05466ebdc742d7a8cc14ffde 100644
--- a/buffyboard/screenshots/README.md
+++ b/buffyboard/screenshots/README.md
@@ -1,16 +1,16 @@
 # Buffyboard themes
 
-## breezy-light
+## adwaita-dark
 
-<img src="breezy-light-480x800.png" alt="480x800" height="300"/>
-<img src="breezy-light-800x480.png" alt="800x480" height="300"/>
-<img src="breezy-light-540x960.png" alt="540x960" height="300"/>
-<img src="breezy-light-960x540.png" alt="960x540" height="300"/>
-<img src="breezy-light-768x1024.png" alt="768x1024" height="300"/>
-<img src="breezy-light-1024x768.png" alt="1024x768" height="300"/>
-<img src="breezy-light-1280x800.png" alt="1280x800" height="300"/>
-<img src="breezy-light-1440x720.png" alt="1440x720" height="300"/>
-<img src="breezy-light-1920x1080.png" alt="1920x1080" height="300"/>
+<img src="adwaita-dark-480x800.png" alt="480x800" height="300"/>
+<img src="adwaita-dark-800x480.png" alt="800x480" height="300"/>
+<img src="adwaita-dark-540x960.png" alt="540x960" height="300"/>
+<img src="adwaita-dark-960x540.png" alt="960x540" height="300"/>
+<img src="adwaita-dark-768x1024.png" alt="768x1024" height="300"/>
+<img src="adwaita-dark-1024x768.png" alt="1024x768" height="300"/>
+<img src="adwaita-dark-1280x800.png" alt="1280x800" height="300"/>
+<img src="adwaita-dark-1440x720.png" alt="1440x720" height="300"/>
+<img src="adwaita-dark-1920x1080.png" alt="1920x1080" height="300"/>
 
 ## breezy-dark
 
@@ -24,29 +24,29 @@
 <img src="breezy-dark-1440x720.png" alt="1440x720" height="300"/>
 <img src="breezy-dark-1920x1080.png" alt="1920x1080" height="300"/>
 
-## pmos-light
+## breezy-light
 
-<img src="pmos-light-480x800.png" alt="480x800" height="300"/>
-<img src="pmos-light-800x480.png" alt="800x480" height="300"/>
-<img src="pmos-light-540x960.png" alt="540x960" height="300"/>
-<img src="pmos-light-960x540.png" alt="960x540" height="300"/>
-<img src="pmos-light-768x1024.png" alt="768x1024" height="300"/>
-<img src="pmos-light-1024x768.png" alt="1024x768" height="300"/>
-<img src="pmos-light-1280x800.png" alt="1280x800" height="300"/>
-<img src="pmos-light-1440x720.png" alt="1440x720" height="300"/>
-<img src="pmos-light-1920x1080.png" alt="1920x1080" height="300"/>
+<img src="breezy-light-480x800.png" alt="480x800" height="300"/>
+<img src="breezy-light-800x480.png" alt="800x480" height="300"/>
+<img src="breezy-light-540x960.png" alt="540x960" height="300"/>
+<img src="breezy-light-960x540.png" alt="960x540" height="300"/>
+<img src="breezy-light-768x1024.png" alt="768x1024" height="300"/>
+<img src="breezy-light-1024x768.png" alt="1024x768" height="300"/>
+<img src="breezy-light-1280x800.png" alt="1280x800" height="300"/>
+<img src="breezy-light-1440x720.png" alt="1440x720" height="300"/>
+<img src="breezy-light-1920x1080.png" alt="1920x1080" height="300"/>
 
-## pmos-dark
+## nord-dark
 
-<img src="pmos-dark-480x800.png" alt="480x800" height="300"/>
-<img src="pmos-dark-800x480.png" alt="800x480" height="300"/>
-<img src="pmos-dark-540x960.png" alt="540x960" height="300"/>
-<img src="pmos-dark-960x540.png" alt="960x540" height="300"/>
-<img src="pmos-dark-768x1024.png" alt="768x1024" height="300"/>
-<img src="pmos-dark-1024x768.png" alt="1024x768" height="300"/>
-<img src="pmos-dark-1280x800.png" alt="1280x800" height="300"/>
-<img src="pmos-dark-1440x720.png" alt="1440x720" height="300"/>
-<img src="pmos-dark-1920x1080.png" alt="1920x1080" height="300"/>
+<img src="nord-dark-480x800.png" alt="480x800" height="300"/>
+<img src="nord-dark-800x480.png" alt="800x480" height="300"/>
+<img src="nord-dark-540x960.png" alt="540x960" height="300"/>
+<img src="nord-dark-960x540.png" alt="960x540" height="300"/>
+<img src="nord-dark-768x1024.png" alt="768x1024" height="300"/>
+<img src="nord-dark-1024x768.png" alt="1024x768" height="300"/>
+<img src="nord-dark-1280x800.png" alt="1280x800" height="300"/>
+<img src="nord-dark-1440x720.png" alt="1440x720" height="300"/>
+<img src="nord-dark-1920x1080.png" alt="1920x1080" height="300"/>
 
 ## nord-light
 
@@ -60,14 +60,26 @@
 <img src="nord-light-1440x720.png" alt="1440x720" height="300"/>
 <img src="nord-light-1920x1080.png" alt="1920x1080" height="300"/>
 
-## nord-dark
+## pmos-dark
 
-<img src="nord-dark-480x800.png" alt="480x800" height="300"/>
-<img src="nord-dark-800x480.png" alt="800x480" height="300"/>
-<img src="nord-dark-540x960.png" alt="540x960" height="300"/>
-<img src="nord-dark-960x540.png" alt="960x540" height="300"/>
-<img src="nord-dark-768x1024.png" alt="768x1024" height="300"/>
-<img src="nord-dark-1024x768.png" alt="1024x768" height="300"/>
-<img src="nord-dark-1280x800.png" alt="1280x800" height="300"/>
-<img src="nord-dark-1440x720.png" alt="1440x720" height="300"/>
-<img src="nord-dark-1920x1080.png" alt="1920x1080" height="300"/>
+<img src="pmos-dark-480x800.png" alt="480x800" height="300"/>
+<img src="pmos-dark-800x480.png" alt="800x480" height="300"/>
+<img src="pmos-dark-540x960.png" alt="540x960" height="300"/>
+<img src="pmos-dark-960x540.png" alt="960x540" height="300"/>
+<img src="pmos-dark-768x1024.png" alt="768x1024" height="300"/>
+<img src="pmos-dark-1024x768.png" alt="1024x768" height="300"/>
+<img src="pmos-dark-1280x800.png" alt="1280x800" height="300"/>
+<img src="pmos-dark-1440x720.png" alt="1440x720" height="300"/>
+<img src="pmos-dark-1920x1080.png" alt="1920x1080" height="300"/>
+
+## pmos-light
+
+<img src="pmos-light-480x800.png" alt="480x800" height="300"/>
+<img src="pmos-light-800x480.png" alt="800x480" height="300"/>
+<img src="pmos-light-540x960.png" alt="540x960" height="300"/>
+<img src="pmos-light-960x540.png" alt="960x540" height="300"/>
+<img src="pmos-light-768x1024.png" alt="768x1024" height="300"/>
+<img src="pmos-light-1024x768.png" alt="1024x768" height="300"/>
+<img src="pmos-light-1280x800.png" alt="1280x800" height="300"/>
+<img src="pmos-light-1440x720.png" alt="1440x720" height="300"/>
+<img src="pmos-light-1920x1080.png" alt="1920x1080" height="300"/>
diff --git a/buffyboard/screenshots/adwaita-dark-1024x768.png b/buffyboard/screenshots/adwaita-dark-1024x768.png
new file mode 100644
index 0000000000000000000000000000000000000000..e8f0f44c769a31d39a28c3d83514c80b3ed463f2
Binary files /dev/null and b/buffyboard/screenshots/adwaita-dark-1024x768.png differ
diff --git a/buffyboard/screenshots/adwaita-dark-1280x800.png b/buffyboard/screenshots/adwaita-dark-1280x800.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d8567925e5d0f291cef463be5b1d57f07aa2949
Binary files /dev/null and b/buffyboard/screenshots/adwaita-dark-1280x800.png differ
diff --git a/buffyboard/screenshots/adwaita-dark-1440x720.png b/buffyboard/screenshots/adwaita-dark-1440x720.png
new file mode 100644
index 0000000000000000000000000000000000000000..d4328c40c6b4afb08b5ec7ad92bb47a03d1822b9
Binary files /dev/null and b/buffyboard/screenshots/adwaita-dark-1440x720.png differ
diff --git a/buffyboard/screenshots/adwaita-dark-1920x1080.png b/buffyboard/screenshots/adwaita-dark-1920x1080.png
new file mode 100644
index 0000000000000000000000000000000000000000..bba07ad20741616f226dc2aa5431b57ae24d7459
Binary files /dev/null and b/buffyboard/screenshots/adwaita-dark-1920x1080.png differ
diff --git a/buffyboard/screenshots/adwaita-dark-480x800.png b/buffyboard/screenshots/adwaita-dark-480x800.png
new file mode 100644
index 0000000000000000000000000000000000000000..ecab0d9b5a37d9130b70c33a80a811ddb5912775
Binary files /dev/null and b/buffyboard/screenshots/adwaita-dark-480x800.png differ
diff --git a/buffyboard/screenshots/adwaita-dark-540x960.png b/buffyboard/screenshots/adwaita-dark-540x960.png
new file mode 100644
index 0000000000000000000000000000000000000000..d41b221318454946d2d0a9cbdfe065cc85149591
Binary files /dev/null and b/buffyboard/screenshots/adwaita-dark-540x960.png differ
diff --git a/buffyboard/screenshots/adwaita-dark-768x1024.png b/buffyboard/screenshots/adwaita-dark-768x1024.png
new file mode 100644
index 0000000000000000000000000000000000000000..9eacb902ea8e14f8c107a86db88281c48c345b58
Binary files /dev/null and b/buffyboard/screenshots/adwaita-dark-768x1024.png differ
diff --git a/buffyboard/screenshots/adwaita-dark-800x480.png b/buffyboard/screenshots/adwaita-dark-800x480.png
new file mode 100644
index 0000000000000000000000000000000000000000..2e3798c1ea591413f2892f7468c9da69e434c531
Binary files /dev/null and b/buffyboard/screenshots/adwaita-dark-800x480.png differ
diff --git a/buffyboard/screenshots/adwaita-dark-960x540.png b/buffyboard/screenshots/adwaita-dark-960x540.png
new file mode 100644
index 0000000000000000000000000000000000000000..96ea3c1191bd4dd4c6357eb51b4befdf19189ede
Binary files /dev/null and b/buffyboard/screenshots/adwaita-dark-960x540.png differ
diff --git a/buffyboard/screenshots/breezy-dark-1024x768.png b/buffyboard/screenshots/breezy-dark-1024x768.png
index 69adae8d206588648fa25bde614602324ded90e0..1a2bded3ea52bfe3d578646dd3177a7c8a37eb8a 100644
Binary files a/buffyboard/screenshots/breezy-dark-1024x768.png and b/buffyboard/screenshots/breezy-dark-1024x768.png differ
diff --git a/buffyboard/screenshots/breezy-dark-1280x800.png b/buffyboard/screenshots/breezy-dark-1280x800.png
index 2e06948c86c095410a17599d5c8efd770ec3fba9..d54594a1cad76028a006c8d5e91a28dff0ed8c2d 100644
Binary files a/buffyboard/screenshots/breezy-dark-1280x800.png and b/buffyboard/screenshots/breezy-dark-1280x800.png differ
diff --git a/buffyboard/screenshots/breezy-dark-1440x720.png b/buffyboard/screenshots/breezy-dark-1440x720.png
index e083ac035f286141b84b42baa191a7a8bc3d76c1..0f22067f7582f74c332bbfb60216e2d6c781ad85 100644
Binary files a/buffyboard/screenshots/breezy-dark-1440x720.png and b/buffyboard/screenshots/breezy-dark-1440x720.png differ
diff --git a/buffyboard/screenshots/breezy-dark-1920x1080.png b/buffyboard/screenshots/breezy-dark-1920x1080.png
index e92d70b5938e62f9cc6682910f91f18635ca5d79..28d9516ffc81ea9b0e763433ac0b93d037e0da3e 100644
Binary files a/buffyboard/screenshots/breezy-dark-1920x1080.png and b/buffyboard/screenshots/breezy-dark-1920x1080.png differ
diff --git a/buffyboard/screenshots/breezy-dark-480x800.png b/buffyboard/screenshots/breezy-dark-480x800.png
index 344b901584547f2518a391ede9346cb489b0a905..81ba947766a0423a7eeaf4d2d808ca1eb9b50b7a 100644
Binary files a/buffyboard/screenshots/breezy-dark-480x800.png and b/buffyboard/screenshots/breezy-dark-480x800.png differ
diff --git a/buffyboard/screenshots/breezy-dark-540x960.png b/buffyboard/screenshots/breezy-dark-540x960.png
index 9c50d6a46ff80f7d9263a3162c9fc47185424ffc..cead0232a444738b61a0fb6f530d5c485b22d085 100644
Binary files a/buffyboard/screenshots/breezy-dark-540x960.png and b/buffyboard/screenshots/breezy-dark-540x960.png differ
diff --git a/buffyboard/screenshots/breezy-dark-768x1024.png b/buffyboard/screenshots/breezy-dark-768x1024.png
index 91c7c4460f896d4ba5a990bfe61c798884d74ef8..6cd5dd2405b8f97a16d6e383d14794cb31a6f495 100644
Binary files a/buffyboard/screenshots/breezy-dark-768x1024.png and b/buffyboard/screenshots/breezy-dark-768x1024.png differ
diff --git a/buffyboard/screenshots/breezy-dark-800x480.png b/buffyboard/screenshots/breezy-dark-800x480.png
index db309404ec76b122d98287e0d22e2bcb44c52196..d8fbb755032159c63762a8f30fea2ca05dee1530 100644
Binary files a/buffyboard/screenshots/breezy-dark-800x480.png and b/buffyboard/screenshots/breezy-dark-800x480.png differ
diff --git a/buffyboard/screenshots/breezy-dark-960x540.png b/buffyboard/screenshots/breezy-dark-960x540.png
index 86979291c9214628e0b04e46d750fb0d8eb86272..03553e2872cb967923e0721dd98dd10d7c303081 100644
Binary files a/buffyboard/screenshots/breezy-dark-960x540.png and b/buffyboard/screenshots/breezy-dark-960x540.png differ
diff --git a/buffyboard/screenshots/breezy-light-1024x768.png b/buffyboard/screenshots/breezy-light-1024x768.png
index 48370e3c295e2f611f037759d9eb94e1c5521772..d3302e92c366e477b121e68e78b57824c9b82350 100644
Binary files a/buffyboard/screenshots/breezy-light-1024x768.png and b/buffyboard/screenshots/breezy-light-1024x768.png differ
diff --git a/buffyboard/screenshots/breezy-light-1280x800.png b/buffyboard/screenshots/breezy-light-1280x800.png
index a4b2c184c460beb98c0cb9ee1cb52516771e12b1..c2d7eb7879f64320226c903250799799b71ffa7a 100644
Binary files a/buffyboard/screenshots/breezy-light-1280x800.png and b/buffyboard/screenshots/breezy-light-1280x800.png differ
diff --git a/buffyboard/screenshots/breezy-light-1440x720.png b/buffyboard/screenshots/breezy-light-1440x720.png
index 07a46f393c6df6c42e73cf4339874758dc726b41..1e2a2331ec51ca884691d1b2f80e15b400673cce 100644
Binary files a/buffyboard/screenshots/breezy-light-1440x720.png and b/buffyboard/screenshots/breezy-light-1440x720.png differ
diff --git a/buffyboard/screenshots/breezy-light-1920x1080.png b/buffyboard/screenshots/breezy-light-1920x1080.png
index 7c792b4fcebf4a5633593563d798d9ceb52003df..98b52fb8e4674b52fa91630ff51870c698276a0c 100644
Binary files a/buffyboard/screenshots/breezy-light-1920x1080.png and b/buffyboard/screenshots/breezy-light-1920x1080.png differ
diff --git a/buffyboard/screenshots/breezy-light-480x800.png b/buffyboard/screenshots/breezy-light-480x800.png
index 4913f20e5b70070c6b42ffea7574c85f588869f0..355250c56cc2790436b87ee2dfb93621d955362b 100644
Binary files a/buffyboard/screenshots/breezy-light-480x800.png and b/buffyboard/screenshots/breezy-light-480x800.png differ
diff --git a/buffyboard/screenshots/breezy-light-540x960.png b/buffyboard/screenshots/breezy-light-540x960.png
index a9a976265260b8d565ca2352e50e842f33d311b1..51bdd48cdd49fc6ac46cf1442b77f806ad7d5c51 100644
Binary files a/buffyboard/screenshots/breezy-light-540x960.png and b/buffyboard/screenshots/breezy-light-540x960.png differ
diff --git a/buffyboard/screenshots/breezy-light-768x1024.png b/buffyboard/screenshots/breezy-light-768x1024.png
index a9713a450293ef1ae855175bfc2a470e8bc5dd83..c1e346ae9a9a496796f122bee2f8917836555997 100644
Binary files a/buffyboard/screenshots/breezy-light-768x1024.png and b/buffyboard/screenshots/breezy-light-768x1024.png differ
diff --git a/buffyboard/screenshots/breezy-light-800x480.png b/buffyboard/screenshots/breezy-light-800x480.png
index fb885d1bb70c63252a19647feb816c9daf14e092..9e4e6ca20ec3db2fbca2ac69ccf548f5707aa286 100644
Binary files a/buffyboard/screenshots/breezy-light-800x480.png and b/buffyboard/screenshots/breezy-light-800x480.png differ
diff --git a/buffyboard/screenshots/breezy-light-960x540.png b/buffyboard/screenshots/breezy-light-960x540.png
index 7f3f4e784259e053e4f60f3489c6b2a7dc310619..90de1b984b9f2ae704e5986f89c634b4874e8c36 100644
Binary files a/buffyboard/screenshots/breezy-light-960x540.png and b/buffyboard/screenshots/breezy-light-960x540.png differ
diff --git a/buffyboard/screenshots/nord-dark-1024x768.png b/buffyboard/screenshots/nord-dark-1024x768.png
index f5d74ac0998da838eb2d249c8822e64ba7d5f9e1..aa8b2ef7558edd199f7bf0da68da3e6a1ec58e5f 100644
Binary files a/buffyboard/screenshots/nord-dark-1024x768.png and b/buffyboard/screenshots/nord-dark-1024x768.png differ
diff --git a/buffyboard/screenshots/nord-dark-1280x800.png b/buffyboard/screenshots/nord-dark-1280x800.png
index c9971df35b97daa554de0bf16905b5eb491908c3..97a0d33d338b1ccd126ce059ed3c23a4c6a2984b 100644
Binary files a/buffyboard/screenshots/nord-dark-1280x800.png and b/buffyboard/screenshots/nord-dark-1280x800.png differ
diff --git a/buffyboard/screenshots/nord-dark-1440x720.png b/buffyboard/screenshots/nord-dark-1440x720.png
index 774b84a4691b9aaa70be4c369e0a3b52456d33b5..f54900e042cd5ba1495b3ce1f184129acef758d4 100644
Binary files a/buffyboard/screenshots/nord-dark-1440x720.png and b/buffyboard/screenshots/nord-dark-1440x720.png differ
diff --git a/buffyboard/screenshots/nord-dark-1920x1080.png b/buffyboard/screenshots/nord-dark-1920x1080.png
index 8708509e73872abc7cecac6cafaa106c093504a4..6d0e756da6e2b103f8aba32180d34b790e95e68b 100644
Binary files a/buffyboard/screenshots/nord-dark-1920x1080.png and b/buffyboard/screenshots/nord-dark-1920x1080.png differ
diff --git a/buffyboard/screenshots/nord-dark-480x800.png b/buffyboard/screenshots/nord-dark-480x800.png
index b12d101ac21b4fde896009efc0e48a9dcf97d989..b63b7fa19a7c791353a4b0c08af456d42e87d446 100644
Binary files a/buffyboard/screenshots/nord-dark-480x800.png and b/buffyboard/screenshots/nord-dark-480x800.png differ
diff --git a/buffyboard/screenshots/nord-dark-540x960.png b/buffyboard/screenshots/nord-dark-540x960.png
index 48349452a73c0bed8fd0a7b4d255720e222bf8ab..201acf54cf917684e1bf8a24dee41fd786e8d68c 100644
Binary files a/buffyboard/screenshots/nord-dark-540x960.png and b/buffyboard/screenshots/nord-dark-540x960.png differ
diff --git a/buffyboard/screenshots/nord-dark-768x1024.png b/buffyboard/screenshots/nord-dark-768x1024.png
index 3ee3536c394741321af1a8aad6f8f65fafc19b9a..86b45140df1b7fffc402dc48c2a28e5613038944 100644
Binary files a/buffyboard/screenshots/nord-dark-768x1024.png and b/buffyboard/screenshots/nord-dark-768x1024.png differ
diff --git a/buffyboard/screenshots/nord-dark-800x480.png b/buffyboard/screenshots/nord-dark-800x480.png
index 688119c1739e3999a6ef8d47973caa20517b80d0..2a17426a1efd498a0ed324be95526b07cbdb8849 100644
Binary files a/buffyboard/screenshots/nord-dark-800x480.png and b/buffyboard/screenshots/nord-dark-800x480.png differ
diff --git a/buffyboard/screenshots/nord-dark-960x540.png b/buffyboard/screenshots/nord-dark-960x540.png
index ceccbac2d4c93641a5be553af92c9cbde0afc482..4744da1cdd2c880892b8a242ce3fce75b24d05cf 100644
Binary files a/buffyboard/screenshots/nord-dark-960x540.png and b/buffyboard/screenshots/nord-dark-960x540.png differ
diff --git a/buffyboard/screenshots/nord-light-1024x768.png b/buffyboard/screenshots/nord-light-1024x768.png
index 6e041cd971c69bac63a26766bfb22219b6f1bc1e..807aa5f4292a19b86fb28b2f188535cfd508a2f7 100644
Binary files a/buffyboard/screenshots/nord-light-1024x768.png and b/buffyboard/screenshots/nord-light-1024x768.png differ
diff --git a/buffyboard/screenshots/nord-light-1280x800.png b/buffyboard/screenshots/nord-light-1280x800.png
index a1c3918d2d69b8cc5f10a4fcca454b7e5acf088c..67f4f88d051a56cb91cafe77bd2efe7fa3271d9f 100644
Binary files a/buffyboard/screenshots/nord-light-1280x800.png and b/buffyboard/screenshots/nord-light-1280x800.png differ
diff --git a/buffyboard/screenshots/nord-light-1440x720.png b/buffyboard/screenshots/nord-light-1440x720.png
index 4f1652f1fc8bec9d197675923b9fe2a88ec4959c..96116993b9c2dd1c2e175f20cbb8bbcea79d437d 100644
Binary files a/buffyboard/screenshots/nord-light-1440x720.png and b/buffyboard/screenshots/nord-light-1440x720.png differ
diff --git a/buffyboard/screenshots/nord-light-1920x1080.png b/buffyboard/screenshots/nord-light-1920x1080.png
index 514f1b19c499a3d75dc3659f192c035b77f87486..2273f4f0f9f5db37689a05ebd1ddb07c06896a0e 100644
Binary files a/buffyboard/screenshots/nord-light-1920x1080.png and b/buffyboard/screenshots/nord-light-1920x1080.png differ
diff --git a/buffyboard/screenshots/nord-light-480x800.png b/buffyboard/screenshots/nord-light-480x800.png
index ed43e588e7f77c68cf57c382c75de8e302feee91..dff8f19d856706fbb8abe5db7e31f59c7b55dc64 100644
Binary files a/buffyboard/screenshots/nord-light-480x800.png and b/buffyboard/screenshots/nord-light-480x800.png differ
diff --git a/buffyboard/screenshots/nord-light-540x960.png b/buffyboard/screenshots/nord-light-540x960.png
index e28463d34d8e3c0af9fb017bbcf56d080b699c6e..99202f253538c1c296c984ee648ee8f1e6e5d693 100644
Binary files a/buffyboard/screenshots/nord-light-540x960.png and b/buffyboard/screenshots/nord-light-540x960.png differ
diff --git a/buffyboard/screenshots/nord-light-768x1024.png b/buffyboard/screenshots/nord-light-768x1024.png
index 5396101d2e3651a65bab1dc4f84723268b5ec97f..f3163a346dd47abefe368110f23255924f628c60 100644
Binary files a/buffyboard/screenshots/nord-light-768x1024.png and b/buffyboard/screenshots/nord-light-768x1024.png differ
diff --git a/buffyboard/screenshots/nord-light-800x480.png b/buffyboard/screenshots/nord-light-800x480.png
index 26b0a8d29c822afdb6db0551a6de8ae8ac42cd1c..1ed5249da371d0c14226caca5812dcae547147d2 100644
Binary files a/buffyboard/screenshots/nord-light-800x480.png and b/buffyboard/screenshots/nord-light-800x480.png differ
diff --git a/buffyboard/screenshots/nord-light-960x540.png b/buffyboard/screenshots/nord-light-960x540.png
index bcc725f0988c8fc664dbf7e25adc3f3ae201d725..08aa6101d14780ee232b7fe5ed37a7b6b44a30da 100644
Binary files a/buffyboard/screenshots/nord-light-960x540.png and b/buffyboard/screenshots/nord-light-960x540.png differ
diff --git a/buffyboard/screenshots/pmos-dark-1024x768.png b/buffyboard/screenshots/pmos-dark-1024x768.png
index 31ec6b105c8e39c7949d6123c70b0d49b2260794..c39946451c7874d30f3f0f1100a07a34b623d713 100644
Binary files a/buffyboard/screenshots/pmos-dark-1024x768.png and b/buffyboard/screenshots/pmos-dark-1024x768.png differ
diff --git a/buffyboard/screenshots/pmos-dark-1280x800.png b/buffyboard/screenshots/pmos-dark-1280x800.png
index ad23809673fb3a8ad6d5e4c7542f5b2160f2b997..c5cf819ddc7c1995713d266df7927d7c6b9888d3 100644
Binary files a/buffyboard/screenshots/pmos-dark-1280x800.png and b/buffyboard/screenshots/pmos-dark-1280x800.png differ
diff --git a/buffyboard/screenshots/pmos-dark-1440x720.png b/buffyboard/screenshots/pmos-dark-1440x720.png
index 5ddb5288d9c541ce6b29db690bc4763d54461792..4cbfef28a0121bca70abedd0819f29654a9e3606 100644
Binary files a/buffyboard/screenshots/pmos-dark-1440x720.png and b/buffyboard/screenshots/pmos-dark-1440x720.png differ
diff --git a/buffyboard/screenshots/pmos-dark-1920x1080.png b/buffyboard/screenshots/pmos-dark-1920x1080.png
index 402640c81614e22fbcf42310e15a19e05c55b8b6..7d095fa1ae5d06a7605450461d87134c59a124d1 100644
Binary files a/buffyboard/screenshots/pmos-dark-1920x1080.png and b/buffyboard/screenshots/pmos-dark-1920x1080.png differ
diff --git a/buffyboard/screenshots/pmos-dark-480x800.png b/buffyboard/screenshots/pmos-dark-480x800.png
index 5299c659420a24453048457785f44fa13c2b004a..38352233a5c3b9b2ffd27d432ba0a6a6c92f48a9 100644
Binary files a/buffyboard/screenshots/pmos-dark-480x800.png and b/buffyboard/screenshots/pmos-dark-480x800.png differ
diff --git a/buffyboard/screenshots/pmos-dark-540x960.png b/buffyboard/screenshots/pmos-dark-540x960.png
index bf52274e8fac5c62f501a647896558b76bc4df08..14682a2c56343967e67afb0f04190a7d735949b2 100644
Binary files a/buffyboard/screenshots/pmos-dark-540x960.png and b/buffyboard/screenshots/pmos-dark-540x960.png differ
diff --git a/buffyboard/screenshots/pmos-dark-768x1024.png b/buffyboard/screenshots/pmos-dark-768x1024.png
index 4930eee0e75c052b4e7e2b648d406a22805c6e82..ce630d1fdcc4cf01e96507907e160e40a61232d3 100644
Binary files a/buffyboard/screenshots/pmos-dark-768x1024.png and b/buffyboard/screenshots/pmos-dark-768x1024.png differ
diff --git a/buffyboard/screenshots/pmos-dark-800x480.png b/buffyboard/screenshots/pmos-dark-800x480.png
index c9f8ec272c4746d14b90a5ccba0fcb1b70bc58ea..c8e4aa24471527aa7c3eddedf08abb27c33c2a64 100644
Binary files a/buffyboard/screenshots/pmos-dark-800x480.png and b/buffyboard/screenshots/pmos-dark-800x480.png differ
diff --git a/buffyboard/screenshots/pmos-dark-960x540.png b/buffyboard/screenshots/pmos-dark-960x540.png
index fff86b22414f0a5bb080b81644d60fc23df55535..8c37eb4cc1c7ed9430dbabba6751741e28d876d3 100644
Binary files a/buffyboard/screenshots/pmos-dark-960x540.png and b/buffyboard/screenshots/pmos-dark-960x540.png differ
diff --git a/buffyboard/screenshots/pmos-light-1024x768.png b/buffyboard/screenshots/pmos-light-1024x768.png
index 85b0c221927abd5816018aa42ee54ba078f3512b..0b76d54008bad65ea40ba8193dddc56f027b2e55 100644
Binary files a/buffyboard/screenshots/pmos-light-1024x768.png and b/buffyboard/screenshots/pmos-light-1024x768.png differ
diff --git a/buffyboard/screenshots/pmos-light-1280x800.png b/buffyboard/screenshots/pmos-light-1280x800.png
index 24f4553d42f4d37c6e2fb12dec215223c3fed9fd..5a616b67451b6cba56bea8e360b59fcf0a69ae33 100644
Binary files a/buffyboard/screenshots/pmos-light-1280x800.png and b/buffyboard/screenshots/pmos-light-1280x800.png differ
diff --git a/buffyboard/screenshots/pmos-light-1440x720.png b/buffyboard/screenshots/pmos-light-1440x720.png
index 1b45bf294adf361b87f49e3f7dfee3772883ca74..17bf57512ba43134a5233d2c29efb1ff4b0fbdf9 100644
Binary files a/buffyboard/screenshots/pmos-light-1440x720.png and b/buffyboard/screenshots/pmos-light-1440x720.png differ
diff --git a/buffyboard/screenshots/pmos-light-1920x1080.png b/buffyboard/screenshots/pmos-light-1920x1080.png
index cd33f3ebd72a71f4e0f0167974f3256fdcca207c..2ceff91466a04d26b3f4ac4fe9b19fb31025bb4d 100644
Binary files a/buffyboard/screenshots/pmos-light-1920x1080.png and b/buffyboard/screenshots/pmos-light-1920x1080.png differ
diff --git a/buffyboard/screenshots/pmos-light-480x800.png b/buffyboard/screenshots/pmos-light-480x800.png
index 337c1ab13ca798496c8108b115f18d292f3329e7..1b62528aaf2ae700c555d24c826002f824730d85 100644
Binary files a/buffyboard/screenshots/pmos-light-480x800.png and b/buffyboard/screenshots/pmos-light-480x800.png differ
diff --git a/buffyboard/screenshots/pmos-light-540x960.png b/buffyboard/screenshots/pmos-light-540x960.png
index 20da132c452c7bc35a776cf07beb7af2e890f512..2497c48466bb5a97cae2e81a69ada5328f88ad28 100644
Binary files a/buffyboard/screenshots/pmos-light-540x960.png and b/buffyboard/screenshots/pmos-light-540x960.png differ
diff --git a/buffyboard/screenshots/pmos-light-768x1024.png b/buffyboard/screenshots/pmos-light-768x1024.png
index bce768e13d620d9d5001bbfdf771221f445e9d73..d453912be02806f2044420488a4eac1a87422203 100644
Binary files a/buffyboard/screenshots/pmos-light-768x1024.png and b/buffyboard/screenshots/pmos-light-768x1024.png differ
diff --git a/buffyboard/screenshots/pmos-light-800x480.png b/buffyboard/screenshots/pmos-light-800x480.png
index 6c132fd509ac99229ad130e43adb9d10c81319e1..36fed68af617f65612efa5bb6af2417aecbe733b 100644
Binary files a/buffyboard/screenshots/pmos-light-800x480.png and b/buffyboard/screenshots/pmos-light-800x480.png differ
diff --git a/buffyboard/screenshots/pmos-light-960x540.png b/buffyboard/screenshots/pmos-light-960x540.png
index 32e8958fd01f0fc538cc9b0cd3f6b3ecd70c6b50..91abf6e37ac9b74cbe435eba675be39cad1d7683 100644
Binary files a/buffyboard/screenshots/pmos-light-960x540.png and b/buffyboard/screenshots/pmos-light-960x540.png differ
diff --git a/buffyboard/test/build.sh b/buffyboard/test/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..114a08552f164d8842b96a015019ed5fe524f4ca
--- /dev/null
+++ b/buffyboard/test/build.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+rm -rf _build
+meson _build
+meson compile -C _build
diff --git a/buffyboard/test/helpers.sh b/buffyboard/test/helpers.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f6f21bf6cfc00e9097d1f5360a96bc7be25acbb4
--- /dev/null
+++ b/buffyboard/test/helpers.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+source "$(dirname "${BASH_SOURCE[0]}")/../../test/helpers.sh"
+
+function run_buffyboard_async() {
+    local log=$1
+    local conf=$2
+
+    ./_build/buffyboard -v -C "$conf" > "$log" 2>&1 &
+    pid=$!
+    sleep 3
+
+    kill -9 $pid
+    wait $pid > /dev/null 2>&1
+}
+
+function run_buffyboard_sync() {
+    local log=$1
+    shift
+    local conf=$2
+    shift
+    local args=$@
+
+    ./_build/buffyboard -v -C "$conf" $@ > "$log" 2>&1
+}
diff --git a/buffyboard/test/test-all.sh b/buffyboard/test/test-all.sh
new file mode 100755
index 0000000000000000000000000000000000000000..d474e6b28912ad7763aee48d6f64cde93b98e2e5
--- /dev/null
+++ b/buffyboard/test/test-all.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+root=$(dirname "${BASH_SOURCE[0]}")
+
+source "$root/helpers.sh"
+
+run_script "$root/build.sh"
+run_script "$root/test-version-matches-meson-and-changelog.sh"
diff --git a/buffyboard/test/test-version-matches-meson-and-changelog.sh b/buffyboard/test/test-version-matches-meson-and-changelog.sh
new file mode 100755
index 0000000000000000000000000000000000000000..e645d691f8be205936d4068cf23b08fb56867a37
--- /dev/null
+++ b/buffyboard/test/test-version-matches-meson-and-changelog.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+log=tmp.log
+
+root=$(dirname "${BASH_SOURCE[0]}")
+
+source "$root/helpers.sh"
+
+function clean_up() {
+    rm -f "$log"
+}
+
+trap clean_up EXIT
+
+info "Querying version from build.meson"
+meson_version=$(read_version_from_meson)
+
+info "Querying version from CHANGELOG.md"
+changelog_version=$(read_version_from_changelog)
+
+info "Verifying versions"
+if [[ "$meson_version" != "$changelog_version" ]]; then
+    error "Version $meson_version from meson.build doesn't match version $changelog_version from CHANGELOG.md"
+    exit 1
+fi
+
+info "Running buffyboard"
+run_buffyboard_sync "$log" "$conf" -V
+
+info "Verifying output"
+if ! grep "buffyboard $meson_version" "$log"; then
+    error "Expected version $meson_version"
+    cat "$log"
+    exit 1
+fi
+
+ok
diff --git a/iskey/README.md b/iskey/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ff7bf6ffadf9479b71e5e3b7c2cca0c5ef0faddb
--- /dev/null
+++ b/iskey/README.md
@@ -0,0 +1,7 @@
+# iskey
+
+A tiny utility for determining if a key is pressed.
+
+iskey is intended to be used in the context of a constrained environment like
+the initramfs, it allows for easily scripting things like "is the user holding
+volume down" which are generally non-trivial to check for in a shell script.
diff --git a/iskey/iskey.c b/iskey/iskey.c
new file mode 100644
index 0000000000000000000000000000000000000000..e92f52d3ef9416a75e2a24e420e1a8b7bcd0f7ee
--- /dev/null
+++ b/iskey/iskey.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <dirent.h> 
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libevdev/libevdev.h>
+
+#define MAX_KEYS 32
+
+static int codes[MAX_KEYS] = { 0 };
+static unsigned int types[MAX_KEYS] = { 0 };
+static int debug = 0;
+static int print_key = 0;
+
+#define log(fmt, ...) \
+	do { \
+		if (debug) \
+			fprintf(stderr, fmt, ##__VA_ARGS__); \
+	} while (0)
+
+#define INPUT_DIR "/dev/input/"
+
+int usage(const char *name)
+{
+	fprintf(stderr, "Usage: %s [-d] [-s] key1...\n", name);
+	fprintf(stderr, "  -d: debug mode\n");
+	fprintf(stderr, "  -s: print the name of the key\n");
+	fprintf(stderr, "\n");
+	fprintf(stderr, "  Check if any input device has the specified keys pressed\n"
+			"  and exit with code 0 if so, otherwise exit with code 1\n");
+	return 1;
+}
+
+/* Check if any of the input devices have a non-zero value for any of the keys.
+ * if so then return 0, otherwise return -1.
+ */
+int check_for_keys(struct libevdev *dev)
+{
+	int i;
+
+	for (i = 0; i < MAX_KEYS; i++) {
+		if (codes[i] == 0)
+			break;
+		if (!libevdev_has_event_code(dev, types[i], codes[i]))
+			continue;
+		if (libevdev_get_event_value(dev, types[i], codes[i])) {
+			if (print_key)
+				printf("%s\n", libevdev_event_code_get_name(types[i], codes[i]));
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+int main(int argc, char *argv[])
+{
+	struct libevdev *dev;
+	struct dirent *dir;
+	DIR *d;
+	int i = 0, opt, fd;
+	char path[64] = { 0 };
+
+	/* getopt */
+	while ((opt = getopt(argc, argv, "d")) != -1) {
+		switch (opt) {
+		case 'd':
+			debug = 1;
+			break;
+		case 's':
+			print_key = 1;
+			break;
+		default:
+			return usage(argv[0]);
+		}
+	}
+
+	for (; optind < argc && i < MAX_KEYS; optind++) {
+		codes[i] = libevdev_event_code_from_code_name(argv[optind]);
+		if (codes[i] == -1) {
+			fprintf(stderr, "Unknown key %s\n", argv[optind]);
+			return 1;
+		}
+		types[i++] = libevdev_event_type_from_code_name(argv[optind]);
+		log("Checking for %s %s (%d)\n", libevdev_event_type_get_name(types[i-1]), argv[optind], codes[i-1]);
+	}
+
+	d = opendir(INPUT_DIR);
+	if (!d) {
+		perror("couldn't open /dev/input/");
+		return 1;
+	}
+
+	/* Walk through the entries in /dev/input */
+	while ((dir = readdir(d)) != NULL) {
+		memset(path, 0, sizeof(path));
+		i = snprintf(path, sizeof(path), "%s%s", INPUT_DIR, dir->d_name);
+		if (i < 0 || i >= sizeof(path)) {
+			printf("Path '%s' too long\n", dir->d_name);
+			return 1;
+		}
+
+		if (dir->d_type != DT_CHR || strncmp("event", dir->d_name, 5) != 0)
+			continue;
+
+		fd = open(path, O_RDONLY|O_NONBLOCK);
+		if (fd < 0) {
+			log("couldn't open device %s\n", dir->d_name);
+			continue;
+		}
+		fd = libevdev_new_from_fd(fd, &dev);
+		if (fd < 0) {
+			log("couldn't init libevdev for %s: %s\n", dir->d_name, strerror(-fd));
+			continue;
+		}
+		log("Checking device %s\n", libevdev_get_name(dev));
+		if (!check_for_keys(dev)) {
+			close(fd);
+			return 0;
+		}
+		close(fd);
+	}
+	closedir(d);
+
+	return 1;
+}
diff --git a/iskey/meson.build b/iskey/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..aa317d428e4d879eecfb9872f557653bf67ad121
--- /dev/null
+++ b/iskey/meson.build
@@ -0,0 +1,7 @@
+project('iskey', 'c')
+
+libevdev_dep = dependency('libevdev')
+
+iskey_exe = executable('iskey',
+			'iskey.c',
+			dependencies: libevdev_dep)
diff --git a/lvgl b/lvgl
index 03498a2f83d36dfe7bd009a4451083a4f64ef0ba..ceadda8a468b7d5fa6ba973bd82cf610166278d8 160000
--- a/lvgl
+++ b/lvgl
@@ -1 +1 @@
-Subproject commit 03498a2f83d36dfe7bd009a4451083a4f64ef0ba
+Subproject commit ceadda8a468b7d5fa6ba973bd82cf610166278d8
diff --git a/shared/themes.c b/shared/themes.c
index ab34a4d92af8b7038b886abf41c815c9b473344e..be4f9a35539aead57b34e13e40033b8a962962cc 100644
--- a/shared/themes.c
+++ b/shared/themes.c
@@ -632,8 +632,161 @@ static const bbx_theme pmos_dark = {
     }
 };
 
-/* Nord themes (based on https://www.nordtheme.com/docs/colors-and-palettes) */
+/* Adwaita dark (based on https://gitlab.gnome.org/GNOME/libadwaita) */
+static const bbx_theme adwaita_dark = {
+    .name = "adwaita-dark",
+    .window = {
+        .bg_color = 0x151515
+    },
+    .header = {
+        .bg_color = 0x242424,
+        .border_width = 0,
+        .border_color = 0x242424,
+        .pad = 10,
+        .gap = 10
+    },
+    .keyboard = {
+        .bg_color = 0x242424,
+        .border_width = 2,
+        .border_color = 0x242424,
+        .pad = 20,
+        .gap = 10,
+        .keys = {
+            .border_width = 1,
+            .corner_radius = 5,
+            .key_char = {
+                .normal = {
+                    .fg_color = 0xDEDDDA,
+                    .bg_color = 0x464448,
+                    .border_color = 0x464448
+                },
+                .pressed = {
+                    .fg_color = 0xDEDDDA,
+                    .bg_color = 0x747077,
+                    .border_color = 0x747077
+                }
+            },
+            .key_non_char = {
+                .normal = {
+                    .fg_color = 0xDEDDDA,
+                    .bg_color = 0x3A3A3A,
+                    .border_color = 0x3A3A3A
+                },
+                .pressed = {
+                    .fg_color = 0xDEDDDA,
+                    .bg_color = 0x666666,
+                    .border_color = 0x666666
+                }
+            },
+            .key_mod_act = {
+                .normal = {
+                    .fg_color = 0x1E1E1E,
+                    .bg_color = 0x747077,
+                    .border_color = 0x747077
+                },
+                .pressed = {
+                    .fg_color = 0xDEDDDA,
+                    .bg_color = 0x464448,
+                    .border_color = 0x464448
+                }
+            },
+            .key_mod_inact = {
+                .normal = {
+                    .fg_color = 0xDEDDDA,
+                    .bg_color = 0x3A3A3A,
+                    .border_color = 0x3A3A3A
+                },
+                .pressed = {
+                    .fg_color = 0xDEDDDA,
+                    .bg_color = 0x3A3A3A,
+                    .border_color = 0x3A3A3A
+                }
+            }
+        }
+    },
+    .button = {
+        .border_width = 1,
+        .corner_radius = 5,
+        .pad = 8,
+        .normal = {
+            .fg_color = 0xDEDDDA,
+            .bg_color = 0x3A3A3A,
+            .border_color = 0x3A3A3A
+        },
+        .pressed = {
+            .fg_color = 0xDEDDDA,
+            .bg_color = 0x666666,
+            .border_color = 0x666666
+        }
+    },
+    .textarea = {
+        .fg_color = 0xDEDDDA,
+        .bg_color = 0x282828,
+        .border_width = 1,
+        .border_color = 0x1C71D8,
+        .corner_radius = 10,
+        .pad = 8,
+        .placeholder_color = 0x1C71D8,
+        .cursor = {
+            .width = 2,
+            .color = 0xDEDDDA,
+            .period = 700
+        }
+    },
+    .dropdown = {
+        .button = {
+            .border_width = 1,
+            .corner_radius = 5,
+            .pad = 8,
+            .normal = {
+                .fg_color = 0xDEDDDA,
+                .bg_color = 0x3A3A3A,
+                .border_color = 0x3A3A3A
+            },
+            .pressed = {
+                .fg_color = 0xDEDDDA,
+                .bg_color = 0x666666,
+                .border_color = 0x666666
+            }
+        },
+        .list = {
+            .fg_color = 0xDEDDDA,
+            .bg_color = 0x383838,
+            .selection_fg_color = 0xDEDDDA,
+            .selection_bg_color = 0x5E5E5E,
+            .border_width = 1,
+            .border_color = 0x383838,
+            .corner_radius = 5,
+            .pad = 8
+        }
+    },
+    .label = {
+        .fg_color = 0xDEDDDA,
+    },
+    .msgbox = {
+        .fg_color = 0xDEDDDA,
+        .bg_color = 0x383838,
+        .border_width = 1,
+        .border_color = 0x383838,
+        .corner_radius = 7,
+        .pad = 20,
+        .gap = 20,
+        .dimming = {
+            .color = 0x151515,
+            .opacity = 225
+        }
+    },
+    .bar = {
+        .border_width = 1,
+        .border_color = 0x1C71D8,
+        .corner_radius = 5,
+        .indicator = {
+            .bg_color = 0x1C71D8
+        }
+    }
+};
 
+/* Nord themes (based on https://www.nordtheme.com/docs/colors-and-palettes) */
 #define NORD0   0x2e3440
 #define NORD1   0x3b4252
 #define NORD2   0x434c5e
@@ -962,14 +1115,15 @@ static const bbx_theme nord_dark = {
  * Public interface
  */
 
-const int bbx_themes_num_themes = 6;
+const int bbx_themes_num_themes = 7;
 const bbx_theme *bbx_themes_themes[] = {
     &breezy_light,
     &breezy_dark,
     &pmos_light,
     &pmos_dark,
+    &adwaita_dark,
     &nord_light,
-    &nord_dark,
+    &nord_dark
 };
 
 bbx_themes_theme_id_t bbx_themes_find_theme_with_name(const char *name) {
diff --git a/shared/themes.h b/shared/themes.h
index 5d592cfd5ed42807a069890d1e9be06ef27894da..f72f7679387e4a3b3efc4a5b34daa655bf04c7df 100644
--- a/shared/themes.h
+++ b/shared/themes.h
@@ -15,7 +15,10 @@ typedef enum {
     BBX_THEMES_THEME_BREEZY_LIGHT = 0,
     BBX_THEMES_THEME_BREEZY_DARK = 1,
     BBX_THEMES_THEME_PMOS_LIGHT = 2,
-    BBX_THEMES_THEME_PMOS_DARK = 3
+    BBX_THEMES_THEME_PMOS_DARK = 3,
+    BBX_THEMES_THEME_ADWAITA_DARK = 4,
+    BBX_THEMES_THEME_NORD_LIGHT = 5,
+    BBX_THEMES_THEME_NORD_DARK = 6,
 } bbx_themes_theme_id_t;
 
 /* Themes */
diff --git a/test/helpers.sh b/test/helpers.sh
new file mode 100644
index 0000000000000000000000000000000000000000..135757c5a6017a2ba12543db4b3ad0277d7a6bf0
--- /dev/null
+++ b/test/helpers.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+function info() {
+    echo -e "[Info] $1"
+}
+
+function error() {
+    echo -e "\e[31m[Error]\e[0m $1"
+}
+
+function ok() {
+    echo -e "\e[32m[Ok]\e[0m $1"
+}
+
+function run_script() {
+    info "Executing $1"
+    "$1"
+    echo
+}
+
+function read_version_from_meson() {
+    grep "^[[:space:]]*version:" "$root/../meson.build" | head -n1 | grep -o "[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+"
+}
+
+function read_version_from_changelog() {
+    grep "^## [[:digit:]]" "$root/../../CHANGELOG.md" | head -n1 | grep -o "[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+"
+}
diff --git a/unl0kr/README.md b/unl0kr/README.md
index 2e4612b0bff4832bb6a67258d825c95f49cff33c..2855562da2b72dd44c3a0321ef33045a42e16dd3 100644
--- a/unl0kr/README.md
+++ b/unl0kr/README.md
@@ -137,17 +137,15 @@ Unl0kr uses [squeekboard layouts] converted to C via [squeek2lvgl]. To regenerat
 $ ./regenerate-layouts.sh
 ```
 
-from the root of the repository.
-
 ## Generating screenshots
 
-To generate screenshots in a variety of common sizes, build unl0kr and then run
+To generate screenshots in a variety of common sizes, install [fbcat], build unl0kr and then run
 
 ```
 $ sudo ./regenerate-screenshots _build/unl0kr
 ```
 
-where `_build/unl0kr` is the location of the unl0kr binary. Note that you may have to adapt some of the settings inside the script depending on the device you're using to generate the screenshots.
+where `_build/unl0kr` is the location of the unl0kr binary.
 
 ## Screen recording
 
@@ -164,6 +162,7 @@ The [lv_port_linux_frame_buffer] project served as a starting point for the code
 [LVGL]: https://lvgl.io
 [adjust]: https://fontawesome.com/v5.15/icons/adjust?style=solid
 [arrow-alt-circle-up]: https://fontawesome.com/v5.15/icons/arrow-alt-circle-up?style=solid
+[fbcat]: https://github.com/jwilk/fbcat
 [inih]: https://github.com/benhoyt/inih
 [libinput]: https://gitlab.freedesktop.org/libinput/libinput
 [libudev]: https://github.com/systemd/systemd/tree/main/src/libudev
diff --git a/unl0kr/meson.build b/unl0kr/meson.build
index b6b3b80c4f4c5ad3f6771c80bfccbbbee0bfb3c3..925d7377ff3ecdc5ce94623c8f93d02e4d7c9eca 100644
--- a/unl0kr/meson.build
+++ b/unl0kr/meson.build
@@ -5,7 +5,7 @@
 project(
   'unl0kr',
   'c',
-  version: '3.0.0',
+  version: '3.1.0',
   default_options: 'warning_level=3',
   meson_version: '>=0.53.0'
 )
diff --git a/unl0kr/regenerate-screenshots.sh b/unl0kr/regenerate-screenshots.sh
index 28fc2daf2f03992b6ac992bc8ebf4378e870fa5a..a41c2606ac55ff0d4a6e9327da031a6d39126015 100755
--- a/unl0kr/regenerate-screenshots.sh
+++ b/unl0kr/regenerate-screenshots.sh
@@ -7,14 +7,8 @@ executable=$1
 outdir=screenshots
 config=unl0kr-screenshots.conf
 
-themes=(
-    breezy-light
-    breezy-dark
-    pmos-light
-    pmos-dark
-    nord-light
-    nord-dark
-)
+root=$(git rev-parse --show-toplevel)
+themes_c=$root/shared/themes.c
 
 resolutions=(
     # Nokia N900
@@ -34,6 +28,11 @@ resolutions=(
     1920x1080
 )
 
+if ! which fbcat > /dev/null 2>&1; then
+    echo "Error: Could not find fbcat" 1>&2
+    exit 1
+fi
+
 if [[ ! -f $executable || ! -x $executable ]]; then
     echo "Error: Could not find executable at $executable" 1>&2
     exit 1
@@ -62,18 +61,20 @@ touchscreen=false
 EOF
 }
 
-function nuke_config() {
+function clean_up() {
     rm -f $config
 }
 
-trap "nuke_config" EXIT
+trap clean_up EXIT
 
 rm -rf "$outdir"
 mkdir "$outdir"
 
 readme="# Unl0kr themes"$'\n'
 
-for theme in ${themes[@]}; do
+clear # Blank the screen
+
+while read -r theme; do
     write_config $theme
 
     readme="$readme"$'\n'"## $theme"$'\n\n'
@@ -84,15 +85,20 @@ for theme in ${themes[@]}; do
 
         sleep 3 # Wait for UI to render
 
-        ../../fbcat/fbcat /dev/fb0 > "$outdir/$theme-$res.ppm"
-        convert -size $fb_res "$outdir/$theme-$res.ppm" -crop $res+0+0 "$outdir/$theme-$res.png"
-        rm "$outdir/$theme-$res.ppm"
+        fbcat /dev/fb0 > "$outdir/$theme-$res.ppm"
         kill -15 $pid
 
+        convert \
+            -size $fb_res \
+            "$outdir/$theme-$res.ppm" \
+            -crop $res+0+0 \
+            "$outdir/$theme-$res.png"
+        rm "$outdir/$theme-$res.ppm"
+
         readme="$readme<img src=\"$theme-$res.png\" alt=\"$res\" height=\"300\"/>"$'\n'
 
         sleep 1 # Delay to prevent terminal mode set / reset interference
     done
-done
+done < <(grep "name =" "$themes_c" | grep -o '".*"' | tr -d '"' | sort)
 
 echo -n "$readme" > "$outdir/README.md"
diff --git a/unl0kr/screenshots/README.md b/unl0kr/screenshots/README.md
index a396ddc44810e63db5fd3be86bc5a431357e1c8b..3e1d30d47e505309ab86861dc6c72e7bbe538a7a 100644
--- a/unl0kr/screenshots/README.md
+++ b/unl0kr/screenshots/README.md
@@ -1,16 +1,16 @@
 # Unl0kr themes
 
-## breezy-light
+## adwaita-dark
 
-<img src="breezy-light-480x800.png" alt="480x800" height="300"/>
-<img src="breezy-light-800x480.png" alt="800x480" height="300"/>
-<img src="breezy-light-540x960.png" alt="540x960" height="300"/>
-<img src="breezy-light-960x540.png" alt="960x540" height="300"/>
-<img src="breezy-light-768x1024.png" alt="768x1024" height="300"/>
-<img src="breezy-light-1024x768.png" alt="1024x768" height="300"/>
-<img src="breezy-light-1280x800.png" alt="1280x800" height="300"/>
-<img src="breezy-light-1440x720.png" alt="1440x720" height="300"/>
-<img src="breezy-light-1920x1080.png" alt="1920x1080" height="300"/>
+<img src="adwaita-dark-480x800.png" alt="480x800" height="300"/>
+<img src="adwaita-dark-800x480.png" alt="800x480" height="300"/>
+<img src="adwaita-dark-540x960.png" alt="540x960" height="300"/>
+<img src="adwaita-dark-960x540.png" alt="960x540" height="300"/>
+<img src="adwaita-dark-768x1024.png" alt="768x1024" height="300"/>
+<img src="adwaita-dark-1024x768.png" alt="1024x768" height="300"/>
+<img src="adwaita-dark-1280x800.png" alt="1280x800" height="300"/>
+<img src="adwaita-dark-1440x720.png" alt="1440x720" height="300"/>
+<img src="adwaita-dark-1920x1080.png" alt="1920x1080" height="300"/>
 
 ## breezy-dark
 
@@ -24,17 +24,41 @@
 <img src="breezy-dark-1440x720.png" alt="1440x720" height="300"/>
 <img src="breezy-dark-1920x1080.png" alt="1920x1080" height="300"/>
 
-## pmos-light
+## breezy-light
 
-<img src="pmos-light-480x800.png" alt="480x800" height="300"/>
-<img src="pmos-light-800x480.png" alt="800x480" height="300"/>
-<img src="pmos-light-540x960.png" alt="540x960" height="300"/>
-<img src="pmos-light-960x540.png" alt="960x540" height="300"/>
-<img src="pmos-light-768x1024.png" alt="768x1024" height="300"/>
-<img src="pmos-light-1024x768.png" alt="1024x768" height="300"/>
-<img src="pmos-light-1280x800.png" alt="1280x800" height="300"/>
-<img src="pmos-light-1440x720.png" alt="1440x720" height="300"/>
-<img src="pmos-light-1920x1080.png" alt="1920x1080" height="300"/>
+<img src="breezy-light-480x800.png" alt="480x800" height="300"/>
+<img src="breezy-light-800x480.png" alt="800x480" height="300"/>
+<img src="breezy-light-540x960.png" alt="540x960" height="300"/>
+<img src="breezy-light-960x540.png" alt="960x540" height="300"/>
+<img src="breezy-light-768x1024.png" alt="768x1024" height="300"/>
+<img src="breezy-light-1024x768.png" alt="1024x768" height="300"/>
+<img src="breezy-light-1280x800.png" alt="1280x800" height="300"/>
+<img src="breezy-light-1440x720.png" alt="1440x720" height="300"/>
+<img src="breezy-light-1920x1080.png" alt="1920x1080" height="300"/>
+
+## nord-dark
+
+<img src="nord-dark-480x800.png" alt="480x800" height="300"/>
+<img src="nord-dark-800x480.png" alt="800x480" height="300"/>
+<img src="nord-dark-540x960.png" alt="540x960" height="300"/>
+<img src="nord-dark-960x540.png" alt="960x540" height="300"/>
+<img src="nord-dark-768x1024.png" alt="768x1024" height="300"/>
+<img src="nord-dark-1024x768.png" alt="1024x768" height="300"/>
+<img src="nord-dark-1280x800.png" alt="1280x800" height="300"/>
+<img src="nord-dark-1440x720.png" alt="1440x720" height="300"/>
+<img src="nord-dark-1920x1080.png" alt="1920x1080" height="300"/>
+
+## nord-light
+
+<img src="nord-light-480x800.png" alt="480x800" height="300"/>
+<img src="nord-light-800x480.png" alt="800x480" height="300"/>
+<img src="nord-light-540x960.png" alt="540x960" height="300"/>
+<img src="nord-light-960x540.png" alt="960x540" height="300"/>
+<img src="nord-light-768x1024.png" alt="768x1024" height="300"/>
+<img src="nord-light-1024x768.png" alt="1024x768" height="300"/>
+<img src="nord-light-1280x800.png" alt="1280x800" height="300"/>
+<img src="nord-light-1440x720.png" alt="1440x720" height="300"/>
+<img src="nord-light-1920x1080.png" alt="1920x1080" height="300"/>
 
 ## pmos-dark
 
@@ -47,3 +71,15 @@
 <img src="pmos-dark-1280x800.png" alt="1280x800" height="300"/>
 <img src="pmos-dark-1440x720.png" alt="1440x720" height="300"/>
 <img src="pmos-dark-1920x1080.png" alt="1920x1080" height="300"/>
+
+## pmos-light
+
+<img src="pmos-light-480x800.png" alt="480x800" height="300"/>
+<img src="pmos-light-800x480.png" alt="800x480" height="300"/>
+<img src="pmos-light-540x960.png" alt="540x960" height="300"/>
+<img src="pmos-light-960x540.png" alt="960x540" height="300"/>
+<img src="pmos-light-768x1024.png" alt="768x1024" height="300"/>
+<img src="pmos-light-1024x768.png" alt="1024x768" height="300"/>
+<img src="pmos-light-1280x800.png" alt="1280x800" height="300"/>
+<img src="pmos-light-1440x720.png" alt="1440x720" height="300"/>
+<img src="pmos-light-1920x1080.png" alt="1920x1080" height="300"/>
diff --git a/unl0kr/screenshots/adwaita-dark-1024x768.png b/unl0kr/screenshots/adwaita-dark-1024x768.png
new file mode 100644
index 0000000000000000000000000000000000000000..7ff00e49186b20acf169003b2eaef87b05fcdd43
Binary files /dev/null and b/unl0kr/screenshots/adwaita-dark-1024x768.png differ
diff --git a/unl0kr/screenshots/adwaita-dark-1280x800.png b/unl0kr/screenshots/adwaita-dark-1280x800.png
new file mode 100644
index 0000000000000000000000000000000000000000..1867cbfac3476b9422020888405be278af9e9d75
Binary files /dev/null and b/unl0kr/screenshots/adwaita-dark-1280x800.png differ
diff --git a/unl0kr/screenshots/adwaita-dark-1440x720.png b/unl0kr/screenshots/adwaita-dark-1440x720.png
new file mode 100644
index 0000000000000000000000000000000000000000..d4cb238495aec22bf57f9f66ca1a6daa45862acf
Binary files /dev/null and b/unl0kr/screenshots/adwaita-dark-1440x720.png differ
diff --git a/unl0kr/screenshots/adwaita-dark-1920x1080.png b/unl0kr/screenshots/adwaita-dark-1920x1080.png
new file mode 100644
index 0000000000000000000000000000000000000000..2102b50f5ebe2dc8e9b80b575dfff64318201a88
Binary files /dev/null and b/unl0kr/screenshots/adwaita-dark-1920x1080.png differ
diff --git a/unl0kr/screenshots/adwaita-dark-480x800.png b/unl0kr/screenshots/adwaita-dark-480x800.png
new file mode 100644
index 0000000000000000000000000000000000000000..0a75656c9b69f63d858a01d15ccc32229f878bc5
Binary files /dev/null and b/unl0kr/screenshots/adwaita-dark-480x800.png differ
diff --git a/unl0kr/screenshots/adwaita-dark-540x960.png b/unl0kr/screenshots/adwaita-dark-540x960.png
new file mode 100644
index 0000000000000000000000000000000000000000..42276f00d065769483823c749c5e28f91eb23488
Binary files /dev/null and b/unl0kr/screenshots/adwaita-dark-540x960.png differ
diff --git a/unl0kr/screenshots/adwaita-dark-768x1024.png b/unl0kr/screenshots/adwaita-dark-768x1024.png
new file mode 100644
index 0000000000000000000000000000000000000000..f1a87cb4abff73939843cc4c275b82545cabcd4b
Binary files /dev/null and b/unl0kr/screenshots/adwaita-dark-768x1024.png differ
diff --git a/unl0kr/screenshots/adwaita-dark-800x480.png b/unl0kr/screenshots/adwaita-dark-800x480.png
new file mode 100644
index 0000000000000000000000000000000000000000..95d11dc239b1cd67190774d5cde5b7a917604818
Binary files /dev/null and b/unl0kr/screenshots/adwaita-dark-800x480.png differ
diff --git a/unl0kr/screenshots/adwaita-dark-960x540.png b/unl0kr/screenshots/adwaita-dark-960x540.png
new file mode 100644
index 0000000000000000000000000000000000000000..9fc7c80844df6def1d82631aa984abbe42bd4764
Binary files /dev/null and b/unl0kr/screenshots/adwaita-dark-960x540.png differ
diff --git a/unl0kr/screenshots/breezy-dark-1024x768.png b/unl0kr/screenshots/breezy-dark-1024x768.png
index 1ee0303a523882f57bb8a76a7f8b44bcb79042fd..1748ad76b77e17ef4d4484192b5200eb4fa16fbe 100644
Binary files a/unl0kr/screenshots/breezy-dark-1024x768.png and b/unl0kr/screenshots/breezy-dark-1024x768.png differ
diff --git a/unl0kr/screenshots/breezy-dark-1280x800.png b/unl0kr/screenshots/breezy-dark-1280x800.png
index 8ed2d72846e3795e9243164706111941cf671030..d1245aee0addd3ccf4b1cd88e904103eaacf6083 100644
Binary files a/unl0kr/screenshots/breezy-dark-1280x800.png and b/unl0kr/screenshots/breezy-dark-1280x800.png differ
diff --git a/unl0kr/screenshots/breezy-dark-1440x720.png b/unl0kr/screenshots/breezy-dark-1440x720.png
index 644f440b975880ba732ed182899bcc7b505a82c1..a59e997dca30fa82a6f92874ab72d10f85385943 100644
Binary files a/unl0kr/screenshots/breezy-dark-1440x720.png and b/unl0kr/screenshots/breezy-dark-1440x720.png differ
diff --git a/unl0kr/screenshots/breezy-dark-1920x1080.png b/unl0kr/screenshots/breezy-dark-1920x1080.png
index 28ed8d49e0dad531f3be7fa9a5480acf1a2eef8b..7e285654791309ad1f2c3b1d568a8301a66294bb 100644
Binary files a/unl0kr/screenshots/breezy-dark-1920x1080.png and b/unl0kr/screenshots/breezy-dark-1920x1080.png differ
diff --git a/unl0kr/screenshots/breezy-dark-480x800.png b/unl0kr/screenshots/breezy-dark-480x800.png
index 5b438281bf0bd637507df0a77ab9bd583a052e76..d37be56dbf5e022f6e264e63ca8ed166ad57c1e8 100644
Binary files a/unl0kr/screenshots/breezy-dark-480x800.png and b/unl0kr/screenshots/breezy-dark-480x800.png differ
diff --git a/unl0kr/screenshots/breezy-dark-540x960.png b/unl0kr/screenshots/breezy-dark-540x960.png
index 2064d9349930b96b2c13d121b9853153e2c62f4d..6cb76aa6325b529caab2140d7c31cdfed4c87474 100644
Binary files a/unl0kr/screenshots/breezy-dark-540x960.png and b/unl0kr/screenshots/breezy-dark-540x960.png differ
diff --git a/unl0kr/screenshots/breezy-dark-768x1024.png b/unl0kr/screenshots/breezy-dark-768x1024.png
index 0fce9ccde421ab88aa7db2e8bebe44db3ac99bbf..370a74dc3643c7ef71713806ba0374ea1c0382d0 100644
Binary files a/unl0kr/screenshots/breezy-dark-768x1024.png and b/unl0kr/screenshots/breezy-dark-768x1024.png differ
diff --git a/unl0kr/screenshots/breezy-dark-800x480.png b/unl0kr/screenshots/breezy-dark-800x480.png
index 656f8e4787eb083e87b288ce1ef6a916af1f480d..d40d526453c80bb2c772f619bad1e11671c6ceb8 100644
Binary files a/unl0kr/screenshots/breezy-dark-800x480.png and b/unl0kr/screenshots/breezy-dark-800x480.png differ
diff --git a/unl0kr/screenshots/breezy-dark-960x540.png b/unl0kr/screenshots/breezy-dark-960x540.png
index 29d1cce5353c47fc0310c136d73a7e21e070ed2c..eb1486a6abcc62ae7819f2d46c8f027a3858a0f0 100644
Binary files a/unl0kr/screenshots/breezy-dark-960x540.png and b/unl0kr/screenshots/breezy-dark-960x540.png differ
diff --git a/unl0kr/screenshots/breezy-light-1024x768.png b/unl0kr/screenshots/breezy-light-1024x768.png
index 24ecab5857915f105f0ecc4f232eef6835d9e9a2..346eaca576e812e77b63216c06f6f06af27194e5 100644
Binary files a/unl0kr/screenshots/breezy-light-1024x768.png and b/unl0kr/screenshots/breezy-light-1024x768.png differ
diff --git a/unl0kr/screenshots/breezy-light-1280x800.png b/unl0kr/screenshots/breezy-light-1280x800.png
index 2afaaeb9730aaa09f981f160984d7dc5ca9d1e15..c12dbe00a43352595ebff1e9d396913d5fb35faf 100644
Binary files a/unl0kr/screenshots/breezy-light-1280x800.png and b/unl0kr/screenshots/breezy-light-1280x800.png differ
diff --git a/unl0kr/screenshots/breezy-light-1440x720.png b/unl0kr/screenshots/breezy-light-1440x720.png
index cf2e9dd6795323d9c12fb1f7d577d3347d89792a..29c9027face441c056a5bc94c42e8341a965bd8d 100644
Binary files a/unl0kr/screenshots/breezy-light-1440x720.png and b/unl0kr/screenshots/breezy-light-1440x720.png differ
diff --git a/unl0kr/screenshots/breezy-light-1920x1080.png b/unl0kr/screenshots/breezy-light-1920x1080.png
index 964d4a99be18c6d5f6f91d8f3c80f9097248feb6..9850657dc3f9c27a5297bbaa2d902509db7a0816 100644
Binary files a/unl0kr/screenshots/breezy-light-1920x1080.png and b/unl0kr/screenshots/breezy-light-1920x1080.png differ
diff --git a/unl0kr/screenshots/breezy-light-480x800.png b/unl0kr/screenshots/breezy-light-480x800.png
index ad107f6da53153398609033eae7d04cbc73bfebd..ce969d1672286892cfd1ec32442890f9673ae8d7 100644
Binary files a/unl0kr/screenshots/breezy-light-480x800.png and b/unl0kr/screenshots/breezy-light-480x800.png differ
diff --git a/unl0kr/screenshots/breezy-light-540x960.png b/unl0kr/screenshots/breezy-light-540x960.png
index 39b2788dee0aa0fd38bd040bf0f3437cff58acac..91fc253f5815989b0064b327721bb42a5c3c4fac 100644
Binary files a/unl0kr/screenshots/breezy-light-540x960.png and b/unl0kr/screenshots/breezy-light-540x960.png differ
diff --git a/unl0kr/screenshots/breezy-light-768x1024.png b/unl0kr/screenshots/breezy-light-768x1024.png
index 0bd78c657ed8e07d0d47fb0bd9b00f9e8b2c2476..739209716191dbd46614372a418268ae71dc69a4 100644
Binary files a/unl0kr/screenshots/breezy-light-768x1024.png and b/unl0kr/screenshots/breezy-light-768x1024.png differ
diff --git a/unl0kr/screenshots/breezy-light-800x480.png b/unl0kr/screenshots/breezy-light-800x480.png
index 5eecd662c36865d6c67aebfc106940f6461d7226..accfeedd407c450e167856a4c47370803aad4e4d 100644
Binary files a/unl0kr/screenshots/breezy-light-800x480.png and b/unl0kr/screenshots/breezy-light-800x480.png differ
diff --git a/unl0kr/screenshots/breezy-light-960x540.png b/unl0kr/screenshots/breezy-light-960x540.png
index 24e9e8913f213e0307cc197ac990856c692fc82c..10413f3fc2140aad5d48fe8b8e761ac4fcc20dac 100644
Binary files a/unl0kr/screenshots/breezy-light-960x540.png and b/unl0kr/screenshots/breezy-light-960x540.png differ
diff --git a/unl0kr/screenshots/nord-dark-1024x768.png b/unl0kr/screenshots/nord-dark-1024x768.png
new file mode 100644
index 0000000000000000000000000000000000000000..b5cf68bf5947a60aa7888f56a8be6592c2437217
Binary files /dev/null and b/unl0kr/screenshots/nord-dark-1024x768.png differ
diff --git a/unl0kr/screenshots/nord-dark-1280x800.png b/unl0kr/screenshots/nord-dark-1280x800.png
new file mode 100644
index 0000000000000000000000000000000000000000..81059e90130428fa7c9fee63402741734614f151
Binary files /dev/null and b/unl0kr/screenshots/nord-dark-1280x800.png differ
diff --git a/unl0kr/screenshots/nord-dark-1440x720.png b/unl0kr/screenshots/nord-dark-1440x720.png
new file mode 100644
index 0000000000000000000000000000000000000000..aac3917d0892219fc8b588cdd34a82214b64a129
Binary files /dev/null and b/unl0kr/screenshots/nord-dark-1440x720.png differ
diff --git a/unl0kr/screenshots/nord-dark-1920x1080.png b/unl0kr/screenshots/nord-dark-1920x1080.png
new file mode 100644
index 0000000000000000000000000000000000000000..5736f804b96cf77590029bd3a6245dae8e65ff14
Binary files /dev/null and b/unl0kr/screenshots/nord-dark-1920x1080.png differ
diff --git a/unl0kr/screenshots/nord-dark-480x800.png b/unl0kr/screenshots/nord-dark-480x800.png
new file mode 100644
index 0000000000000000000000000000000000000000..8e90d4e7d4ad0807562189d907d57031550da2a0
Binary files /dev/null and b/unl0kr/screenshots/nord-dark-480x800.png differ
diff --git a/unl0kr/screenshots/nord-dark-540x960.png b/unl0kr/screenshots/nord-dark-540x960.png
new file mode 100644
index 0000000000000000000000000000000000000000..ae729414ca6d1e50ab86abce70654394251ff097
Binary files /dev/null and b/unl0kr/screenshots/nord-dark-540x960.png differ
diff --git a/unl0kr/screenshots/nord-dark-768x1024.png b/unl0kr/screenshots/nord-dark-768x1024.png
new file mode 100644
index 0000000000000000000000000000000000000000..33c4ad5b0bb51ebd02e860bc7698f3101a14ce35
Binary files /dev/null and b/unl0kr/screenshots/nord-dark-768x1024.png differ
diff --git a/unl0kr/screenshots/nord-dark-800x480.png b/unl0kr/screenshots/nord-dark-800x480.png
new file mode 100644
index 0000000000000000000000000000000000000000..07fa1ba0e12b8ec5ba00b443441f9d6195f43d24
Binary files /dev/null and b/unl0kr/screenshots/nord-dark-800x480.png differ
diff --git a/unl0kr/screenshots/nord-dark-960x540.png b/unl0kr/screenshots/nord-dark-960x540.png
new file mode 100644
index 0000000000000000000000000000000000000000..e9b06fa2c0aff49d02cb0fbec809a1073ad8a1a7
Binary files /dev/null and b/unl0kr/screenshots/nord-dark-960x540.png differ
diff --git a/unl0kr/screenshots/nord-light-1024x768.png b/unl0kr/screenshots/nord-light-1024x768.png
new file mode 100644
index 0000000000000000000000000000000000000000..c4d36a350d9afb657f7aa4b30da733f06c2d9870
Binary files /dev/null and b/unl0kr/screenshots/nord-light-1024x768.png differ
diff --git a/unl0kr/screenshots/nord-light-1280x800.png b/unl0kr/screenshots/nord-light-1280x800.png
new file mode 100644
index 0000000000000000000000000000000000000000..e26475425f4958ddbf54eb24e3c8f4bf532ce0f7
Binary files /dev/null and b/unl0kr/screenshots/nord-light-1280x800.png differ
diff --git a/unl0kr/screenshots/nord-light-1440x720.png b/unl0kr/screenshots/nord-light-1440x720.png
new file mode 100644
index 0000000000000000000000000000000000000000..07d3442e5c02d8983adc423ad016eb5ec34c9a0b
Binary files /dev/null and b/unl0kr/screenshots/nord-light-1440x720.png differ
diff --git a/unl0kr/screenshots/nord-light-1920x1080.png b/unl0kr/screenshots/nord-light-1920x1080.png
new file mode 100644
index 0000000000000000000000000000000000000000..d4ab4b5a6143465377cae4641509353791dacc67
Binary files /dev/null and b/unl0kr/screenshots/nord-light-1920x1080.png differ
diff --git a/unl0kr/screenshots/nord-light-480x800.png b/unl0kr/screenshots/nord-light-480x800.png
new file mode 100644
index 0000000000000000000000000000000000000000..efb986d2f93e7f24a4beaaf3309de1e34a623868
Binary files /dev/null and b/unl0kr/screenshots/nord-light-480x800.png differ
diff --git a/unl0kr/screenshots/nord-light-540x960.png b/unl0kr/screenshots/nord-light-540x960.png
new file mode 100644
index 0000000000000000000000000000000000000000..29957cc555e109ddb0287113ccd6c1f90effdfc1
Binary files /dev/null and b/unl0kr/screenshots/nord-light-540x960.png differ
diff --git a/unl0kr/screenshots/nord-light-768x1024.png b/unl0kr/screenshots/nord-light-768x1024.png
new file mode 100644
index 0000000000000000000000000000000000000000..4ffc781ef361162c9f0193f17a1a5218c3f50296
Binary files /dev/null and b/unl0kr/screenshots/nord-light-768x1024.png differ
diff --git a/unl0kr/screenshots/nord-light-800x480.png b/unl0kr/screenshots/nord-light-800x480.png
new file mode 100644
index 0000000000000000000000000000000000000000..213c916557e26fc998d660694cd05908286035b5
Binary files /dev/null and b/unl0kr/screenshots/nord-light-800x480.png differ
diff --git a/unl0kr/screenshots/nord-light-960x540.png b/unl0kr/screenshots/nord-light-960x540.png
new file mode 100644
index 0000000000000000000000000000000000000000..21468232fa66d2e7f2edc68f472851ba7e498fed
Binary files /dev/null and b/unl0kr/screenshots/nord-light-960x540.png differ
diff --git a/unl0kr/screenshots/pmos-dark-1024x768.png b/unl0kr/screenshots/pmos-dark-1024x768.png
index 2cd6cbb168176fffd4813e6320ef69c8c555f6f4..4a1ed2a18440cddf5c5d8bec309dbac20aa66180 100644
Binary files a/unl0kr/screenshots/pmos-dark-1024x768.png and b/unl0kr/screenshots/pmos-dark-1024x768.png differ
diff --git a/unl0kr/screenshots/pmos-dark-1280x800.png b/unl0kr/screenshots/pmos-dark-1280x800.png
index d5b6dcf9102d6fb962df153c0bfc8f5e5ccdf580..230134fcaa4b0b0f487ba2b14ad90cf1dc74ee69 100644
Binary files a/unl0kr/screenshots/pmos-dark-1280x800.png and b/unl0kr/screenshots/pmos-dark-1280x800.png differ
diff --git a/unl0kr/screenshots/pmos-dark-1440x720.png b/unl0kr/screenshots/pmos-dark-1440x720.png
index 8f9a32ea1d963cd69d707031c07a878dad507634..6b99a5abd8eb8bf850ed7d56058644e6167401f3 100644
Binary files a/unl0kr/screenshots/pmos-dark-1440x720.png and b/unl0kr/screenshots/pmos-dark-1440x720.png differ
diff --git a/unl0kr/screenshots/pmos-dark-1920x1080.png b/unl0kr/screenshots/pmos-dark-1920x1080.png
index 99e134865e10e15b877c69c1d1f8bebe0b7de9a8..b13459d25bf60b7e196aeffeb6db1190383595f8 100644
Binary files a/unl0kr/screenshots/pmos-dark-1920x1080.png and b/unl0kr/screenshots/pmos-dark-1920x1080.png differ
diff --git a/unl0kr/screenshots/pmos-dark-480x800.png b/unl0kr/screenshots/pmos-dark-480x800.png
index e627bd9486171aa2ded95ff0d9ed7c80b4178828..d7731a7ece9bcd341cd24d50ea34a220b38343d0 100644
Binary files a/unl0kr/screenshots/pmos-dark-480x800.png and b/unl0kr/screenshots/pmos-dark-480x800.png differ
diff --git a/unl0kr/screenshots/pmos-dark-540x960.png b/unl0kr/screenshots/pmos-dark-540x960.png
index 1e92f02fce084410b466728a54c89cac0587d60b..38559556c2b4c5af6454f85757fd886499ffddd6 100644
Binary files a/unl0kr/screenshots/pmos-dark-540x960.png and b/unl0kr/screenshots/pmos-dark-540x960.png differ
diff --git a/unl0kr/screenshots/pmos-dark-768x1024.png b/unl0kr/screenshots/pmos-dark-768x1024.png
index a58cb6d7d88592208e1911d9e4afd01f7bbdec9a..7dd34ea4c57836641603ba723b20f306e229c6b5 100644
Binary files a/unl0kr/screenshots/pmos-dark-768x1024.png and b/unl0kr/screenshots/pmos-dark-768x1024.png differ
diff --git a/unl0kr/screenshots/pmos-dark-800x480.png b/unl0kr/screenshots/pmos-dark-800x480.png
index 925dc4f4579b0f291d9497827ff0119df5b76421..1b9f02bb7243d3f6c3dc826af177c3624215a0e6 100644
Binary files a/unl0kr/screenshots/pmos-dark-800x480.png and b/unl0kr/screenshots/pmos-dark-800x480.png differ
diff --git a/unl0kr/screenshots/pmos-dark-960x540.png b/unl0kr/screenshots/pmos-dark-960x540.png
index 395c205ba08cac677353834723690f9366d19d9f..198197f1925b971ecf965048a99cdb38c4a7aa60 100644
Binary files a/unl0kr/screenshots/pmos-dark-960x540.png and b/unl0kr/screenshots/pmos-dark-960x540.png differ
diff --git a/unl0kr/screenshots/pmos-light-1024x768.png b/unl0kr/screenshots/pmos-light-1024x768.png
index 966a356b9d4608f2420aa0c38e69a76fec4f12eb..9f87024929ec3f96eb2d97064e80f7f1613b090d 100644
Binary files a/unl0kr/screenshots/pmos-light-1024x768.png and b/unl0kr/screenshots/pmos-light-1024x768.png differ
diff --git a/unl0kr/screenshots/pmos-light-1280x800.png b/unl0kr/screenshots/pmos-light-1280x800.png
index be085fbf9191bfbe43a6becae6f02add85b46c87..608e306c67c8a69e55c040e8214caf9985fb895f 100644
Binary files a/unl0kr/screenshots/pmos-light-1280x800.png and b/unl0kr/screenshots/pmos-light-1280x800.png differ
diff --git a/unl0kr/screenshots/pmos-light-1440x720.png b/unl0kr/screenshots/pmos-light-1440x720.png
index fc53b5b076ffc84f56ddbff294af873d66765b1a..b2aed0947b973aaadb1d3d48c5897cecaa6fe76e 100644
Binary files a/unl0kr/screenshots/pmos-light-1440x720.png and b/unl0kr/screenshots/pmos-light-1440x720.png differ
diff --git a/unl0kr/screenshots/pmos-light-1920x1080.png b/unl0kr/screenshots/pmos-light-1920x1080.png
index 5c692ef81c9239740010ae0af47dc65a687f2480..7ccd1b5bdc9514fa6eb2082b73c670b1941080da 100644
Binary files a/unl0kr/screenshots/pmos-light-1920x1080.png and b/unl0kr/screenshots/pmos-light-1920x1080.png differ
diff --git a/unl0kr/screenshots/pmos-light-480x800.png b/unl0kr/screenshots/pmos-light-480x800.png
index a73cfabf8e2593b19f80334b51010cc352db8ea7..e1fd5e7812da31dd4dd5c051a81fbd7693a01394 100644
Binary files a/unl0kr/screenshots/pmos-light-480x800.png and b/unl0kr/screenshots/pmos-light-480x800.png differ
diff --git a/unl0kr/screenshots/pmos-light-540x960.png b/unl0kr/screenshots/pmos-light-540x960.png
index 5851701d3ae9c12059b4ce7c513abc5337288d83..e8f50cb1e632fded1a7f7ffb8aa5b95904e027a4 100644
Binary files a/unl0kr/screenshots/pmos-light-540x960.png and b/unl0kr/screenshots/pmos-light-540x960.png differ
diff --git a/unl0kr/screenshots/pmos-light-768x1024.png b/unl0kr/screenshots/pmos-light-768x1024.png
index 7e48332c8b9ae0fa8c6f4c6b48612562a0201cfc..6e4c8460e5660eb28b6890b73440e229d1d7a4c8 100644
Binary files a/unl0kr/screenshots/pmos-light-768x1024.png and b/unl0kr/screenshots/pmos-light-768x1024.png differ
diff --git a/unl0kr/screenshots/pmos-light-800x480.png b/unl0kr/screenshots/pmos-light-800x480.png
index 3f21396a612524453d857fa9084a360d0b392fc8..7e693c9da4ce3607069c62264c330793b7b536f2 100644
Binary files a/unl0kr/screenshots/pmos-light-800x480.png and b/unl0kr/screenshots/pmos-light-800x480.png differ
diff --git a/unl0kr/screenshots/pmos-light-960x540.png b/unl0kr/screenshots/pmos-light-960x540.png
index 20de34ae30e1c29d989b668798b109aa2a4a36ac..e21be29468b943e42edfb72424d6c6d432f5986f 100644
Binary files a/unl0kr/screenshots/pmos-light-960x540.png and b/unl0kr/screenshots/pmos-light-960x540.png differ
diff --git a/unl0kr/test/helpers.sh b/unl0kr/test/helpers.sh
index ff36c88d596f8e5e1738c90017bac2a73d307648..c1f8636b3fe5976e2c56c9fe899d4da5d5ff4bd7 100644
--- a/unl0kr/test/helpers.sh
+++ b/unl0kr/test/helpers.sh
@@ -1,18 +1,8 @@
 #!/bin/bash
 
-function info() {
-    echo -e "[Info] $1"
-}
-
-function error() {
-    echo -e "\e[31m[Error]\e[0m $1"
-}
-
-function ok() {
-    echo -e "\e[32m[Ok]\e[0m $1"
-}
+source "$(dirname "${BASH_SOURCE[0]}")/../../test/helpers.sh"
 
-function run_unl0kr() {
+function run_unl0kr_async() {
     local log=$1
     local conf=$2
 
@@ -23,3 +13,13 @@ function run_unl0kr() {
     kill -9 $pid
     wait $pid > /dev/null 2>&1
 }
+
+function run_unl0kr_sync() {
+    local log=$1
+    shift
+    local conf=$2
+    shift
+    local args=$@
+
+    ./_build/unl0kr -v -C "$conf" $@ > "$log" 2>&1
+}
\ No newline at end of file
diff --git a/unl0kr/test/test-uses-drm-backend-if-selected-via-config-and-available.sh b/unl0kr/test/test-uses-drm-backend-if-selected-via-config-and-available.sh
index b4ed20ad5ee17894917b876b583da5cbe2aace9f..2257a802442d88644df2a926309c408836026294 100755
--- a/unl0kr/test/test-uses-drm-backend-if-selected-via-config-and-available.sh
+++ b/unl0kr/test/test-uses-drm-backend-if-selected-via-config-and-available.sh
@@ -18,7 +18,7 @@ backend=drm
 EOF
 
 info "Running unl0kr"
-run_unl0kr "$log" "$conf"
+run_unl0kr_async "$log" "$conf"
 
 info "Verifying output"
 if ! grep "Using DRM backend" "$log"; then
diff --git a/unl0kr/test/test-uses-fb-backend-by-default.sh b/unl0kr/test/test-uses-fb-backend-by-default.sh
index 7e19b1b622789de974a48f265d013d77d7bb3165..3775bf5899e0a1cd92e25e43eac05003c766606c 100755
--- a/unl0kr/test/test-uses-fb-backend-by-default.sh
+++ b/unl0kr/test/test-uses-fb-backend-by-default.sh
@@ -11,7 +11,7 @@ function clean_up() {
 trap clean_up EXIT
 
 info "Running unl0kr"
-run_unl0kr "$log"
+run_unl0kr_async "$log"
 
 info "Verifying output"
 if ! grep "Using framebuffer backend" "$log"; then
diff --git a/unl0kr/test/test-uses-fb-backend-if-drm-selected-via-config-but-unavailable.sh b/unl0kr/test/test-uses-fb-backend-if-drm-selected-via-config-but-unavailable.sh
index 8f324276e0d718bd7efddd15d855516993dadb86..717a09b5a00f209ba44337905f2111d10fe5a8fb 100755
--- a/unl0kr/test/test-uses-fb-backend-if-drm-selected-via-config-but-unavailable.sh
+++ b/unl0kr/test/test-uses-fb-backend-if-drm-selected-via-config-but-unavailable.sh
@@ -18,7 +18,7 @@ backend=drm
 EOF
 
 info "Running unl0kr"
-run_unl0kr "$log" "$conf"
+run_unl0kr_async "$log" "$conf"
 
 info "Verifying output"
 if ! grep "Using framebuffer backend" "$log"; then
diff --git a/unl0kr/test/test-uses-fb-backend-if-selected-via-config.sh b/unl0kr/test/test-uses-fb-backend-if-selected-via-config.sh
index fb585e8d191bc5211235cf29e7bc2522e7476e2a..31d4431ae86ea39cec415b24b8a193ae553b0e43 100755
--- a/unl0kr/test/test-uses-fb-backend-if-selected-via-config.sh
+++ b/unl0kr/test/test-uses-fb-backend-if-selected-via-config.sh
@@ -18,7 +18,7 @@ backend=fb
 EOF
 
 info "Running unl0kr"
-run_unl0kr "$log" "$conf"
+run_unl0kr_async "$log" "$conf"
 
 info "Verifying output"
 if ! grep "Using framebuffer backend" "$log"; then
diff --git a/unl0kr/test/test-version-matches-meson-and-changelog.sh b/unl0kr/test/test-version-matches-meson-and-changelog.sh
new file mode 100755
index 0000000000000000000000000000000000000000..887ee8374f15f06a8344d2ca83ab4804b53cc40c
--- /dev/null
+++ b/unl0kr/test/test-version-matches-meson-and-changelog.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+log=tmp.log
+
+root=$(dirname "${BASH_SOURCE[0]}")
+
+source "$root/helpers.sh"
+
+function clean_up() {
+    rm -f "$log"
+}
+
+trap clean_up EXIT
+
+info "Querying version from build.meson"
+meson_version=$(read_version_from_meson)
+
+info "Querying version from CHANGELOG.md"
+changelog_version=$(read_version_from_changelog)
+
+info "Verifying versions"
+if [[ "$meson_version" != "$changelog_version" ]]; then
+    error "Version $meson_version from meson.build doesn't match version $changelog_version from CHANGELOG.md"
+    exit 1
+fi
+
+info "Running unl0kr"
+run_unl0kr_sync "$log" "$conf" -V
+
+info "Verifying output"
+if ! grep "unl0kr $meson_version" "$log"; then
+    error "Expected version $meson_version"
+    cat "$log"
+    exit 1
+fi
+
+ok
diff --git a/unl0kr/test/test-with-drm.sh b/unl0kr/test/test-with-drm.sh
index 445dc3310fd6c6a33d674135308ce9f62e9a1440..82255104566640498a8502c12fb101eb738fc091 100755
--- a/unl0kr/test/test-with-drm.sh
+++ b/unl0kr/test/test-with-drm.sh
@@ -4,13 +4,8 @@ root=$(dirname "${BASH_SOURCE[0]}")
 
 source "$root/helpers.sh"
 
-function run() {
-    info "Executing $1"
-    "$1"
-    echo
-}
-
-run "$root/build-with-drm.sh"
-run "$root/test-uses-fb-backend-by-default.sh"
-run "$root/test-uses-fb-backend-if-selected-via-config.sh"
-run "$root/test-uses-drm-backend-if-selected-via-config-and-available.sh"
+run_script "$root/build-with-drm.sh"
+run_script "$root/test-version-matches-meson-and-changelog.sh"
+run_script "$root/test-uses-fb-backend-by-default.sh"
+run_script "$root/test-uses-fb-backend-if-selected-via-config.sh"
+run_script "$root/test-uses-drm-backend-if-selected-via-config-and-available.sh"
diff --git a/unl0kr/test/test-without-drm.sh b/unl0kr/test/test-without-drm.sh
index 11e01fc5fd22e5fd37e2d7deb35392c6ebd7578e..a8e86c99008bf5820e31ba08be1aff8bf2ecbb1d 100755
--- a/unl0kr/test/test-without-drm.sh
+++ b/unl0kr/test/test-without-drm.sh
@@ -4,13 +4,8 @@ root=$(dirname "${BASH_SOURCE[0]}")
 
 source "$root/helpers.sh"
 
-function run() {
-    info "Executing $1"
-    "$1"
-    echo
-}
-
-run "$root/build-without-drm.sh"
-run "$root/test-uses-fb-backend-by-default.sh"
-run "$root/test-uses-fb-backend-if-selected-via-config.sh"
-run "$root/test-uses-fb-backend-if-drm-selected-via-config-but-unavailable.sh"
+run_script "$root/build-without-drm.sh"
+run_script "$root/test-version-matches-meson-and-changelog.sh"
+run_script "$root/test-uses-fb-backend-by-default.sh"
+run_script "$root/test-uses-fb-backend-if-selected-via-config.sh"
+run_script "$root/test-uses-fb-backend-if-drm-selected-via-config-but-unavailable.sh"