summaryrefslogtreecommitdiff
path: root/lib/renderers/wayland/wayland.c
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2014-10-25 01:38:30 +0300
committerJari Vetoniemi <mailroxas@gmail.com>2014-10-25 01:38:30 +0300
commit3f5e21a83f525586d1ee5b1bcd04cc2e50350403 (patch)
tree226cb57348ae89bc62df34cfd7ee2afe43f03c45 /lib/renderers/wayland/wayland.c
parentf8d97efb8f1bc5a7e764e1bb14f0e97ac36de68d (diff)
downloadbemenu-3f5e21a83f525586d1ee5b1bcd04cc2e50350403.tar.gz
bemenu-3f5e21a83f525586d1ee5b1bcd04cc2e50350403.tar.bz2
bemenu-3f5e21a83f525586d1ee5b1bcd04cc2e50350403.zip
Cleanup wayland renderer and plugin support.
Diffstat (limited to 'lib/renderers/wayland/wayland.c')
-rw-r--r--lib/renderers/wayland/wayland.c623
1 files changed, 35 insertions, 588 deletions
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 <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#include <wayland-client.h>
-#include <xkbcommon/xkbcommon.h>
-#include <cairo/cairo.h>
-
-#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, &registry_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";
}