forked from RepoMirrors/bemenu
After the changes of the previous commit, the event loop flow on Wayland is: 1. Render windows if window->render_pending is set 2. Wait for events [NOTE: this includes the frame callback] 3. Schedule render if menu->dirty is set 4. Handle events (return from render) and repeat This can still miss renders since the menu->dirty flag is set in step (4), but the menu->dirty flag is checked in step (3). So if the event loop only does a single iteration (quite unusual as most user actions cause multiple events), we can get stuck on step (2) for a while. In order to avoid this problem, this changes the event loop order to: 1. Schedule render if menu->dirty is set 2. Wait for events [NOTE: this includes the frame callback] 3. Render windows if window->render_pending is set 4. Handle events (return from render) and repeat Script (for Sway) to reproduce the issue / verify the fix: #!/usr/bin/env sh mousesety() { swaymsg seat - cursor set 200 "$1" >/dev/null; sleep 0.2; } { while true; do mousesety 200; mousesety 300; mousesety 400; done } & trap 'kill $!' EXIT export BEMENU_BACKEND=wayland BEMENU_OPTS='--list 40 --hb #0000FF' yes | head -30 | bemenu Fixes: #274 Fixes: #275
607 lines
18 KiB
C
607 lines
18 KiB
C
#include "internal.h"
|
|
#include "wayland.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
#include <sys/epoll.h>
|
|
#include <sys/timerfd.h>
|
|
|
|
static int efd;
|
|
|
|
static void
|
|
render_windows_if_pending(const struct bm_menu *menu, struct wayland *wayland) {
|
|
struct window *window;
|
|
wl_list_for_each(window, &wayland->windows, link) {
|
|
if (window->render_pending)
|
|
bm_wl_window_render(window, wayland->display, menu);
|
|
}
|
|
wl_display_flush(wayland->display);
|
|
}
|
|
|
|
static void
|
|
wait_for_events(struct wayland *wayland) {
|
|
wl_display_dispatch_pending(wayland->display);
|
|
|
|
if (wl_display_flush(wayland->display) < 0 && errno != EAGAIN) {
|
|
wayland->input.sym = XKB_KEY_Escape;
|
|
return;
|
|
}
|
|
|
|
struct epoll_event ep[16];
|
|
uint32_t num = epoll_wait(efd, ep, 16, -1);
|
|
for (uint32_t i = 0; i < num; ++i) {
|
|
if (ep[i].data.ptr == &wayland->fds.display) {
|
|
if (ep[i].events & EPOLLERR || ep[i].events & EPOLLHUP ||
|
|
((ep[i].events & EPOLLIN) && wl_display_dispatch(wayland->display) < 0))
|
|
wayland->input.sym = XKB_KEY_Escape;
|
|
} else if (ep[i].data.ptr == &wayland->fds.repeat) {
|
|
bm_wl_repeat(wayland);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
schedule_windows_render_if_dirty(struct bm_menu *menu, struct wayland *wayland) {
|
|
struct window *window;
|
|
wl_list_for_each(window, &wayland->windows, link) {
|
|
if (window->render_pending) {
|
|
// This does not happen during normal execution, but only when the windows need to
|
|
// be(re)created. We need to do the render ASAP (not schedule it) because otherwise,
|
|
// since we lack a window, we may not receive further events and will get deadlocked
|
|
render_windows_if_pending(menu, wayland);
|
|
} else if (menu->dirty) {
|
|
bm_wl_window_schedule_render(window);
|
|
}
|
|
}
|
|
|
|
menu->dirty = false;
|
|
}
|
|
|
|
static void
|
|
render(struct bm_menu *menu)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
|
|
schedule_windows_render_if_dirty(menu, wayland);
|
|
wait_for_events(wayland);
|
|
render_windows_if_pending(menu, wayland);
|
|
}
|
|
|
|
static enum bm_key
|
|
poll_key(const struct bm_menu *menu, unsigned int *unicode)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
assert(wayland && unicode);
|
|
*unicode = 0;
|
|
|
|
if (wayland->input.sym == XKB_KEY_NoSymbol)
|
|
return BM_KEY_NONE;
|
|
|
|
xkb_keysym_t sym = wayland->input.sym;
|
|
uint32_t mods = wayland->input.modifiers;
|
|
*unicode = xkb_state_key_get_utf32(wayland->input.xkb.state, wayland->input.code);
|
|
|
|
if (!*unicode && wayland->input.code == 23 && (mods & MOD_SHIFT))
|
|
return BM_KEY_SHIFT_TAB;
|
|
|
|
wayland->input.sym = XKB_KEY_NoSymbol;
|
|
wayland->input.code = 0;
|
|
|
|
if (!wayland->input.key_pending)
|
|
return BM_KEY_UNICODE;
|
|
wayland->input.key_pending = false;
|
|
|
|
switch (sym) {
|
|
case XKB_KEY_Up:
|
|
return BM_KEY_UP;
|
|
|
|
case XKB_KEY_Down:
|
|
return BM_KEY_DOWN;
|
|
|
|
case XKB_KEY_Left:
|
|
return (mods & MOD_SHIFT ? BM_KEY_UP : BM_KEY_LEFT);
|
|
|
|
case XKB_KEY_Right:
|
|
return (mods & MOD_SHIFT ? BM_KEY_DOWN : BM_KEY_RIGHT);
|
|
|
|
case XKB_KEY_Home:
|
|
return BM_KEY_HOME;
|
|
|
|
case XKB_KEY_End:
|
|
return BM_KEY_END;
|
|
|
|
case XKB_KEY_SunPageUp:
|
|
return (mods & MOD_SHIFT ? BM_KEY_SHIFT_PAGE_UP : BM_KEY_PAGE_UP);
|
|
|
|
case XKB_KEY_less:
|
|
return (mods & MOD_ALT ? BM_KEY_SHIFT_PAGE_UP : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_SunPageDown:
|
|
return (mods & MOD_SHIFT ? BM_KEY_SHIFT_PAGE_DOWN : BM_KEY_PAGE_DOWN);
|
|
|
|
case XKB_KEY_greater:
|
|
return (mods & MOD_ALT ? BM_KEY_SHIFT_PAGE_DOWN : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_v:
|
|
return (mods & MOD_CTRL ? BM_KEY_PAGE_DOWN : (mods & MOD_ALT ? BM_KEY_PAGE_UP : BM_KEY_UNICODE));
|
|
|
|
case XKB_KEY_BackSpace:
|
|
return BM_KEY_BACKSPACE;
|
|
|
|
case XKB_KEY_Delete:
|
|
return (mods & MOD_SHIFT ? BM_KEY_LINE_DELETE_LEFT : BM_KEY_DELETE);
|
|
|
|
case XKB_KEY_Tab:
|
|
return (mods & MOD_SHIFT ? BM_KEY_SHIFT_TAB : BM_KEY_TAB);
|
|
|
|
case XKB_KEY_Insert:
|
|
return BM_KEY_SHIFT_RETURN;
|
|
|
|
case XKB_KEY_KP_Enter:
|
|
case XKB_KEY_Return:
|
|
return (mods & MOD_CTRL ? BM_KEY_CONTROL_RETURN : (mods & MOD_SHIFT ? BM_KEY_SHIFT_RETURN : BM_KEY_RETURN));
|
|
|
|
case XKB_KEY_g:
|
|
if (!(mods & MOD_CTRL)) return BM_KEY_UNICODE;
|
|
// fall through
|
|
case XKB_KEY_c:
|
|
if (!(mods & MOD_CTRL)) return BM_KEY_UNICODE;
|
|
// fall through
|
|
case XKB_KEY_bracketleft:
|
|
if (!(mods & MOD_CTRL)) return BM_KEY_UNICODE;
|
|
// fall through
|
|
case XKB_KEY_Escape:
|
|
return BM_KEY_ESCAPE;
|
|
|
|
case XKB_KEY_p:
|
|
return (mods & MOD_CTRL ? BM_KEY_UP : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_n:
|
|
return (mods & MOD_CTRL ? BM_KEY_DOWN : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_l:
|
|
return (mods & MOD_CTRL ? BM_KEY_LEFT : (mods & MOD_ALT ? BM_KEY_DOWN : BM_KEY_UNICODE));
|
|
|
|
case XKB_KEY_f:
|
|
return (mods & MOD_CTRL ? BM_KEY_RIGHT : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_a:
|
|
return (mods & MOD_CTRL ? BM_KEY_HOME : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_e:
|
|
return (mods & MOD_CTRL ? BM_KEY_END : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_h:
|
|
return (mods & MOD_CTRL ? BM_KEY_BACKSPACE : (mods & MOD_ALT ? BM_KEY_UP : BM_KEY_UNICODE));
|
|
|
|
case XKB_KEY_u:
|
|
return (mods & MOD_CTRL ? BM_KEY_LINE_DELETE_LEFT : (mods & MOD_ALT ? BM_KEY_PAGE_UP : BM_KEY_UNICODE));
|
|
|
|
case XKB_KEY_k:
|
|
return (mods & MOD_CTRL ? BM_KEY_LINE_DELETE_RIGHT : (mods & MOD_ALT ? BM_KEY_UP : BM_KEY_UNICODE));
|
|
|
|
case XKB_KEY_w:
|
|
return (mods & MOD_CTRL ? BM_KEY_WORD_DELETE : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_j:
|
|
return (mods & MOD_ALT ? BM_KEY_DOWN : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_d:
|
|
return (mods & MOD_ALT ? BM_KEY_PAGE_DOWN : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_m:
|
|
return (mods & MOD_CTRL ? BM_KEY_RETURN : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_y:
|
|
return (mods & MOD_CTRL ? BM_KEY_PASTE : BM_KEY_UNICODE);
|
|
|
|
case XKB_KEY_1:
|
|
if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_1;
|
|
break;
|
|
case XKB_KEY_2:
|
|
if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_2;
|
|
break;
|
|
case XKB_KEY_3:
|
|
if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_3;
|
|
break;
|
|
case XKB_KEY_4:
|
|
if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_4;
|
|
break;
|
|
case XKB_KEY_5:
|
|
if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_5;
|
|
break;
|
|
case XKB_KEY_6:
|
|
if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_6;
|
|
break;
|
|
case XKB_KEY_7:
|
|
if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_7;
|
|
break;
|
|
case XKB_KEY_8:
|
|
if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_8;
|
|
break;
|
|
case XKB_KEY_9:
|
|
if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_9;
|
|
break;
|
|
case XKB_KEY_0:
|
|
if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_10;
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
|
|
return BM_KEY_UNICODE;
|
|
}
|
|
|
|
struct bm_pointer
|
|
poll_pointer(const struct bm_menu *menu)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
struct input *input = &wayland->input;
|
|
struct pointer_event *event = &input->pointer_event;
|
|
assert(wayland && event);
|
|
|
|
struct bm_pointer bm_pointer;
|
|
|
|
bm_pointer.event_mask = event->event_mask;
|
|
bm_pointer.pos_x = wl_fixed_to_int(event->surface_x);
|
|
bm_pointer.pos_y = wl_fixed_to_int(event->surface_y);
|
|
bm_pointer.time = event->time;
|
|
bm_pointer.axes[0].valid = event->axes[0].valid;
|
|
bm_pointer.axes[0].value = event->axes[0].value;
|
|
bm_pointer.axes[0].discrete = event->axes[0].discrete;
|
|
bm_pointer.axes[1].valid = event->axes[1].valid;
|
|
bm_pointer.axes[1].value = event->axes[1].value;
|
|
bm_pointer.axes[1].discrete = event->axes[1].discrete;
|
|
bm_pointer.axis_source = event->axis_source;
|
|
|
|
bm_pointer.button = BM_POINTER_KEY_NONE;
|
|
switch (event->button) {
|
|
case BTN_LEFT:
|
|
bm_pointer.button = BM_POINTER_KEY_PRIMARY;
|
|
break;
|
|
}
|
|
|
|
if (event->state & WL_POINTER_BUTTON_STATE_PRESSED) {
|
|
bm_pointer.state |= POINTER_STATE_PRESSED;
|
|
}
|
|
if (event->state & WL_POINTER_BUTTON_STATE_RELEASED) {
|
|
bm_pointer.state |= POINTER_STATE_RELEASED;
|
|
}
|
|
|
|
memset(event, 0, sizeof(*event));
|
|
return bm_pointer;
|
|
}
|
|
|
|
struct bm_touch
|
|
poll_touch(const struct bm_menu *menu)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
struct input *input = &wayland->input;
|
|
struct touch_event *event = &input->touch_event;
|
|
assert(wayland && event);
|
|
|
|
struct bm_touch bm_touch;
|
|
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
struct touch_point *point = &event->points[i];
|
|
|
|
if (!point->valid) {
|
|
bm_touch.points[i].event_mask = 0;
|
|
continue;
|
|
}
|
|
|
|
bm_touch.points[i].event_mask = point->event_mask;
|
|
bm_touch.points[i].pos_x = wl_fixed_to_int(point->surface_x);
|
|
bm_touch.points[i].pos_y = wl_fixed_to_int(point->surface_y);
|
|
bm_touch.points[i].start_x = wl_fixed_to_int(point->surface_start_x);
|
|
bm_touch.points[i].start_y = wl_fixed_to_int(point->surface_start_y);
|
|
bm_touch.points[i].major = point->major;
|
|
bm_touch.points[i].minor = point->minor;
|
|
bm_touch.points[i].orientation = point->orientation;
|
|
|
|
if (point->event_mask & TOUCH_EVENT_UP) {
|
|
point->valid = false;
|
|
point->event_mask = 0;
|
|
}
|
|
}
|
|
|
|
return bm_touch;
|
|
}
|
|
|
|
void
|
|
release_touch(const struct bm_menu *menu)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
struct input *input = &wayland->input;
|
|
struct touch_event *event = &input->touch_event;
|
|
assert(wayland && event);
|
|
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
struct touch_point *point = &event->points[i];
|
|
point->valid = false;
|
|
}
|
|
}
|
|
|
|
static uint32_t
|
|
get_displayed_count(const struct bm_menu *menu)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
assert(wayland);
|
|
uint32_t max = 0;
|
|
struct window *window;
|
|
wl_list_for_each(window, &wayland->windows, link) {
|
|
if (window->displayed > max)
|
|
max = window->displayed;
|
|
}
|
|
return max;
|
|
}
|
|
|
|
static uint32_t
|
|
get_height(const struct bm_menu *menu)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
assert(wayland);
|
|
uint32_t max = 0;
|
|
struct window *window;
|
|
wl_list_for_each(window, &wayland->windows, link) {
|
|
if (window->displayed > max)
|
|
max = window->height;
|
|
}
|
|
return max;
|
|
}
|
|
|
|
static uint32_t
|
|
get_width(const struct bm_menu *menu)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
assert(wayland);
|
|
uint32_t max = 0;
|
|
struct window *window;
|
|
wl_list_for_each(window, &wayland->windows, link) {
|
|
if (window->displayed > max)
|
|
max = window->width;
|
|
}
|
|
return max;
|
|
}
|
|
|
|
static void
|
|
set_width(const struct bm_menu *menu, uint32_t margin, float factor)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
assert(wayland);
|
|
|
|
struct window *window;
|
|
wl_list_for_each(window, &wayland->windows, link) {
|
|
bm_wl_window_set_width(window, wayland->display, margin, factor);
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_align(const struct bm_menu *menu, enum bm_align align)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
assert(wayland);
|
|
|
|
struct window *window;
|
|
wl_list_for_each(window, &wayland->windows, link) {
|
|
bm_wl_window_set_align(window, wayland->display, align);
|
|
}
|
|
}
|
|
|
|
static void
|
|
grab_keyboard(const struct bm_menu *menu, bool grab)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
assert(wayland);
|
|
|
|
struct window *window;
|
|
wl_list_for_each(window, &wayland->windows, link) {
|
|
bm_wl_window_grab_keyboard(window, wayland->display, grab);
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_overlap(const struct bm_menu *menu, bool overlap)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
assert(wayland);
|
|
|
|
struct window *window;
|
|
wl_list_for_each(window, &wayland->windows, link) {
|
|
bm_wl_window_set_overlap(window, wayland->display, overlap);
|
|
}
|
|
}
|
|
|
|
static void
|
|
destroy_windows(struct wayland *wayland)
|
|
{
|
|
struct window *window;
|
|
wl_list_for_each(window, &wayland->windows, link) {
|
|
bm_wl_window_destroy(window);
|
|
}
|
|
wl_list_init(&wayland->windows);
|
|
}
|
|
|
|
static void
|
|
recreate_windows(const struct bm_menu *menu, struct wayland *wayland)
|
|
{
|
|
destroy_windows(wayland);
|
|
|
|
int32_t monitors = 0;
|
|
struct output *output;
|
|
wl_list_for_each(output, &wayland->outputs, link)
|
|
monitors++;
|
|
|
|
int32_t monitor = 0;
|
|
wl_list_for_each(output, &wayland->outputs, link) {
|
|
|
|
if (!menu->monitor_name) {
|
|
if (menu->monitor > -1) {
|
|
if (menu->monitor < monitors && monitor != menu->monitor) {
|
|
++monitor;
|
|
continue;
|
|
}
|
|
}
|
|
} else if (strcmp(menu->monitor_name, output->name)) {
|
|
continue;
|
|
}
|
|
|
|
struct wl_surface *surface;
|
|
if (!(surface = wl_compositor_create_surface(wayland->compositor)))
|
|
goto fail;
|
|
|
|
wl_surface_set_buffer_scale(surface, output->scale);
|
|
|
|
struct window *window = calloc(1, sizeof(struct window));
|
|
window->align = menu->align;
|
|
window->hmargin_size = menu->hmargin_size;
|
|
window->width_factor = menu->width_factor;
|
|
|
|
const char *scale = getenv("BEMENU_SCALE");
|
|
if (scale) {
|
|
window->scale = fmax(strtof(scale, NULL), 1.0f);
|
|
} else {
|
|
window->scale = output->scale;
|
|
}
|
|
|
|
if (!bm_wl_window_create(window, wayland->display, wayland->shm, (menu->monitor == -1) ? NULL : output->output, wayland->layer_shell, surface))
|
|
free(window);
|
|
|
|
window->notify.render = bm_cairo_paint;
|
|
window->max_height = output->height;
|
|
window->render_pending = true;
|
|
wl_list_insert(&wayland->windows, &window->link);
|
|
if (menu->monitor != -2) break;
|
|
}
|
|
|
|
set_overlap(menu, menu->overlap);
|
|
grab_keyboard(menu, menu->grabbed);
|
|
return;
|
|
|
|
fail:
|
|
// This is non handlable if fails on recreation
|
|
fprintf(stderr, "wayland window creation failed :/\n");
|
|
abort();
|
|
}
|
|
|
|
static void
|
|
set_monitor(const struct bm_menu *menu, int32_t monitor)
|
|
{
|
|
(void)monitor;
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
assert(wayland);
|
|
recreate_windows(menu, wayland);
|
|
}
|
|
|
|
static void
|
|
set_monitor_name(const struct bm_menu *menu, char *monitor_name)
|
|
{
|
|
(void)monitor_name;
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
assert(wayland);
|
|
recreate_windows(menu, wayland);
|
|
}
|
|
|
|
static void
|
|
destructor(struct bm_menu *menu)
|
|
{
|
|
struct wayland *wayland = menu->renderer->internal;
|
|
|
|
if (!wayland)
|
|
return;
|
|
|
|
destroy_windows(wayland);
|
|
bm_wl_registry_destroy(wayland);
|
|
|
|
xkb_context_unref(wayland->input.xkb.context);
|
|
|
|
if (wayland->display) {
|
|
epoll_ctl(efd, EPOLL_CTL_DEL, wayland->fds.repeat, NULL);
|
|
epoll_ctl(efd, EPOLL_CTL_DEL, wayland->fds.display, NULL);
|
|
close(wayland->fds.repeat);
|
|
wl_display_flush(wayland->display);
|
|
wl_display_disconnect(wayland->display);
|
|
}
|
|
|
|
free(wayland);
|
|
menu->renderer->internal = NULL;
|
|
}
|
|
|
|
static bool
|
|
constructor(struct bm_menu *menu)
|
|
{
|
|
if (!getenv("WAYLAND_DISPLAY") && !getenv("WAYLAND_SOCKET"))
|
|
return false;
|
|
|
|
struct wayland *wayland;
|
|
if (!(menu->renderer->internal = wayland = calloc(1, sizeof(struct wayland))))
|
|
goto fail;
|
|
|
|
wl_list_init(&wayland->windows);
|
|
wl_list_init(&wayland->outputs);
|
|
|
|
if (!(wayland->display = wl_display_connect(NULL)))
|
|
goto fail;
|
|
|
|
if (!(wayland->input.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS)))
|
|
goto fail;
|
|
|
|
if (!bm_wl_registry_register(wayland))
|
|
goto fail;
|
|
|
|
wayland->fds.display = wl_display_get_fd(wayland->display);
|
|
wayland->fds.repeat = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
|
wayland->input.repeat_fd = &wayland->fds.repeat;
|
|
wayland->input.key_pending = false;
|
|
recreate_windows(menu, wayland);
|
|
|
|
if (!efd && (efd = epoll_create1(EPOLL_CLOEXEC)) < 0)
|
|
goto fail;
|
|
|
|
struct epoll_event ep;
|
|
ep.events = EPOLLIN | EPOLLERR | EPOLLHUP;
|
|
ep.data.ptr = &wayland->fds.display;
|
|
epoll_ctl(efd, EPOLL_CTL_ADD, wayland->fds.display, &ep);
|
|
|
|
struct epoll_event ep2;
|
|
ep2.events = EPOLLIN;
|
|
ep2.data.ptr = &wayland->fds.repeat;
|
|
epoll_ctl(efd, EPOLL_CTL_ADD, wayland->fds.repeat, &ep2);
|
|
return true;
|
|
|
|
fail:
|
|
destructor(menu);
|
|
return false;
|
|
}
|
|
|
|
BM_PUBLIC extern const char*
|
|
register_renderer(struct render_api *api)
|
|
{
|
|
api->constructor = constructor;
|
|
api->destructor = destructor;
|
|
api->get_displayed_count = get_displayed_count;
|
|
api->get_height = get_height;
|
|
api->get_width = get_width;
|
|
api->poll_key = poll_key;
|
|
api->poll_pointer = poll_pointer;
|
|
api->poll_touch = poll_touch;
|
|
api->release_touch = release_touch;
|
|
api->render = render;
|
|
api->set_align = set_align;
|
|
api->set_width = set_width;
|
|
api->grab_keyboard = grab_keyboard;
|
|
api->set_overlap = set_overlap;
|
|
api->set_monitor = set_monitor;
|
|
api->set_monitor_name = set_monitor_name;
|
|
api->priorty = BM_PRIO_GUI;
|
|
api->version = BM_PLUGIN_VERSION;
|
|
return "wayland";
|
|
}
|
|
|
|
/* vim: set ts=8 sw=4 tw=0 :*/
|