Separate menu state from Wayland state

This commit is contained in:
adnano 2024-05-02 17:03:07 -04:00
parent 6a39269d2e
commit 6284eea24b
7 changed files with 577 additions and 508 deletions

179
menu.c
View file

@ -1,5 +1,4 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <ctype.h>
#include <poll.h>
#include <stdbool.h>
@ -19,10 +18,8 @@
#include "menu.h"
#include "pango.h"
#include "pool-buffer.h"
#include "render.h"
#include "xdg-activation-v1-client-protocol.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#include "wayland.h"
// Creates and returns a new menu.
struct menu *menu_create() {
@ -38,38 +35,6 @@ struct menu *menu_create() {
return menu;
}
// Creates and returns a new keyboard.
struct keyboard *keyboard_create(struct menu *menu, struct wl_keyboard *wl_keyboard) {
struct keyboard *keyboard = calloc(1, sizeof(struct keyboard));
keyboard->menu = menu;
keyboard->keyboard = wl_keyboard;
keyboard->context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
assert(keyboard->context != NULL);
keyboard->repeat_timer = timerfd_create(CLOCK_MONOTONIC, 0);
assert(keyboard->repeat_timer != -1);
return keyboard;
}
// Sets the current keyboard.
void menu_set_keyboard(struct menu *menu, struct keyboard *keyboard) {
menu->keyboard = keyboard;
}
// Creates and returns a new output.
struct output *output_create(struct menu *menu, struct wl_output *wl_output) {
struct output *output = calloc(1, sizeof(struct output));
output->menu = menu;
output->output = wl_output;
output->scale = 1;
return output;
}
// Adds an output to the output list.
void menu_add_output(struct menu *menu, struct output *output) {
output->next = menu->output_list;
menu->output_list = output;
}
static bool parse_color(const char *color, uint32_t *result) {
if (color[0] == '#') {
++color;
@ -170,6 +135,22 @@ void menu_getopts(struct menu *menu, int argc, char *argv[]) {
menu->padding = height / 2;
}
// Add an item to the menu.
void menu_add_item(struct menu *menu, char *text) {
struct item *item = calloc(1, sizeof *item);
if (!item) {
return;
}
item->text = text;
if (menu->lastitem) {
menu->lastitem->next = item;
} else {
menu->items = item;
}
menu->lastitem = item;
}
static void append_page(struct page *page, struct page **first, struct page **last) {
if (*last) {
(*last)->next = page;
@ -246,7 +227,7 @@ static const char *fstrstr(struct menu *menu, const char *s, const char *sub) {
return NULL;
}
static void append_item(struct item *item, struct item **first, struct item **last) {
static void append_match(struct item *item, struct item **first, struct item **last) {
if (*last) {
(*last)->next_match = item;
} else {
@ -300,11 +281,11 @@ static void match_items(struct menu *menu) {
continue;
}
if (!tokc || !menu->strncmp(menu->input, item->text, input_len + 1)) {
append_item(item, &lexact, &exactend);
append_match(item, &lexact, &exactend);
} else if (!menu->strncmp(tokv[0], item->text, tok_len)) {
append_item(item, &lprefix, &prefixend);
append_match(item, &lprefix, &prefixend);
} else {
append_item(item, &lsubstr, &substrend);
append_match(item, &lsubstr, &substrend);
}
}
@ -339,45 +320,27 @@ static void match_items(struct menu *menu) {
}
}
// Read menu items from standard input.
void read_menu_items(struct menu *menu) {
if (menu->passwd) {
// Don't read standard input in password mode
calc_widths(menu);
return;
}
char buf[sizeof menu->input];
struct item **next = &menu->items;
while (fgets(buf, sizeof buf, stdin)) {
char *p = strchr(buf, '\n');
if (p) {
*p = '\0';
}
struct item *item = calloc(1, sizeof *item);
if (!item) {
return;
}
item->text = strdup(buf);
*next = item;
next = &item->next;
}
// Process menu items.
void menu_process_items(struct menu *menu) {
calc_widths(menu);
match_items(menu);
}
static void insert(struct menu *menu, const char *s, ssize_t n) {
if (strlen(menu->input) + n > sizeof menu->input - 1) {
static void insert(struct menu *menu, const char *text, ssize_t len) {
if (strlen(menu->input) + len > sizeof menu->input - 1) {
return;
}
memmove(menu->input + menu->cursor + n, menu->input + menu->cursor,
sizeof menu->input - menu->cursor - MAX(n, 0));
if (n > 0 && s != NULL) {
memcpy(menu->input + menu->cursor, s, n);
memmove(menu->input + menu->cursor + len, menu->input + menu->cursor,
sizeof menu->input - menu->cursor - MAX(len, 0));
if (len > 0 && text != NULL) {
memcpy(menu->input + menu->cursor, text, len);
}
menu->cursor += n;
menu->cursor += len;
}
// Add pasted text to the menu input.
void menu_paste(struct menu *menu, const char *text, ssize_t len) {
insert(menu, text, len);
}
static size_t nextrune(struct menu *menu, int incr) {
@ -417,14 +380,12 @@ void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
return;
}
bool ctrl = xkb_state_mod_name_is_active(menu->keyboard->state,
XKB_MOD_NAME_CTRL,
struct xkb_state *state = context_get_xkb_state(menu->context);
bool ctrl = xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL,
XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
bool meta = xkb_state_mod_name_is_active(menu->keyboard->state,
XKB_MOD_NAME_ALT,
bool meta = xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT,
XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
bool shift = xkb_state_mod_name_is_active(menu->keyboard->state,
XKB_MOD_NAME_SHIFT,
bool shift = xkb_state_mod_name_is_active(state, XKB_MOD_NAME_SHIFT,
XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
size_t len = strlen(menu->input);
@ -501,32 +462,9 @@ void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
return;
case XKB_KEY_Y:
// Paste clipboard
if (!menu->data_offer) {
if (!context_paste(menu->context)) {
return;
}
int fds[2];
if (pipe(fds) == -1) {
// Pipe failed
return;
}
wl_data_offer_receive(menu->data_offer, "text/plain", fds[1]);
close(fds[1]);
wl_display_roundtrip(menu->display);
while (true) {
char buf[1024];
ssize_t n = read(fds[0], buf, sizeof(buf));
if (n <= 0) {
break;
}
insert(menu, buf, n);
}
close(fds[0]);
wl_data_offer_destroy(menu->data_offer);
menu->data_offer = NULL;
match_items(menu);
render_menu(menu);
return;
@ -696,26 +634,6 @@ void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
}
}
// Frees the keyboard.
static void free_keyboard(struct keyboard *keyboard) {
wl_keyboard_release(keyboard->keyboard);
xkb_state_unref(keyboard->state);
xkb_keymap_unref(keyboard->keymap);
xkb_context_unref(keyboard->context);
free(keyboard);
}
// Frees the outputs.
static void free_outputs(struct menu *menu) {
struct output *next = menu->output_list;
while (next) {
struct output *output = next;
next = output->next;
wl_output_destroy(output->output);
free(output);
}
}
// Frees menu pages.
static void free_pages(struct menu *menu) {
struct page *next = menu->pages;
@ -739,26 +657,9 @@ static void free_items(struct menu *menu) {
// Destroys the menu, freeing memory associated with it.
void menu_destroy(struct menu *menu) {
wl_registry_destroy(menu->registry);
wl_compositor_destroy(menu->compositor);
wl_shm_destroy(menu->shm);
wl_seat_destroy(menu->seat);
wl_data_device_manager_destroy(menu->data_device_manager);
zwlr_layer_shell_v1_destroy(menu->layer_shell);
free_outputs(menu);
free_keyboard(menu->keyboard);
wl_data_device_destroy(menu->data_device);
wl_surface_destroy(menu->surface);
zwlr_layer_surface_v1_destroy(menu->layer_surface);
xdg_activation_v1_destroy(menu->activation);
free_pages(menu);
free_items(menu);
destroy_buffer(&menu->buffers[0]);
destroy_buffer(&menu->buffers[1]);
wl_display_disconnect(menu->display);
free(menu);
}