suggestion picker: a persistent layer to complement virtual keyboards like wvkbd
Diffstat (limited to 'main.c')
| -rw-r--r-- | main.c | 169 |
1 files changed, 111 insertions, 58 deletions
@@ -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, @@ -238,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 @@ -290,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); - } } @@ -300,13 +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) { - 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); + + drwsurf_flip(&draw_surf); } void @@ -331,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; } @@ -366,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); @@ -381,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 */ @@ -414,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"))) { @@ -424,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]); @@ -447,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]); @@ -486,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); - } - 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); + } + if (fds[WAYLAND_FD].revents & POLLERR) { + die("Exceptional condition on wayland socket.\n"); } - wl_display_roundtrip(display); - while (run_display && !layer_surface) { - // Hidden - sleep(1); + 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); } } |