diff --git a/CHANGELOG.md b/CHANGELOG.md
index c01aa49..9e83606 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,8 @@
- fix: Prevent scrolling when keyboard hides (#21)
- feat!: Do not show last typed character when typing (#25)
- feat: Update lvgl & lv_drivers to git master (2022-02-21)
+- feat: allow runtime selection of the lvgl display driver ("backend")
+- feat: allow overriding dpi with the --dpi command line parameter
## 0.1.0 (2021-11-15)
diff --git a/README.md b/README.md
index f0b5c3f..f7a8a46 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
Unl0kr
======
-Framebuffer-based disk unlocker for the initramfs based on [LVGL].
+Disk unlocker for the initramfs based on [LVGL].
[[_TOC_]]
@@ -72,6 +72,7 @@ Mandatory arguments to long options are mandatory for short options too.
order.
-g, --geometry=NxM Force a display size of N horizontal times M
vertical pixels
+ -d --dpi=N Overrides the DPI
-h, --help Print this message and exit
-v, --verbose Enable more detailed logging output on STDERR
-V, --version Print the unl0kr version and exit
@@ -89,6 +90,7 @@ For an example configuration file, see [unl0kr.conf].
- [squeek2lvgl] (git submodule / linked statically)
- [libinput]
- [libxkbcommon]
+- [libdrm] (optional, required for the DRM backend)
- evdev kernel module
## Building & running
@@ -104,6 +106,28 @@ $ sudo ./_build/unl0kr
With meson <0\.55 use `ninja` instead of `meson compile`\.
+### Optional features
+
+If [libdrm] is installed, the DRM backend will be compiled automatically. It's possible to
+change this behaviour using the `with-drm` meson feature. For example,
+
+```
+$ meson _build -Dwith-drm=disabled
+```
+
+will forcibly disable the DRM backend regardless if libdrm is installed or not.
+
+## Backends
+
+Unl0kr supports multiple lvgl display drivers, which are herein referred as "backends".
+
+Currently supported backends:
+
+- fbdev
+- drm (optional)
+
+The backend can be switched at runtime by modifying the `general.backend` configuration.
+
## Fonts
In order to work with [LVGL], fonts need to be converted to bitmaps, stored as C arrays. Unl0kr currently uses a combination of the [OpenSans] font for text and the [FontAwesome] font for pictograms. For both fonts only limited character ranges are included to reduce the binary size. To (re)generate the C file containing the combined font, run the following command
@@ -200,6 +224,7 @@ The [FontAwesome] font is licensed under the Open Font License version 1.1.
[inih]: https://github.com/benhoyt/inih
[libinput]: https://gitlab.freedesktop.org/libinput/libinput
[libxkbcommon]: https://github.com/xkbcommon/libxkbcommon
+[libdrm]: https://gitlab.freedesktop.org/mesa/drm
[lv_drivers]: https://github.com/lvgl/lv_drivers
[lv_port_linux_frame_buffer]: https://github.com/lvgl/lv_port_linux_frame_buffer
[lv_sim_emscripten]: https://github.com/lvgl/lv_sim_emscripten/blob/master/mouse_cursor_icon.c
diff --git a/backends.c b/backends.c
new file mode 100644
index 0000000..7ac3af9
--- /dev/null
+++ b/backends.c
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2022 Eugenio Paolantonio (g7)
+ *
+ * This file is part of unl0kr, hereafter referred to as the program.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#include "backends.h"
+
+#include
+
+/**
+ * Public interface
+ */
+
+const char *ul_backends_backends[] = {
+#if USE_FBDEV
+ "fbdev",
+#endif /* USE_FBDEV */
+#if USE_DRM
+ "drm",
+#endif /* USE_DRM */
+ NULL
+};
+
+ul_backends_backend_id_t ul_backends_find_backend_with_name(const char *name) {
+ for (int i = 0; ul_backends_backends[i] != NULL; ++i) {
+ if (strcmp(ul_backends_backends[i], name) == 0) {
+ ul_log(UL_LOG_LEVEL_VERBOSE, "Found backend: %s\n", name);
+ return i;
+ }
+ }
+ ul_log(UL_LOG_LEVEL_WARNING, "Backend %s not found\n", name);
+ return UL_BACKENDS_BACKEND_NONE;
+}
diff --git a/backends.h b/backends.h
new file mode 100644
index 0000000..5e1dc1c
--- /dev/null
+++ b/backends.h
@@ -0,0 +1,50 @@
+/**
+ * Copyright 2022 Eugenio Paolantonio (g7)
+ *
+ * This file is part of unl0kr, hereafter referred to as the program.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#ifndef UL_BACKENDS_H
+#define UL_BACKENDS_H
+
+#include "lv_drv_conf.h"
+
+#include "log.h"
+
+/* NOTE: Only UL_BACKENDS_BACKEND_NONE is ought to have an explicit value assigned */
+typedef enum {
+ UL_BACKENDS_BACKEND_NONE = -1,
+#if USE_FBDEV
+ UL_BACKENDS_BACKEND_FBDEV,
+#endif /* USE_FBDEV */
+#if USE_DRM
+ UL_BACKENDS_BACKEND_DRM,
+#endif /* USE_DRM */
+} ul_backends_backend_id_t;
+
+/* Backends */
+extern const char *ul_backends_backends[];
+
+/**
+ * Find the first backend with a given name.
+ *
+ * @param name backend name
+ * @return ID of the first matching backend or UL_BACKENDS_BACKEND_NONE if no backend matched
+ */
+ul_backends_backend_id_t ul_backends_find_backend_with_name(const char *name);
+
+#endif /* UL_BACKENDS_H */
diff --git a/command_line.c b/command_line.c
index 183496d..872717c 100644
--- a/command_line.c
+++ b/command_line.c
@@ -82,6 +82,7 @@ static void print_usage() {
" order.\n"
" -g, --geometry=NxM Force a display size of N horizontal times M\n"
" vertical pixels\n"
+ " -d --dpi=N Overrides the DPI\n"
" -h, --help Print this message and exit\n"
" -v, --verbose Enable more detailed logging output on STDERR\n"
" -V, --version Print the unl0kr version and exit\n");
@@ -100,6 +101,7 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) {
{ "config", required_argument, NULL, 'c' },
{ "config-override", required_argument, NULL, 'C' },
{ "geometry", required_argument, NULL, 'g' },
+ { "dpi", required_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
@@ -108,7 +110,7 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) {
int opt, index = 0;
- while ((opt = getopt_long(argc, argv, "c:C:g:hvV", long_opts, &index)) != -1) {
+ while ((opt = getopt_long(argc, argv, "c:C:g:d:hvV", long_opts, &index)) != -1) {
switch (opt) {
case 'c':
opts->config_files[0] = optarg;
@@ -128,6 +130,12 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) {
exit(EXIT_FAILURE);
}
break;
+ case 'd':
+ if (sscanf(optarg, "%i", &(opts->dpi)) != 1) {
+ ul_log(UL_LOG_LEVEL_ERROR, "Invalid dpi argument \"%s\"\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
case 'h':
print_usage();
exit(EXIT_SUCCESS);
diff --git a/command_line.h b/command_line.h
index beb357d..5a98923 100644
--- a/command_line.h
+++ b/command_line.h
@@ -35,6 +35,8 @@ typedef struct {
int hor_res;
/* Vertical display resolution */
int ver_res;
+ /* DPI */
+ int dpi;
/* Verbose mode. If true, provide more detailed logging output on STDERR. */
bool verbose;
} ul_cli_opts;
diff --git a/config.c b/config.c
index 71e4bb4..da4c985 100644
--- a/config.c
+++ b/config.c
@@ -73,6 +73,7 @@ static bool parse_bool(const char *value, bool *result);
static void init_opts(ul_config_opts *opts) {
opts->general.animations = false;
+ opts->general.backend = ul_backends_backends[0] == NULL ? UL_BACKENDS_BACKEND_NONE : 0;
opts->keyboard.autohide = true;
opts->keyboard.layout_id = SQ2LV_LAYOUT_US;
opts->keyboard.popovers = false;
@@ -95,6 +96,12 @@ static int parsing_handler(void* user_data, const char* section, const char* key
if (parse_bool(value, &(opts->general.animations))) {
return 1;
}
+ } else if (strcmp(key, "backend") == 0) {
+ ul_backends_backend_id_t id = ul_backends_find_backend_with_name(value);
+ if (id != UL_BACKENDS_BACKEND_NONE) {
+ opts->general.backend = id;
+ return 1;
+ }
}
} else if (strcmp(section, "keyboard") == 0) {
if (strcmp(key, "autohide") == 0) {
diff --git a/config.h b/config.h
index 5c582e6..948f29c 100644
--- a/config.h
+++ b/config.h
@@ -21,6 +21,8 @@
#ifndef UL_CONFIG_H
#define UL_CONFIG_H
+#include "backends.h"
+
#include "themes.h"
#include "sq2lv_layouts.h"
@@ -31,6 +33,8 @@
* General options
*/
typedef struct {
+ /* Backend to use */
+ ul_backends_backend_id_t backend;
/* If true, use animations */
bool animations;
} ul_config_opts_general;
diff --git a/main.c b/main.c
index 5e7c506..3054031 100644
--- a/main.c
+++ b/main.c
@@ -18,6 +18,7 @@
*/
+#include "backends.h"
#include "command_line.h"
#include "config.h"
#include "indev.h"
@@ -27,7 +28,14 @@
#include "theme.h"
#include "themes.h"
+#include "lv_drv_conf.h"
+
+#if USE_FBDEV
#include "lv_drivers/display/fbdev.h"
+#endif /* USE_FBDEV */
+#if USE_DRM
+#include "lv_drivers/display/drm.h"
+#endif /* USE_DRM */
#include "lvgl/lvgl.h"
@@ -338,19 +346,45 @@ int main(int argc, char *argv[]) {
lv_init();
lv_log_register_print_cb(ul_log_print_cb);
- /* Initialise framebuffer driver and query display size */
- fbdev_init();
- uint32_t hor_res;
- uint32_t ver_res;
- fbdev_get_sizes(&hor_res, &ver_res);
+ /* Initialise display driver */
+ static lv_disp_drv_t disp_drv;
+ lv_disp_drv_init(&disp_drv);
- /* Override display size with command line options if necessary */
+ /* Initialise framebuffer driver and query display size */
+ uint32_t hor_res = 0;
+ uint32_t ver_res = 0;
+ uint32_t dpi = 0;
+
+ switch (conf_opts.general.backend) {
+#if USE_FBDEV
+ case UL_BACKENDS_BACKEND_FBDEV:
+ fbdev_init();
+ fbdev_get_sizes(&hor_res, &ver_res);
+ disp_drv.flush_cb = fbdev_flush;
+ break;
+#endif /* USE_FBDEV */
+#if USE_DRM
+ case UL_BACKENDS_BACKEND_DRM:
+ drm_init();
+ drm_get_sizes((lv_coord_t *)&hor_res, (lv_coord_t *)&ver_res, &dpi);
+ disp_drv.flush_cb = drm_flush;
+ break;
+#endif /* USE_DRM */
+ default:
+ ul_log(UL_LOG_LEVEL_ERROR, "Unable to find suitable backend");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Override display parameters with command line options if necessary */
if (cli_opts.hor_res > 0) {
hor_res = LV_MIN(hor_res, cli_opts.hor_res);
}
if (cli_opts.ver_res > 0) {
ver_res = LV_MIN(ver_res, cli_opts.ver_res);
}
+ if (cli_opts.dpi > 0) {
+ dpi = cli_opts.dpi;
+ }
/* Prepare display buffer */
const size_t buf_size = hor_res * ver_res / 10; /* At least 1/10 of the display size is recommended */
@@ -358,13 +392,12 @@ int main(int argc, char *argv[]) {
lv_color_t *buf = (lv_color_t *)malloc(buf_size * sizeof(lv_color_t));
lv_disp_draw_buf_init(&disp_buf, buf, NULL, buf_size);
- /* Initialise display driver */
- static lv_disp_drv_t disp_drv;
- lv_disp_drv_init(&disp_drv);
+
+ /* Register display driver */
disp_drv.draw_buf = &disp_buf;
- disp_drv.flush_cb = fbdev_flush;
disp_drv.hor_res = hor_res;
disp_drv.ver_res = ver_res;
+ disp_drv.dpi = dpi;
lv_disp_drv_register(&disp_drv);
/* Connect input devices */
diff --git a/meson.build b/meson.build
index 45d2b9d..359495c 100644
--- a/meson.build
+++ b/meson.build
@@ -27,6 +27,7 @@ project(
add_project_arguments('-DUL_VERSION="@0@"'.format(meson.project_version()), language: ['c'])
unl0kr_sources = [
+ 'backends.c',
'command_line.c',
'config.c',
'cursor.c',
@@ -37,13 +38,25 @@ unl0kr_sources = [
'sq2lv_layouts.c',
'terminal.c',
'theme.c',
- 'themes.c'
+ 'themes.c',
]
squeek2lvgl_sources = [
'squeek2lvgl/sq2lv.c',
]
+unl0kr_dependencies = [
+ dependency('inih'),
+ dependency('libinput'),
+ dependency('xkbcommon'),
+]
+
+libdrm_dep = dependency('libdrm', required: get_option('with-drm'))
+if libdrm_dep.found()
+ unl0kr_dependencies += [libdrm_dep]
+ add_project_arguments('-DUSE_DRM=1', language: ['c'])
+endif
+
lvgl_sources = run_command('find-lvgl-sources.sh', 'lvgl', check: true).stdout().strip().split('\n')
lv_drivers_sources = run_command('find-lvgl-sources.sh', 'lv_drivers', check: true).stdout().strip().split('\n')
@@ -54,10 +67,6 @@ executable(
'unl0kr',
sources: unl0kr_sources + squeek2lvgl_sources + lvgl_sources + lv_drivers_sources,
include_directories: ['lvgl', 'lv_drivers'],
- dependencies: [
- dependency('inih'),
- dependency('libinput'),
- dependency('xkbcommon')
- ],
+ dependencies: unl0kr_dependencies,
install: true
)
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..2b2783b
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1 @@
+option('with-drm', type : 'feature', value : 'auto', description : 'Enable DRM backend')
diff --git a/unl0kr.conf b/unl0kr.conf
index 4486809..9e75f31 100644
--- a/unl0kr.conf
+++ b/unl0kr.conf
@@ -1,5 +1,6 @@
[general]
animations=true
+#backend=fbdev
[keyboard]
autohide=true