suggestion picker: a persistent layer to complement virtual keyboards like wvkbd
-rw-r--r--README.md5
-rw-r--r--config.mk2
-rw-r--r--main.c147
3 files changed, 102 insertions, 52 deletions
diff --git a/README.md b/README.md
index f9e4254..4d938e4 100644
--- a/README.md
+++ b/README.md
@@ -13,14 +13,15 @@ Each line of input is treated as TSV.
You'll need the following developer packages
- - pangocairo
+ - cairo
+ - pango
- wayland-client
Make any customizations you would like in `config.h` and run `make`
## Usage
-The keyboard can be hidden by sending it a `SIGUSR1` signal and shown again by sending it `SIGUSR2`. This saves some
+The keyboard can be hidden by sending it a `SIGUSR1` signal, shown again by sending it `SIGUSR2`, or toggled by sending it `SIGRTMIN`. This saves some
start up time and may be appropriate in some low-resource environments.
## Contribute
diff --git a/config.mk b/config.mk
index 7a7a93e..fd9f467 100644
--- a/config.mk
+++ b/config.mk
@@ -1,2 +1,2 @@
-VERSION = 0.1.2
+VERSION = 0.1.4
CFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=700
diff --git a/main.c b/main.c
index ad9ffef..848041b 100644
--- a/main.c
+++ b/main.c
@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/signalfd.h>
#include <unistd.h>
#include <wayland-client.h>
#include <wchar.h>
@@ -17,7 +18,7 @@
exit(1)
/* client state */
-static const char *namespace = "wlroots";
+static const char *namespace = "suggpicker";
static struct wl_display *display;
static struct wl_compositor *compositor;
static struct wl_seat *seat;
@@ -43,6 +44,7 @@ static int cur_x = -1, cur_y = -1;
static bool cur_press = false;
static struct kbd keyboard;
static uint32_t height, normal_height, landscape_height;
+static bool hidden = false;
/* event handler prototypes */
static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
@@ -245,7 +247,8 @@ display_handle_geometry(void *data, struct wl_output *wl_output, int x, int y,
physical_height = tmp;
}
bool landscape = physical_width > physical_height;
- if (landscape == keyboard.landscape) return;
+ if (landscape == keyboard.landscape)
+ return;
keyboard.landscape = landscape;
if (keyboard.landscape) {
height = landscape_height;
@@ -253,9 +256,11 @@ display_handle_geometry(void *data, struct wl_output *wl_output, int x, int y,
height = normal_height;
}
- zwlr_layer_surface_v1_set_size(layer_surface, 0, height);
- zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, height);
- wl_surface_commit(draw_surf.surf);
+ if (layer_surface) {
+ zwlr_layer_surface_v1_set_size(layer_surface, 0, height);
+ zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, height);
+ wl_surface_commit(draw_surf.surf);
+ }
}
static void
@@ -295,7 +300,6 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name,
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
layer_shell =
wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1);
-
}
}
@@ -305,10 +309,11 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) {}
void
layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface,
uint32_t serial, uint32_t w, uint32_t h) {
- if (w != keyboard.w || h != keyboard.h) {
+ if (w != keyboard.w || h != keyboard.h || hidden) {
keyboard.w = w;
keyboard.h = h;
kbd_resize(&keyboard);
+ hidden = false;
}
zwlr_layer_surface_v1_ack_configure(surface, serial);
@@ -338,20 +343,26 @@ usage(char *argv0) {
void
hide(int sigint) {
- signal(SIGUSR1, hide);
+ if (keyboard.debug)
+ fprintf(stderr, "hiding keyboard\n");
if (!layer_surface) {
+ if (keyboard.debug)
+ fprintf(stderr, "can't hide nothing\n");
return;
}
-
zwlr_layer_surface_v1_destroy(layer_surface);
wl_surface_destroy(draw_surf.surf);
layer_surface = NULL;
+ hidden = true;
}
void
show(int sigint) {
- signal(SIGUSR2, show);
+ if (keyboard.debug)
+ fprintf(stderr, "showing keyboard\n");
if (layer_surface) {
+ if (keyboard.debug)
+ fprintf(stderr, "already shown\n");
return;
}
@@ -369,12 +380,19 @@ show(int sigint) {
zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener,
NULL);
wl_surface_commit(draw_surf.surf);
-
- wl_display_roundtrip(display);
- drwsurf_flip(&draw_surf);
}
void
+toggle_visibility(int sigint) {
+ if (keyboard.debug)
+ fprintf(stderr, "toggling visibility\n");
+ if (hidden) {
+ show(sigint);
+ } else {
+ hide(sigint);
+ }
+}
+void
handle_input(FILE *fd, struct key *sugg, struct kbd *kb) {
char *line;
line = malloc(1024);
@@ -384,19 +402,19 @@ handle_input(FILE *fd, struct key *sugg, struct kbd *kb) {
int i;
struct key *key = sugg;
char *l = line;
- for (i = 0; l[i+1]; i++) {
+ for (i = 0; l[i + 1]; i++) {
if (l[i] == '\t') {
free(key->label);
- key->label = strndup(l,i);
+ key->label = strndup(l, i);
l += i + 1;
i = 0;
key++;
} else if (l[i] == '\n') {
break;
}
- }
+ }
free(key->label);
- key->label = strndup(l,i);
+ key->label = strndup(l, i);
key++;
free(key->label);
key->label = NULL;
@@ -408,6 +426,11 @@ handle_input(FILE *fd, struct key *sugg, struct kbd *kb) {
free(line);
}
+void
+pipewarn(int sigint) {
+ fprintf(stderr, "suggpicker: cannot pipe data out.\n");
+}
+
int
main(int argc, char **argv) {
/* parse command line arguments */
@@ -418,8 +441,6 @@ main(int argc, char **argv) {
/* keyboard settings */
keyboard.scheme = scheme;
- bool starthidden = false;
-
int i;
for (i = 1; argv[i]; i++) {
if ((!strcmp(argv[i], "-v")) || (!strcmp(argv[i], "--version"))) {
@@ -428,11 +449,6 @@ main(int argc, char **argv) {
} else if ((!strcmp(argv[i], "-h")) || (!strcmp(argv[i], "--help"))) {
usage(argv[0]);
exit(0);
- } else if (!strcmp(argv[i], "-l")) {
- if (i >= argc - 1) {
- usage(argv[0]);
- exit(1);
- }
} else if (!strcmp(argv[i], "-H")) {
if (i >= argc - 1) {
usage(argv[0]);
@@ -451,7 +467,7 @@ main(int argc, char **argv) {
fc_font_pattern = estrdup(argv[++i]);
} else if ((!strcmp(argv[i], "-hidden")) ||
(!strcmp(argv[i], "--hidden"))) {
- starthidden = true;
+ hidden = true;
} else {
fprintf(stderr, "Invalid argument: %s\n", argv[i]);
usage(argv[0]);
@@ -490,36 +506,69 @@ main(int argc, char **argv) {
draw_ctx.font_description =
pango_font_description_from_string(fc_font_pattern);
- if (!starthidden) {
+ if (!hidden) {
show(0);
- } else {
- signal(SIGUSR2, show);
}
- signal(SIGUSR1, hide);
-
// We need a more complicated event loop than wayland's default.
- struct pollfd fds[2];
- fds[0].fd = STDIN_FILENO;
- fds[0].events = POLLIN;
- fds[1].fd = wl_display_get_fd(display);
- fds[1].events = POLLIN;
- // Initial dispatch so that bar appears (and can take events).
- wl_display_dispatch(display);
+ struct pollfd fds[3];
+ int WAYLAND_FD = 0;
+ int SIGNAL_FD = 1;
+ int STDIN_FD = 2;
+ fds[WAYLAND_FD].events = POLLIN;
+ fds[SIGNAL_FD].events = POLLIN;
+ fds[STDIN_FD].events = POLLIN;
+
+ fds[WAYLAND_FD].fd = wl_display_get_fd(display);
+ if (fds[WAYLAND_FD].fd == -1) {
+ die("Failed to get wayland_fd: %d\n", errno);
+ }
+
+ sigset_t signal_mask;
+ sigemptyset(&signal_mask);
+ sigaddset(&signal_mask, SIGUSR1);
+ sigaddset(&signal_mask, SIGUSR2);
+ sigaddset(&signal_mask, SIGRTMIN);
+ sigaddset(&signal_mask, SIGPIPE);
+ if (sigprocmask(SIG_BLOCK, &signal_mask, NULL) == -1) {
+ die("Failed to disable handled signals: %d\n", errno);
+ }
+ fds[SIGNAL_FD].fd = signalfd(-1, &signal_mask, 0);
+ if (fds[SIGNAL_FD].fd == -1) {
+ die("Failed to get signalfd: %d\n", errno);
+ }
+
+ fds[STDIN_FD].fd = STDIN_FILENO;
+
while (run_display) {
- while(layer_surface && poll(fds, 2, -1) != -1) {
- if (fds[0].revents & POLLIN) {
- handle_input(stdin, keyboard.suggs, &keyboard);
- } else if(fds[1].revents & POLLIN) {
- //error check?
- wl_display_dispatch(display);
- }
- wl_display_flush(display);
+ wl_display_flush(display);
+ poll(fds, 3, -1);
+ if (fds[STDIN_FD].revents & POLLIN) {
+ handle_input(stdin, keyboard.suggs, &keyboard);
}
- wl_display_roundtrip(display);
- while (run_display && !layer_surface) {
- // Hidden
- sleep(1);
+ if (fds[WAYLAND_FD].revents & POLLIN) {
+ wl_display_dispatch(display);
+ }
+ if (fds[WAYLAND_FD].revents & POLLERR) {
+ die("Exceptional condition on wayland socket.\n");
+ }
+ if (fds[WAYLAND_FD].revents & POLLHUP) {
+ die("Wayland socket has been disconnected.\n");
+ }
+
+ if (fds[SIGNAL_FD].revents & POLLIN) {
+ struct signalfd_siginfo si;
+
+ if (read(fds[SIGNAL_FD].fd, &si, sizeof(si)) != sizeof(si))
+ fprintf(stderr, "Signal read error: %d", errno);
+ else if (si.ssi_signo == SIGUSR1)
+ hide(0);
+ else if (si.ssi_signo == SIGUSR2)
+ show(0);
+ else if (si.ssi_signo == SIGRTMIN)
+ toggle_visibility(0);
+ else if (si.ssi_signo == SIGPIPE)
+ pipewarn(0);
}
}