suggestion picker: a persistent layer to complement virtual keyboards like wvkbd
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 11 | ||||
| -rw-r--r-- | README.md | 6 | ||||
| -rw-r--r-- | config.mk | 2 | ||||
| -rw-r--r-- | drw.c | 18 | ||||
| -rw-r--r-- | drw.h | 1 | ||||
| -rw-r--r-- | keyboard.c | 36 | ||||
| -rw-r--r-- | main.c | 202 | ||||
| -rw-r--r-- | os-compatibility.c | 201 | ||||
| -rw-r--r-- | os-compatibility.h | 52 | ||||
| -rw-r--r-- | suggpicker.1.scd | 21 |
11 files changed, 176 insertions, 375 deletions
@@ -5,3 +5,4 @@ .gdb_history *.log suggpicker +suggpicker.1 @@ -2,10 +2,12 @@ include config.mk NAME=suggpicker BIN=${NAME} +MAN=${NAME}.1 SRC=. -PKGS = wayland-client xkbcommon pangocairo +PKGS = wayland-client pangocairo +PREFIX?=/usr/local MY_SOURCES += $(wildcard $(SRC)/*.c) MY_HEADERS += $(wildcard $(SRC)/*.h) @@ -21,7 +23,7 @@ SOURCES = $(MY_SOURCES) $(WAYLAND_SRC) OBJECTS = $(SOURCES:.c=.o) -all: ${BIN} +all: ${BIN} ${MAN} proto/%-client-protocol.c: proto/%.xml wayland-scanner code < $? > $@ @@ -34,6 +36,9 @@ $(OBJECTS): $(HDRS) $(MY_HEADERS) ${BIN}: config.h $(OBJECTS) $(CC) -o ${BIN} $(OBJECTS) $(LDFLAGS) +${MAN}: ${MAN}.scd + scdoc < $? > $@ + clean: rm -f $(OBJECTS) $(HDRS) $(WAYLAND_SRC) ${BIN} @@ -44,3 +49,5 @@ install: all mkdir -p ${DESTDIR}${PREFIX}/bin cp -f ${BIN} ${DESTDIR}${PREFIX}/bin chmod 755 ${DESTDIR}${PREFIX}/bin/${BIN} + mkdir -p ${DESTDIR}${PREFIX}/share/man/man1 + cp -f ${MAN} ${DESTDIR}${PREFIX}/share/man/man1 @@ -13,15 +13,15 @@ Each line of input is treated as TSV. You'll need the following developer packages - - pangocairo + - cairo + - pango - wayland-client - - xkbcommon 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 @@ -1,2 +1,2 @@ -VERSION = 0.0.1 +VERSION = 0.1.4 CFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=700 @@ -20,31 +20,13 @@ drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, uint32_t s) { setup_buffer(ds); } -static void surface_frame_callback(void *data, struct wl_callback *cb, - uint32_t time); - -static struct wl_callback_listener frame_listener = {.done = - surface_frame_callback}; - void drwsurf_flip(struct drwsurf *ds) { - ds->cb = wl_surface_frame(ds->surf); - wl_callback_add_listener(ds->cb, &frame_listener, (void *)ds); - wl_surface_attach(ds->surf, ds->buf, 0, 0); wl_surface_commit(ds->surf); } void -surface_frame_callback(void *data, struct wl_callback *cb, uint32_t time) { - struct drwsurf *ds = (struct drwsurf *)data; - wl_callback_destroy(cb); - ds->cb = NULL; - - drwsurf_flip(ds); -} - -void drw_draw_text(struct drwsurf *d, Color color, uint32_t x, uint32_t y, uint32_t w, uint32_t h, const char *label) { @@ -15,7 +15,6 @@ struct drwsurf { struct wl_surface *surf; struct wl_buffer *buf; struct wl_shm *shm; - struct wl_callback *cb; unsigned char *pool_data; cairo_t *cairo; @@ -2,7 +2,6 @@ #include <sys/mman.h> #include "keyboard.h" #include "drw.h" -#include "os-compatibility.h" #define KBD_KEY_BORDER 1 @@ -15,9 +14,9 @@ void kbd_init(struct kbd *kb) { fprintf(stderr, "Initializing keyboard\n"); - kb->suggs[0].label = strdup("Hello"); - kb->suggs[1].label = strdup("Sugar"); - kb->suggs[2].label = strdup("Pie"); + kb->suggs[0].label = strdup("Hey"); + kb->suggs[1].label = strdup("Honey"); + kb->suggs[2].label = strdup("Bunches"); kb->suggs[3].label = NULL; } @@ -30,11 +29,16 @@ kbd_init_suggs(struct key *suggs, uint32_t width, uint32_t height) { struct key *k = suggs; double rowlength = kbd_get_row_length(k); + uint8_t i = 0; while (k->label != NULL) { k->x = x; k->y = y; k->w = width / rowlength; x += k->w; + i++; + if (x < (width * i) / rowlength) { + k->w++; x++; + } k->h = keyheight; k++; } @@ -69,21 +73,30 @@ kbd_unpress_key(struct kbd *kb) { if (kb->last_press) { kbd_draw_key(kb, kb->last_press, Unpress); kb->last_press = NULL; + drwsurf_flip(kb->surf); } } void kbd_release_key(struct kbd *kb) { - kbd_unpress_key(kb); - printf("\n"); - // Important so autocompleted words get typed in time - fflush(stdout); - kbd_draw_layout(kb); + if (kb->last_press) { + printf("%s\n", kb->last_press->label); + // Important so autocompleted words get typed in time + fflush(stdout); + kbd_unpress_key(kb); + } } void kbd_motion_key(struct kbd *kb, uint32_t x, uint32_t y) { - + struct key *next_key; + next_key = kbd_get_key(kb, x, y); + if (next_key != kb->last_press) { + kbd_unpress_key(kb); + if (next_key) { + kbd_press_key(kb, next_key); + } + } } void @@ -91,8 +104,7 @@ kbd_press_key(struct kbd *kb, struct key *k) { if (k->label) { kb->last_press = k; kbd_draw_key(kb, k, Press); - printf("%s", k->label); - fflush(stdout); + drwsurf_flip(kb->surf); } } @@ -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); } } diff --git a/os-compatibility.c b/os-compatibility.c deleted file mode 100644 index 93f744b..0000000 --- a/os-compatibility.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright © 2012 Collabora, Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include <errno.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> -#include <sys/epoll.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -#include "os-compatibility.h" - -int -os_fd_set_cloexec(int fd) { - long flags; - - if (fd == -1) - return -1; - - flags = fcntl(fd, F_GETFD); - if (flags == -1) - return -1; - - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) - return -1; - - return 0; -} - -static int -set_cloexec_or_close(int fd) { - if (os_fd_set_cloexec(fd) != 0) { - close(fd); - return -1; - } - return fd; -} - -int -os_socketpair_cloexec(int domain, int type, int protocol, int *sv) { - int ret; - -#ifdef SOCK_CLOEXEC - ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv); - if (ret == 0 || errno != EINVAL) - return ret; -#endif - - ret = socketpair(domain, type, protocol, sv); - if (ret < 0) - return ret; - - sv[0] = set_cloexec_or_close(sv[0]); - sv[1] = set_cloexec_or_close(sv[1]); - - if (sv[0] != -1 && sv[1] != -1) - return 0; - - close(sv[0]); - close(sv[1]); - return -1; -} - -int -os_epoll_create_cloexec(void) { - int fd; - -#ifdef EPOLL_CLOEXEC - fd = epoll_create1(EPOLL_CLOEXEC); - if (fd >= 0) - return fd; - if (errno != EINVAL) - return -1; -#endif - - fd = epoll_create(1); - return set_cloexec_or_close(fd); -} - -static int -create_tmpfile_cloexec(char *tmpname) { - int fd; - -#ifdef HAVE_MKOSTEMP - fd = mkostemp(tmpname, O_CLOEXEC); - if (fd >= 0) - unlink(tmpname); -#else - fd = mkstemp(tmpname); - if (fd >= 0) { - fd = set_cloexec_or_close(fd); - unlink(tmpname); - } -#endif - - return fd; -} - -/* - * Create a new, unique, anonymous file of the given size, and - * return the file descriptor for it. The file descriptor is set - * CLOEXEC. The file is immediately suitable for mmap()'ing - * the given size at offset zero. - * - * The file should not have a permanent backing store like a disk, - * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. - * - * The file name is deleted from the file system. - * - * The file is suitable for buffer sharing between processes by - * transmitting the file descriptor over Unix sockets using the - * SCM_RIGHTS methods. - * - * If the C library implements posix_fallocate(), it is used to - * guarantee that disk space is available for the file at the - * given size. If disk space is insufficient, errno is set to ENOSPC. - * If posix_fallocate() is not supported, program may receive - * SIGBUS on accessing mmap()'ed file contents instead. - */ -int -os_create_anonymous_file(off_t size) { - static const char template[] = "/weston-shared-XXXXXX"; - const char *path; - char *name; - int fd; - int ret; - - path = getenv("XDG_RUNTIME_DIR"); - if (!path) { - errno = ENOENT; - return -1; - } - - name = malloc(strlen(path) + sizeof(template)); - if (!name) - return -1; - - strcpy(name, path); - strcat(name, template); - - fd = create_tmpfile_cloexec(name); - - free(name); - - if (fd < 0) - return -1; - -#ifdef HAVE_POSIX_FALLOCATE - do { - ret = posix_fallocate(fd, 0, size); - } while (ret == EINTR); - if (ret != 0) { - close(fd); - errno = ret; - return -1; - } -#else - do { - ret = ftruncate(fd, size); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - close(fd); - return -1; - } -#endif - - return fd; -} - -#ifndef MISSING_STRCHRNUL -char * -strchrnul(const char *s, int c) { - while (*s && *s != c) - s++; - return (char *)s; -} -#endif diff --git a/os-compatibility.h b/os-compatibility.h deleted file mode 100644 index 80e7627..0000000 --- a/os-compatibility.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © 2012 Collabora, Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef OS_COMPATIBILITY_H -#define OS_COMPATIBILITY_H - -#include <sys/types.h> - -#ifdef HAVE_EXECINFO_H -#include <execinfo.h> -#else -static inline int -backtrace(void **buffer, int size) { - return 0; -} -#endif - -int os_fd_set_cloexec(int fd); - -int os_socketpair_cloexec(int domain, int type, int protocol, int *sv); - -int os_epoll_create_cloexec(void); - -int os_create_anonymous_file(off_t size); - -#ifdef MISSING_STRCHRNUL -char *strchrnul(const char *s, int c); -#endif - -#endif /* OS_COMPATIBILITY_H */ diff --git a/suggpicker.1.scd b/suggpicker.1.scd new file mode 100644 index 0000000..9800255 --- /dev/null +++ b/suggpicker.1.scd @@ -0,0 +1,21 @@ +suggpicker(1) + +# NAME +suggpicker - floating bar for making decisions + +# SYNOPSIS + +suggpicker < choices.sock > selection.sock + +wvkbd -O | swipeGuess words.txt 5 | *suggpicker* | completelyTypeWord.sh + +# DESCRIPTION + +*suggpicker* is a persistent dynamic menu for Wayland. + +Each line of tab-separated choices it reads changes the choices on the bar. Choices which are clicked or tapped will be outputted into stdout, so it can be processed by another program. + +It's made to be used in conjunction with a virtual keyboard, which it will float above or below. + +# SEE ALSO +*bemenu*(1) *swipeGuess*(1) *wvkbd*(1) *SwipeBehavior*(7) |