From 3f5e21a83f525586d1ee5b1bcd04cc2e50350403 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 25 Oct 2014 01:38:30 +0300 Subject: Cleanup wayland renderer and plugin support. --- lib/renderers/wayland/wayland.c | 623 +++------------------------------------- 1 file changed, 35 insertions(+), 588 deletions(-) (limited to 'lib/renderers/wayland/wayland.c') diff --git a/lib/renderers/wayland/wayland.c b/lib/renderers/wayland/wayland.c index abc0d2e..289fa5a 100644 --- a/lib/renderers/wayland/wayland.c +++ b/lib/renderers/wayland/wayland.c @@ -1,575 +1,33 @@ -#define _DEFAULT_SOURCE #include "internal.h" +#include "version.h" +#include "wayland.h" #include #include #include #include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define MOD_SHIFT_MASK 0x01 -#define MOD_ALT_MASK 0x02 -#define MOD_CONTROL_MASK 0x04 - -struct xkb { - struct xkb_context *context; - struct xkb_keymap *keymap; - struct xkb_state *state; - xkb_mod_mask_t control_mask; - xkb_mod_mask_t alt_mask; - xkb_mod_mask_t shift_mask; - xkb_keysym_t sym; - uint32_t key; - uint32_t modifiers; -}; - -struct cairo { - cairo_t *cr; - cairo_surface_t *surface; -}; - -struct buffer { - struct cairo cairo; - struct wl_buffer *buffer; - int busy; -}; - -static struct wayland { - struct bm_menu *menu; - struct wl_display *display; - struct wl_registry *registry; - struct wl_compositor *compositor; - struct wl_surface *surface; - struct wl_shell_surface *shell_surface; - struct wl_seat *seat; - struct wl_keyboard *keyboard; - struct wl_shm *shm; -#if 0 - struct xdg_shell *shell; -#else - struct wl_shell *shell; -#endif - struct xkb xkb; - struct buffer buffers[2]; - uint32_t width, height; - uint32_t formats; -} wayland; - -// XXX: move to utils.c if reused -static char* -csprintf(const char *fmt, ...) -{ - assert(fmt); - - va_list args; - va_start(args, fmt); - size_t len = vsnprintf(NULL, 0, fmt, args) + 1; - va_end(args); - - char *buffer; - if (!(buffer = calloc(1, len))) - return NULL; - - va_start(args, fmt); - vsnprintf(buffer, len, fmt, args); - va_end(args); - return buffer; -} - -static int -set_cloexec_or_close(int fd) -{ - if (fd == -1) - return -1; - - long flags = fcntl(fd, F_GETFD); - if (flags == -1) - goto err; - - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) - goto err; - - return fd; - -err: - close(fd); - return -1; -} - -static int -create_tmpfile_cloexec(char *tmpname) -{ - int fd; - -#ifdef HAVE_MKOSTEMP - if ((fd = mkostemp(tmpname, O_CLOEXEC)) >= 0) - unlink(tmpname); -#else - if ((fd = mkstemp(tmpname)) >= 0) { - fd = set_cloexec_or_close(fd); - unlink(tmpname); - } -#endif - - return fd; -} - -static int -os_create_anonymous_file(off_t size) -{ - static const char template[] = "/bemenu-shared-XXXXXX"; - int fd; - int ret; - - const char *path; - if (!(path = getenv("XDG_RUNTIME_DIR")) || strlen(path) <= 0) { - errno = ENOENT; - return -1; - } - - char *name; - int ts = (path[strlen(path) - 1] == '/'); - if (!(name = csprintf("%s%s%s", path, (ts ? "" : "/"), template))) - return -1; - - fd = create_tmpfile_cloexec(name); - free(name); - - if (fd < 0) - return -1; - -#ifdef HAVE_POSIX_FALLOCATE - if ((ret = posix_fallocate(fd, 0, size)) != 0) { - close(fd); - errno = ret; - return -1; - } -#else - if ((ret = ftruncate(fd, size)) < 0) { - close(fd); - return -1; - } -#endif - - return fd; -} - -static void -buffer_release(void *data, struct wl_buffer *buffer) -{ - struct buffer *mybuf = data; - mybuf->busy = 0; -} - -static const struct wl_buffer_listener buffer_listener = { - buffer_release -}; - -static bool -create_shm_buffer(struct buffer *buffer, int32_t width, int32_t height, uint32_t format) -{ - uint32_t stride = width * 4; - uint32_t size = stride * height; - - int fd; - if ((fd = os_create_anonymous_file(size)) < 0) { - fprintf(stderr, "creating a buffer file for %d B failed: %m\n", size); - return false; - } - - void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) { - fprintf(stderr, "mmap failed: %m\n"); - close(fd); - return false; - } - - // FIXME: error handling - struct wl_shm_pool *pool = wl_shm_create_pool(wayland.shm, fd, size); - buffer->buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, format); - wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer); - wl_shm_pool_destroy(pool); - close(fd); - - buffer->cairo.surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, stride); - buffer->cairo.cr = cairo_create(buffer->cairo.surface); - return true; -} - -static struct buffer* -next_buffer(void) -{ - struct buffer *buffer; - - if (!wayland.buffers[0].busy) - buffer = &wayland.buffers[0]; - else if (!wayland.buffers[1].busy) - buffer = &wayland.buffers[1]; - else - return NULL; - - if (!buffer->buffer) { - if (!create_shm_buffer(buffer, wayland.width, wayland.height, WL_SHM_FORMAT_ARGB8888)) - return NULL; - } - - return buffer; -} - -static bool -resize_buffer(char **buffer, size_t *osize, size_t nsize) -{ - assert(buffer); - assert(osize); - - if (nsize == 0 || nsize <= *osize) - return false; - - void *tmp; - if (!*buffer || !(tmp = realloc(*buffer, nsize))) { - if (!(tmp = malloc(nsize))) - return 0; - - if (*buffer) { - memcpy(tmp, *buffer, *osize); - free(*buffer); - } - } - - *buffer = tmp; - *osize = nsize; - return true; -} - -#if __GNUC__ -__attribute__((format(printf, 5, 6))) -#endif -static int32_t -draw_line(struct cairo *c, int32_t pair, int32_t x, int32_t y, const char *format, ...) -{ - static size_t blen = 0; - static char *buffer = NULL; - - va_list args; - va_start(args, format); - size_t nlen = vsnprintf(NULL, 0, format, args); - va_end(args); - - if ((!buffer || nlen > blen) && !resize_buffer(&buffer, &blen, nlen + 1)) - return; - - va_start(args, format); - vsnprintf(buffer, blen, format, args); - va_end(args); - - cairo_text_extents_t te; - switch (pair) { - case 2: - cairo_set_source_rgb(c->cr, 1.0, 0.0, 0.0); - break; - case 1: - cairo_set_source_rgb(c->cr, 1.0, 0.0, 0.0); - break; - case 0: - cairo_set_source_rgb(c->cr, 1.0, 1.0, 1.0); - break; - }; - - cairo_select_font_face(c->cr, "Terminus", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(c->cr, 12); - cairo_text_extents(c->cr, buffer, &te); - cairo_move_to(c->cr, x, y * te.height + te.height); - cairo_show_text(c->cr, buffer); - return x + te.x_advance; -} - -static void -paint(struct cairo *c, int width, int height, uint32_t time) -{ - cairo_set_source_rgb(c->cr, 18.0f / 255.0f, 18 / 255.0f, 18.0f / 255.0f); - cairo_rectangle(c->cr, 0, 0, width, height); - cairo_fill(c->cr); - - struct bm_menu *menu = wayland.menu; - - int32_t x = 0; - if (menu->title) - x = draw_line(c, 1, x, 0, "%s ", menu->title); - if (menu->filter) - x = draw_line(c, 1, x, 0, "%s", menu->filter); - - uint32_t lines = height / 8; - uint32_t count, cl = 1; - struct bm_item **items = bm_menu_get_filtered_items(menu, &count); - for (uint32_t i = (menu->index / (lines - 1)) * (lines - 1); i < count && cl < lines; ++i) { - bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu)); - int32_t color = (highlighted ? 2 : (bm_menu_item_is_selected(menu, items[i]) ? 1 : 0)); - draw_line(c, color, 0, cl++, "%s%s", (highlighted ? ">> " : " "), (items[i]->text ? items[i]->text : "")); - } -} - -static void -redraw(void *data, uint32_t time) -{ - struct wayland *d = data; - struct buffer *buffer; - - if (!(buffer = next_buffer())) - return; - - paint(&buffer->cairo, d->width, d->height, time); - wl_surface_attach(d->surface, buffer->buffer, 0, 0); - wl_surface_commit(d->surface); - buffer->busy = 1; -} - -static void -shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) -{ - (void)wl_shm; - struct wayland *d = data; - d->formats |= (1 << format); -} - -struct wl_shm_listener shm_listener = { - .format = shm_format -}; - -#if 0 -static void -xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial) -{ - (void)data; - xdg_shell_pong(shell, serial); -} - -static const struct xdg_shell_listener xdg_shell_listener = { - xdg_shell_ping, -}; -#endif - -static void -keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) -{ - struct wayland *d = data; - - if (!data) { - close(fd); - return; - } - - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { - close(fd); - return; - } - - char *map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - if (map_str == MAP_FAILED) { - close(fd); - return; - } - - struct xkb_keymap *keymap = xkb_keymap_new_from_string(d->xkb.context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); - munmap(map_str, size); - close(fd); - - if (!keymap) { - fprintf(stderr, "failed to compile keymap\n"); - return; - } - - struct xkb_state *state = xkb_state_new(keymap); - if (!state) { - fprintf(stderr, "failed to create XKB state\n"); - xkb_keymap_unref(keymap); - return; - } - - xkb_keymap_unref(d->xkb.keymap); - xkb_state_unref(d->xkb.state); - d->xkb.keymap = keymap; - d->xkb.state = state; - d->xkb.control_mask = 1 << xkb_keymap_mod_get_index(d->xkb.keymap, "Control"); - d->xkb.alt_mask = 1 << xkb_keymap_mod_get_index(d->xkb.keymap, "Mod1"); - d->xkb.shift_mask = 1 << xkb_keymap_mod_get_index(d->xkb.keymap, "Shift"); -} - -static void -keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) -{ - (void)data, (void)keyboard, (void)serial, (void)surface, (void)keys; -} - -static void -keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) -{ - (void)data, (void)keyboard, (void)serial, (void)surface; -} - -static void -keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state_w) -{ - struct wayland *d = data; - enum wl_keyboard_key_state state = state_w; - - if (!d->xkb.state) - return; - - uint32_t code = key + 8; - xkb_keysym_t sym = xkb_state_key_get_one_sym(d->xkb.state, code); - - d->xkb.key = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? code : 0); - d->xkb.sym = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? sym : XKB_KEY_NoSymbol); - -#if 0 - if (state == WL_KEYBOARD_KEY_STATE_RELEASED && - key == input->repeat_key) { - its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 0; - its.it_value.tv_sec = 0; - its.it_value.tv_nsec = 0; - timerfd_settime(input->repeat_timer_fd, 0, &its, NULL); - } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED && - xkb_keymap_key_repeats(input->xkb.keymap, code)) { - input->repeat_sym = sym; - input->repeat_key = key; - input->repeat_time = time; - its.it_interval.tv_sec = input->repeat_rate_sec; - its.it_interval.tv_nsec = input->repeat_rate_nsec; - its.it_value.tv_sec = input->repeat_delay_sec; - its.it_value.tv_nsec = input->repeat_delay_nsec; - timerfd_settime(input->repeat_timer_fd, 0, &its, NULL); - } -#endif -} - -static void -keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) -{ - (void)keyboard, (void)serial; - struct wayland *d = data; - - if (!d->xkb.keymap) - return; - - xkb_state_update_mask(d->xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); - xkb_mod_mask_t mask = xkb_state_serialize_mods(d->xkb.state, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED); - - d->xkb.modifiers = 0; - if (mask & d->xkb.control_mask) - d->xkb.modifiers |= MOD_CONTROL_MASK; - if (mask & d->xkb.alt_mask) - d->xkb.modifiers |= MOD_ALT_MASK; - if (mask & d->xkb.shift_mask) - d->xkb.modifiers |= MOD_SHIFT_MASK; -} - -static void -keyboard_handle_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay) -{ - (void)data, (void)keyboard, (void)rate, (void)delay; -} - -static const struct wl_keyboard_listener keyboard_listener = { - .keymap = keyboard_handle_keymap, - .enter = keyboard_handle_enter, - .leave = keyboard_handle_leave, - .key = keyboard_handle_key, - .modifiers = keyboard_handle_modifiers, - .repeat_info = keyboard_handle_repeat_info -}; - -static void -seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps) -{ - struct wayland *d = data; - - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !d->keyboard) { - d->keyboard = wl_seat_get_keyboard(seat); - wl_keyboard_add_listener(d->keyboard, &keyboard_listener, data); - } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && d->keyboard) { - wl_keyboard_destroy(d->keyboard); - d->keyboard = NULL; - } -} - -static void -seat_handle_name(void *data, struct wl_seat *seat, const char *name) -{ - (void)data, (void)seat, (void)name; -} - -static const struct wl_seat_listener seat_listener = { - seat_handle_capabilities, - seat_handle_name -}; - -static void -registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) -{ - (void)version; - struct wayland *d = data; - - if (strcmp(interface, "wl_compositor") == 0) { - d->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1); -#if 0 - } else if (strcmp(interface, "xdg_shell") == 0) { - d->shell = wl_registry_bind(registry, id, &xdg_shell_interface, 1); - xdg_shell_use_unstable_version(d->shell, XDG_VERSION); - xdg_shell_add_listener(d->shell, &xdg_shell_listener, d); -#else - } else if (strcmp(interface, "wl_shell") == 0) { - d->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1); -#endif - } else if (strcmp(interface, "wl_seat") == 0) { - d->seat = wl_registry_bind(registry, id, &wl_seat_interface, 4); - wl_seat_add_listener(d->seat, &seat_listener, d); - } else if (strcmp(interface, "wl_shm") == 0) { - d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); - wl_shm_add_listener(d->shm, &shm_listener, d); - } -} - -static void -registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) -{ - (void)data, (void)registry, (void)name; -} - -static const struct wl_registry_listener registry_listener = { - registry_handle_global, - registry_handle_global_remove -}; static void render(const struct bm_menu *menu) { - (void)menu; - redraw(&wayland, 0); - wl_display_dispatch(wayland.display); + struct wayland *wayland = menu->renderer->internal; + bm_wl_window_render(&wayland->window, menu); + wl_display_dispatch(wayland->display); } static enum bm_key poll_key(const struct bm_menu *menu, unsigned int *unicode) { - (void)menu; - assert(unicode); + struct wayland *wayland = menu->renderer->internal; + assert(wayland && unicode); *unicode = 0; - if (wayland.xkb.sym == XKB_KEY_NoSymbol) + if (wayland->input.sym == XKB_KEY_NoSymbol) return BM_KEY_UNICODE; - *unicode = xkb_state_key_get_utf32(wayland.xkb.state, wayland.xkb.key); + *unicode = xkb_state_key_get_utf32(wayland->input.xkb.state, wayland->input.code); - switch (wayland.xkb.sym) { + switch (wayland->input.sym) { case XKB_KEY_Up: return BM_KEY_UP; @@ -621,68 +79,55 @@ poll_key(const struct bm_menu *menu, unsigned int *unicode) static uint32_t get_displayed_count(const struct bm_menu *menu) { - (void)menu; - return wayland.height / 8; + struct wayland *wayland = menu->renderer->internal; + assert(wayland); + return wayland->window.height / 12; } static void destructor(struct bm_menu *menu) { - (void)menu; - - if (wayland.shm) - wl_shm_destroy(wayland.shm); + struct wayland *wayland = menu->renderer->internal; -#if 0 - if (wayland.shell) - xdg_shell_destroy(wayland.shell); -#endif - - if (wayland.compositor) - wl_compositor_destroy(wayland.compositor); + if (!wayland) + return; - if (wayland.registry) - wl_registry_destroy(wayland.registry); + bm_wl_window_destroy(&wayland->window); + bm_wl_registry_destroy(wayland); - if (wayland.display) { - wl_display_flush(wayland.display); - wl_display_disconnect(wayland.display); + if (wayland->display) { + wl_display_flush(wayland->display); + wl_display_disconnect(wayland->display); } + + free(wayland); + menu->renderer->internal = NULL; } static bool constructor(struct bm_menu *menu) { - (void)menu; - memset(&wayland, 0, sizeof(wayland)); - - if (!(wayland.display = wl_display_connect(NULL))) + struct wayland *wayland; + if (!(menu->renderer->internal = wayland = calloc(1, sizeof(struct wayland)))) goto fail; - if (!(wayland.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS))) + if (!(wayland->display = wl_display_connect(NULL))) goto fail; - wayland.width = 800; - wayland.height = 480; - - wayland.registry = wl_display_get_registry(wayland.display); - wl_registry_add_listener(wayland.registry, ®istry_listener, &wayland); - wl_display_roundtrip(wayland.display); // shm bind - if (!wayland.shm) + if (!(wayland->input.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS))) goto fail; - wl_display_roundtrip(wayland.display); // shm formats - if (!(wayland.formats & (1 << WL_SHM_FORMAT_ARGB8888))) + if (!bm_wl_registry_register(wayland)) goto fail; - if (!(wayland.surface = wl_compositor_create_surface(wayland.compositor))) + struct wl_surface *surface; + if (!(surface = wl_compositor_create_surface(wayland->compositor))) goto fail; - if (!(wayland.shell_surface = wl_shell_get_shell_surface(wayland.shell, wayland.surface))) + if (!bm_wl_window_create(&wayland->window, wayland->shm, wayland->shell, wayland->xdg_shell, surface)) goto fail; - wayland.menu = menu; - wl_surface_damage(wayland.surface, 0, 0, wayland.width, wayland.height); + wayland->window.notify.render = bm_cairo_paint; return true; fail: @@ -698,6 +143,8 @@ register_renderer(struct render_api *api) api->get_displayed_count = get_displayed_count; api->poll_key = poll_key; api->render = render; + api->prioritory = BM_PRIO_GUI; + api->version = BM_VERSION; return "wayland"; } -- cgit v1.2.3-70-g09d2