suggestion picker: a persistent layer to complement virtual keyboards like wvkbd
Diffstat (limited to 'main.c')
-rw-r--r--main.c202
1 files changed, 117 insertions, 85 deletions
diff --git a/main.c b/main.c
index b05dd08..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,
@@ -141,18 +143,12 @@ void
wl_touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
uint32_t time, struct wl_surface *surface, int32_t id,
wl_fixed_t x, wl_fixed_t y) {
- struct key *next_key;
uint32_t touch_x, touch_y;
touch_x = wl_fixed_to_int(x);
touch_y = wl_fixed_to_int(y);
- kbd_unpress_key(&keyboard);
-
- next_key = kbd_get_key(&keyboard, touch_x, touch_y);
- if (next_key) {
- kbd_press_key(&keyboard, next_key);
- }
+ kbd_motion_key(&keyboard, touch_x, touch_y);
}
void
@@ -211,7 +207,6 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time,
void
wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
uint32_t time, uint32_t button, uint32_t state) {
- struct key *next_key;
cur_press = state == WL_POINTER_BUTTON_STATE_PRESSED;
if (cur_press) {
@@ -221,10 +216,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
}
if (cur_press && cur_x >= 0 && cur_y >= 0) {
- next_key = kbd_get_key(&keyboard, cur_x, cur_y);
- if (next_key) {
- kbd_press_key(&keyboard, next_key);
- }
+ kbd_motion_key(&keyboard, cur_x, cur_y);
}
}
@@ -248,19 +240,27 @@ static void
display_handle_geometry(void *data, struct wl_output *wl_output, int x, int y,
int physical_width, int physical_height, int subpixel,
const char *make, const char *model, int transform) {
- if (transform % 2 == 0 && keyboard.landscape) {
- keyboard.landscape = false;
- height = normal_height;
- } else if (transform % 2 != 0 && !keyboard.landscape) {
- keyboard.landscape = true;
+ // Swap width and height on rotated displays
+ if (transform % 2 != 0) {
+ int tmp = physical_width;
+ physical_width = physical_height;
+ physical_height = tmp;
+ }
+ bool landscape = physical_width > physical_height;
+ if (landscape == keyboard.landscape)
+ return;
+ keyboard.landscape = landscape;
+ if (keyboard.landscape) {
height = landscape_height;
} else {
- return; // no changes
+ 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
@@ -300,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);
-
}
}
@@ -310,11 +309,16 @@ 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) {
- keyboard.w = w;
- keyboard.h = h;
- kbd_resize(&keyboard);
+ 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);
+
+ drwsurf_flip(&draw_surf);
}
void
@@ -339,24 +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;
- if (draw_surf.cb) {
- wl_callback_destroy(draw_surf.cb);
- draw_surf.cb = 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;
}
@@ -374,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);
@@ -389,29 +402,35 @@ 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;
kbd_init_suggs(sugg, kb->w, kb->h);
kbd_draw_layout(kb);
+ drwsurf_flip(kb->surf);
}
free(line);
}
+void
+pipewarn(int sigint) {
+ fprintf(stderr, "suggpicker: cannot pipe data out.\n");
+}
+
int
main(int argc, char **argv) {
/* parse command line arguments */
@@ -422,21 +441,14 @@ 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"))) {
- printf("suggpicker-%s", VERSION);
+ printf("suggpicker-%s\n", VERSION);
exit(0);
} 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]);
@@ -455,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]);
@@ -494,49 +506,69 @@ main(int argc, char **argv) {
draw_ctx.font_description =
pango_font_description_from_string(fc_font_pattern);
- if (!starthidden) {
- draw_surf.surf = wl_compositor_create_surface(compositor);
-
- layer_surface = zwlr_layer_shell_v1_get_layer_surface(
- layer_shell, draw_surf.surf, wl_output, layer, namespace);
+ if (!hidden) {
+ show(0);
+ }
- zwlr_layer_surface_v1_set_size(layer_surface, 0, height);
- zwlr_layer_surface_v1_set_anchor(layer_surface, anchor);
- zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, height);
- zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface, false);
- zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener,
- NULL);
- wl_surface_commit(draw_surf.surf);
+ // We need a more complicated event loop than wayland's default.
+ 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);
+ }
- wl_display_roundtrip(display);
- drwsurf_flip(&draw_surf);
+ 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);
}
- signal(SIGUSR1, hide);
- signal(SIGUSR2, show);
+ fds[STDIN_FD].fd = STDIN_FILENO;
- // 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);
while (run_display) {
- while(layer_surface && poll(fds, 2, -1) != -1) {
- if (fds[0].revents & POLLIN) {
- handle_input(stdin, keyboard.suggs, &keyboard);
- }
- if (wl_display_dispatch(display) == -1) {
- break;
- }
- wl_display_flush(display);
+ wl_display_flush(display);
+ poll(fds, 3, -1);
+ if (fds[STDIN_FD].revents & POLLIN) {
+ handle_input(stdin, keyboard.suggs, &keyboard);
+ }
+ if (fds[WAYLAND_FD].revents & POLLIN) {
+ wl_display_dispatch(display);
}
- wl_display_roundtrip(display);
- while (run_display && !layer_surface) {
- // Hidden
- sleep(1);
+ 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);
}
}