diff --git a/README.md b/README.md
index 9e5010c..26dc996 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,21 @@ Below is a summary of contributions upstreamed thus far.
- [Automatic device discovery via libinput] (✅ merged)
- [Make it possible to use multiple devices with the libinput and XKB drivers] (⏳ in review)
+# Usage
+
+For an overview of available command line options, run unl0kr with the `-h` or `--help` argument.
+
+```
+$ unl0kr --help
+Usage: unl0kr [OPTION]
+
+Mandatory arguments to long options are mandatory for short options too.
+ -g, --geometry=NxM Force a display size of N horizontal times M vertical pixels
+ -h, --help Print this message and exit
+ -v, --verbose Enable more detailed logging output on STDERR
+ -V, --version Print the unl0kr version and exit
+```
+
# Development
## Dependencies
diff --git a/command_line.c b/command_line.c
new file mode 100644
index 0000000..8b9bbd9
--- /dev/null
+++ b/command_line.c
@@ -0,0 +1,108 @@
+/**
+ * Copyright 2021 Johannes Marbach
+ *
+ * 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 "command_line.h"
+
+#include "unl0kr.h"
+
+#include
+#include
+#include
+
+
+/**
+ * Static prototypes
+ */
+
+/**
+ * Initialise a command line options struct with default values.
+ *
+ * @param opts pointer to the options struct
+ */
+static void init_opts(ul_cli_opts *cli_opts);
+
+/**
+ * Output usage instructions.
+ */
+static void print_usage();
+
+
+/**
+ * Static functions
+ */
+
+static void init_opts(ul_cli_opts *cli_opts) {
+ cli_opts->hor_res = -1;
+ cli_opts->ver_res = -1;
+ cli_opts->verbose = false;
+}
+
+static void print_usage() {
+ fprintf(stderr,
+ "Usage: unl0kr [OPTION]\n"
+ "\n"
+ "Mandatory arguments to long options are mandatory for short options too.\n"
+ " -g, --geometry=NxM Force a display size of N horizontal times M vertical pixels\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");
+}
+
+
+/**
+ * Public functions
+ */
+
+void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *cli_opts) {
+ init_opts(cli_opts);
+
+ struct option opts[] = {
+ { "geometry", required_argument, NULL, 'g' },
+ { "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, "g:hvV", opts, &index)) != -1) {
+ switch (opt) {
+ case 'g':
+ if (sscanf(optarg, "%ix%i", &(cli_opts->hor_res), &(cli_opts->ver_res)) != 2) {
+ fprintf(stderr, "Error: invalid geometry argument \"%s\"\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'h':
+ print_usage();
+ exit(EXIT_SUCCESS);
+ case 'v':
+ cli_opts->verbose = true;
+ break;
+ case 'V':
+ fprintf(stderr, "unl0kr %s\n", UL_VERSION);
+ exit(0);
+ default:
+ print_usage();
+ exit(EXIT_FAILURE);
+ }
+ }
+}
diff --git a/command_line.h b/command_line.h
new file mode 100644
index 0000000..121dc29
--- /dev/null
+++ b/command_line.h
@@ -0,0 +1,47 @@
+/**
+ * Copyright 2021 Johannes Marbach
+ *
+ * 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_COMMAND_LINE_H
+#define UL_COMMAND_LINE_H
+
+#include
+
+/**
+ * Options parsed from command line arguments
+ */
+typedef struct {
+ /* Horizontal display resolution */
+ int hor_res;
+ /* Vertical display resolution */
+ int ver_res;
+ /* Verbose mode. If true, provide more detailed logging output on STDERR. */
+ bool verbose;
+} ul_cli_opts;
+
+/**
+ * Parse command line arguments and exit on failure.
+ *
+ * @param argc number of provided command line arguments
+ * @param argv arguments as an array of strings
+ * @param cli_opts pointer for writing the parsed options into
+ */
+void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *cli_opts);
+
+#endif /* UL_COMMAND_LINE_H */
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..7449d0e
--- /dev/null
+++ b/log.c
@@ -0,0 +1,54 @@
+/**
+ * Copyright 2021 Johannes Marbach
+ *
+ * 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 "log.h"
+
+#include
+
+
+/**
+ * Static variables
+ */
+
+static ul_log_level log_level = UL_LOG_LEVEL_ERROR;
+
+
+/**
+ * Public functions
+ */
+
+void ul_set_log_level(ul_log_level level) {
+ log_level = level;
+}
+
+void ul_log(ul_log_level level, const char *format, ...) {
+ if (level > log_level) {
+ return;
+ }
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+void ul_print_cb(const char *msg) {
+ ul_log(UL_LOG_LEVEL_VERBOSE, "%s\n", msg);
+}
diff --git a/log.h b/log.h
new file mode 100644
index 0000000..a194336
--- /dev/null
+++ b/log.h
@@ -0,0 +1,59 @@
+/**
+ * Copyright 2021 Johannes Marbach
+ *
+ * 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_LOG_H
+#define UL_LOG_H
+
+#include
+
+/**
+ * Log levels
+ */
+typedef enum {
+ /* Errors only */
+ UL_LOG_LEVEL_ERROR = 0,
+ /* Include non-errors in log */
+ UL_LOG_LEVEL_VERBOSE = 1
+} ul_log_level;
+
+/**
+ * Set the log level.
+ *
+ * @param level new log level value
+ */
+void ul_set_log_level(ul_log_level level);
+
+/**
+ * Log a message.
+ *
+ * @param level log level of the message
+ * @param format message format string
+ * @param ... parameters to fill into the format string
+ */
+void ul_log(ul_log_level level, const char *format, ...);
+
+/**
+ * Handle an LVGL log message.
+ *
+ * @param msg message to print
+ */
+void ul_print_cb(const char *msg);
+
+#endif /* UL_LOG_H */
diff --git a/main.c b/main.c
index d02553c..830ddcf 100644
--- a/main.c
+++ b/main.c
@@ -18,9 +18,12 @@
*/
+#include "command_line.h"
#include "cursor.h"
#include "libinput_multi.h"
#include "libinput_xkb.h"
+#include "log.h"
+#include "unl0kr.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_drivers/indev/libinput_drv.h"
@@ -329,17 +332,36 @@ static void keyboard_ready_cb(lv_event_t *event) {
* Main
*/
-int main(void) {
- /* Initialise lvgl and framebuffer driver */
- lv_init();
- fbdev_init();
+int main(int argc, char *argv[]) {
+ /* Parse command line options */
+ ul_cli_opts opts;
+ ul_cli_parse_opts(argc, argv, &opts);
- /* Query display size */
+ /* Set up log level */
+ if (opts.verbose) {
+ ul_set_log_level(UL_LOG_LEVEL_VERBOSE);
+ }
+
+ /* Announce ourselves */
+ ul_log(UL_LOG_LEVEL_VERBOSE, "unl0kr %s", UL_VERSION);
+
+ /* Initialise LVGL and set up logging callback */
+ lv_init();
+ lv_log_register_print_cb(ul_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);
+ fbdev_get_sizes(&hor_res, &ver_res);
- // hor_res = ver_res * 0.6; /* Simulate mobile screen */
+ /* Override display size with command line options if necessary */
+ if (opts.hor_res > 0) {
+ hor_res = LV_MIN(hor_res, opts.hor_res);
+ }
+ if (opts.ver_res > 0) {
+ ver_res = LV_MIN(ver_res, opts.ver_res);
+ }
/* Prepare display buffer */
const size_t buf_size = hor_res * ver_res / 10; /* At least 1/10 of the display size is recommended */
@@ -364,7 +386,7 @@ int main(void) {
lv_indev_t *keyboard_indevs[MAX_KEYBOARDS] = { NULL, NULL, NULL };
size_t num_keyboards = libinput_find_devs(LIBINPUT_CAPABILITY_KEYBOARD, keyboard_devices, MAX_KEYBOARDS, false);
for (int i = 0; i < num_keyboards; ++i) {
- printf("found keyboard device %s\n", keyboard_devices[i]);
+ ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting keyboard device %s\n", keyboard_devices[i]);
lv_indev_drv_init(&keyboard_indev_drvs[i]);
keyboard_indev_drvs[i].type = LV_INDEV_TYPE_KEYPAD;
keyboard_indev_drvs[i].read_cb = libinput_multi_read;
@@ -385,7 +407,7 @@ int main(void) {
lv_indev_t *pointer_indevs[MAX_POINTER_DEVICES] = { NULL, NULL, NULL, NULL };
size_t num_pointer_devices = libinput_find_devs(LIBINPUT_CAPABILITY_POINTER, pointer_devices, MAX_POINTER_DEVICES, false);
for (int i = 0; i < num_pointer_devices; ++i) {
- printf("found pointer device %s\n", pointer_devices[i]);
+ ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting pointer device %s\n", pointer_devices[i]);
lv_indev_drv_init(&pointer_indev_drvs[i]);
pointer_indev_drvs[i].type = LV_INDEV_TYPE_POINTER;
pointer_indev_drvs[i].read_cb = libinput_multi_read;
@@ -410,7 +432,7 @@ int main(void) {
lv_indev_drv_t touchscreen_indev_drvs[MAX_TOUCHSCREENS];
size_t num_touchscreens = libinput_find_devs(LIBINPUT_CAPABILITY_TOUCH, touchscreens, MAX_TOUCHSCREENS, false);
for (int i = 0; i < num_touchscreens; ++i) {
- printf("found touchscreen %s\n", touchscreens[i]);
+ ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting touchscreen device %s\n", touchscreens[i]);
lv_indev_drv_init(&touchscreen_indev_drvs[i]);
touchscreen_indev_drvs[i].type = LV_INDEV_TYPE_POINTER;
touchscreen_indev_drvs[i].read_cb = libinput_multi_read;
diff --git a/meson.build b/meson.build
index 89284ea..42328a9 100644
--- a/meson.build
+++ b/meson.build
@@ -24,11 +24,15 @@ project(
meson_version: '>=0.53.0'
)
+add_project_arguments('-DUL_VERSION="@0@"'.format(meson.project_version()), language: ['c'])
+
unl0kr_sources = [
+ 'command_line.c',
'cursor.c',
- 'main.c',
+ 'log.c',
'libinput_multi.c',
'libinput_xkb.c',
+ 'main.c',
'montserrat_extended_32.c',
'sq2lv_layouts.c',
]
diff --git a/unl0kr.h b/unl0kr.h
new file mode 100644
index 0000000..c6096d8
--- /dev/null
+++ b/unl0kr.h
@@ -0,0 +1,28 @@
+/**
+ * Copyright 2021 Johannes Marbach
+ *
+ * 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_UNL0KR_H
+#define UL_UNL0KR_H
+
+#ifndef UL_VERSION
+#define UL_VERSION "?" /* Just to silence IDE warning. Real version injected by meson during build. */
+#endif
+
+#endif /* UL_UNL0KR_H */