702 lines
20 KiB
C
702 lines
20 KiB
C
#include "wayland.h"
|
|
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/timerfd.h>
|
|
#include <string.h>
|
|
|
|
const char *BM_XKB_MASK_NAMES[MASK_LAST] = {
|
|
XKB_MOD_NAME_SHIFT,
|
|
XKB_MOD_NAME_CAPS,
|
|
XKB_MOD_NAME_CTRL,
|
|
XKB_MOD_NAME_ALT,
|
|
"Mod2",
|
|
"Mod3",
|
|
XKB_MOD_NAME_LOGO,
|
|
"Mod5",
|
|
};
|
|
|
|
const enum mod_bit BM_XKB_MODS[MASK_LAST] = {
|
|
MOD_SHIFT,
|
|
MOD_CAPS,
|
|
MOD_CTRL,
|
|
MOD_ALT,
|
|
MOD_MOD2,
|
|
MOD_MOD3,
|
|
MOD_LOGO,
|
|
MOD_MOD5
|
|
};
|
|
|
|
static void
|
|
shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
|
|
{
|
|
(void)wl_shm;
|
|
struct wayland *wayland = data;
|
|
wayland->formats |= (1 << format);
|
|
}
|
|
|
|
struct wl_shm_listener shm_listener = {
|
|
.format = shm_format
|
|
};
|
|
|
|
static void
|
|
keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size)
|
|
{
|
|
(void)keyboard;
|
|
struct input *input = data;
|
|
|
|
if (!data) {
|
|
close(fd);
|
|
return;
|
|
}
|
|
|
|
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
|
close(fd);
|
|
return;
|
|
}
|
|
|
|
char *map_str;
|
|
if ((map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
|
|
close(fd);
|
|
return;
|
|
}
|
|
|
|
struct xkb_keymap *keymap = xkb_keymap_new_from_string(input->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;
|
|
if (!(state = xkb_state_new(keymap))) {
|
|
fprintf(stderr, "failed to create XKB state\n");
|
|
xkb_keymap_unref(keymap);
|
|
return;
|
|
}
|
|
|
|
xkb_keymap_unref(input->xkb.keymap);
|
|
xkb_state_unref(input->xkb.state);
|
|
input->xkb.keymap = keymap;
|
|
input->xkb.state = state;
|
|
|
|
for (uint32_t i = 0; i < MASK_LAST; ++i)
|
|
input->xkb.masks[i] = 1 << xkb_keymap_mod_get_index(input->xkb.keymap, BM_XKB_MASK_NAMES[i]);
|
|
}
|
|
|
|
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)keyboard, (void)serial, (void)surface;
|
|
struct input *input = data;
|
|
struct itimerspec its;
|
|
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_fd, 0, &its, NULL);
|
|
}
|
|
|
|
static void
|
|
press(struct input *input, xkb_keysym_t sym, uint32_t key, enum wl_keyboard_key_state state)
|
|
{
|
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
|
input->sym = sym;
|
|
input->code = key + 8;
|
|
input->key_pending = true;
|
|
} else if (!input->key_pending) {
|
|
input->sym = XKB_KEY_NoSymbol;
|
|
input->code = 0;
|
|
}
|
|
|
|
if (input->notify.key)
|
|
input->notify.key(state, sym, key);
|
|
}
|
|
|
|
static void
|
|
keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state_w)
|
|
{
|
|
(void)keyboard, (void)serial, (void)time;
|
|
struct input *input = data;
|
|
enum wl_keyboard_key_state state = state_w;
|
|
|
|
if (!input->xkb.state)
|
|
return;
|
|
|
|
xkb_keysym_t sym = xkb_state_key_get_one_sym(input->xkb.state, key + 8);
|
|
press(input, sym, key, state);
|
|
|
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(input->xkb.keymap, input->code)) {
|
|
struct itimerspec its;
|
|
input->repeat_sym = sym;
|
|
input->repeat_key = key;
|
|
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_fd, 0, &its, NULL);
|
|
} else if (state == WL_KEYBOARD_KEY_STATE_RELEASED && key == input->repeat_key) {
|
|
struct itimerspec its;
|
|
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_fd, 0, &its, NULL);
|
|
}
|
|
}
|
|
|
|
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 input *input = data;
|
|
|
|
if (!input->xkb.keymap)
|
|
return;
|
|
|
|
xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
|
xkb_mod_mask_t mask = xkb_state_serialize_mods(input->xkb.state, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
|
|
|
|
input->modifiers = 0;
|
|
for (uint32_t i = 0; i < MASK_LAST; ++i) {
|
|
if (mask & input->xkb.masks[i])
|
|
input->modifiers |= BM_XKB_MODS[i];
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_repeat_info(struct input *input, int32_t rate, int32_t delay)
|
|
{
|
|
assert(input);
|
|
|
|
input->repeat_rate_sec = input->repeat_rate_nsec = 0;
|
|
input->repeat_delay_sec = input->repeat_delay_nsec = 0;
|
|
|
|
/* a rate of zero disables any repeating, regardless of the delay's value */
|
|
if (rate == 0)
|
|
return;
|
|
|
|
if (rate == 1)
|
|
input->repeat_rate_sec = 1;
|
|
else
|
|
input->repeat_rate_nsec = 1000000000 / rate;
|
|
|
|
input->repeat_delay_sec = delay / 1000;
|
|
delay -= (input->repeat_delay_sec * 1000);
|
|
input->repeat_delay_nsec = delay * 1000 * 1000;
|
|
}
|
|
|
|
static void
|
|
keyboard_handle_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)
|
|
{
|
|
(void)keyboard;
|
|
set_repeat_info(data, rate, delay);
|
|
}
|
|
|
|
static void
|
|
pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
|
|
uint32_t serial, struct wl_surface *surface,
|
|
wl_fixed_t surface_x, wl_fixed_t surface_y)
|
|
{
|
|
(void)wl_pointer, (void)surface;
|
|
struct input *input = data;
|
|
input->pointer_event.event_mask |= POINTER_EVENT_ENTER;
|
|
input->pointer_event.serial = serial;
|
|
input->pointer_event.surface_x = surface_x,
|
|
input->pointer_event.surface_y = surface_y;
|
|
}
|
|
|
|
static void
|
|
pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
|
|
uint32_t serial, struct wl_surface *surface)
|
|
{
|
|
(void)wl_pointer, (void)surface;
|
|
struct input *input = data;
|
|
input->pointer_event.serial = serial;
|
|
input->pointer_event.event_mask |= POINTER_EVENT_LEAVE;
|
|
}
|
|
|
|
static void
|
|
pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time,
|
|
wl_fixed_t surface_x, wl_fixed_t surface_y)
|
|
{
|
|
(void)wl_pointer;
|
|
struct input *input = data;
|
|
input->pointer_event.event_mask |= POINTER_EVENT_MOTION;
|
|
input->pointer_event.time = time;
|
|
input->pointer_event.surface_x = surface_x,
|
|
input->pointer_event.surface_y = surface_y;
|
|
}
|
|
|
|
static void
|
|
pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
|
uint32_t time, uint32_t button, uint32_t state)
|
|
{
|
|
(void)wl_pointer;
|
|
struct input *input = data;
|
|
input->pointer_event.event_mask |= POINTER_EVENT_BUTTON;
|
|
input->pointer_event.time = time;
|
|
input->pointer_event.serial = serial;
|
|
input->pointer_event.button = button,
|
|
input->pointer_event.state |= state;
|
|
}
|
|
|
|
static void
|
|
pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time,
|
|
uint32_t axis, wl_fixed_t value)
|
|
{
|
|
(void)wl_pointer;
|
|
struct input *input = data;
|
|
input->pointer_event.event_mask |= POINTER_EVENT_AXIS;
|
|
input->pointer_event.time = time;
|
|
input->pointer_event.axes[axis].valid = true;
|
|
input->pointer_event.axes[axis].value = value;
|
|
}
|
|
|
|
static void
|
|
pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer,
|
|
uint32_t axis_source)
|
|
{
|
|
(void)wl_pointer;
|
|
struct input *input = data;
|
|
input->pointer_event.event_mask |= POINTER_EVENT_AXIS_SOURCE;
|
|
input->pointer_event.axis_source = axis_source;
|
|
}
|
|
|
|
static void
|
|
pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
|
uint32_t time, uint32_t axis)
|
|
{
|
|
(void)wl_pointer;
|
|
struct input *input = data;
|
|
input->pointer_event.time = time;
|
|
input->pointer_event.event_mask |= POINTER_EVENT_AXIS_STOP;
|
|
input->pointer_event.axes[axis].valid = true;
|
|
}
|
|
|
|
static void
|
|
pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer,
|
|
uint32_t axis, int32_t discrete)
|
|
{
|
|
(void)wl_pointer;
|
|
struct input *input = data;
|
|
input->pointer_event.event_mask |= POINTER_EVENT_AXIS_DISCRETE;
|
|
input->pointer_event.axes[axis].valid = true;
|
|
input->pointer_event.axes[axis].discrete = discrete;
|
|
}
|
|
|
|
|
|
static void
|
|
pointer_handle_frame(void *data, struct wl_pointer *wl_pointer)
|
|
{
|
|
(void) data, (void) wl_pointer;
|
|
}
|
|
|
|
static struct touch_point *
|
|
get_touch_point(struct input *input, int32_t id)
|
|
{
|
|
struct touch_event *touch = &input->touch_event;
|
|
int invalid = -1;
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
if (touch->points[i].id == id) {
|
|
invalid = i;
|
|
}
|
|
if (invalid == -1 && !touch->points[i].valid) {
|
|
invalid = i;
|
|
}
|
|
}
|
|
if (invalid == -1) {
|
|
return NULL;
|
|
}
|
|
touch->points[invalid].id = id;
|
|
return &touch->points[invalid];
|
|
}
|
|
|
|
static void
|
|
reset_all_start_position(struct input *input)
|
|
{
|
|
struct touch_event *event = &input->touch_event;
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
struct touch_point *point = &event->points[i];
|
|
|
|
if (!point->valid)
|
|
continue;
|
|
|
|
point->surface_start_x = point->surface_x;
|
|
point->surface_start_y = point->surface_y;
|
|
}
|
|
}
|
|
|
|
static void
|
|
revalidate_all_released(struct input *input)
|
|
{
|
|
struct touch_event *event = &input->touch_event;
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
struct touch_point *point = &event->points[i];
|
|
|
|
if (!point->valid && point->event_mask & TOUCH_EVENT_DOWN)
|
|
point->valid = true;
|
|
}
|
|
}
|
|
|
|
static void
|
|
touch_handle_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)
|
|
{
|
|
(void) wl_touch, (void) surface;
|
|
struct input *input = data;
|
|
struct touch_point *point = get_touch_point(input, id);
|
|
if (point == NULL) {
|
|
return;
|
|
}
|
|
point->valid = true;
|
|
point->event_mask = TOUCH_EVENT_DOWN;
|
|
point->surface_x = x,
|
|
point->surface_y = y;
|
|
input->touch_event.time = time;
|
|
input->touch_event.serial = serial;
|
|
input->touch_event.active += 1;
|
|
|
|
revalidate_all_released(input);
|
|
reset_all_start_position(input);
|
|
}
|
|
|
|
static void
|
|
touch_handle_up(void *data, struct wl_touch *wl_touch, uint32_t serial,
|
|
uint32_t time, int32_t id)
|
|
{
|
|
(void) time, (void) wl_touch, (void) serial;
|
|
struct input *input = data;
|
|
struct touch_point *point = get_touch_point(input, id);
|
|
if (point == NULL) {
|
|
return;
|
|
}
|
|
point->event_mask |= TOUCH_EVENT_UP;
|
|
input->touch_event.active -= 1;
|
|
|
|
reset_all_start_position(input);
|
|
}
|
|
|
|
static void
|
|
touch_handle_motion(void *data, struct wl_touch *wl_touch, uint32_t time,
|
|
int32_t id, wl_fixed_t x, wl_fixed_t y)
|
|
{
|
|
(void) wl_touch;
|
|
struct input *input = data;
|
|
struct touch_point *point = get_touch_point(input, id);
|
|
if (point == NULL) {
|
|
return;
|
|
}
|
|
point->event_mask |= TOUCH_EVENT_MOTION;
|
|
point->surface_x = x, point->surface_y = y;
|
|
input->touch_event.time = time;
|
|
}
|
|
|
|
static void
|
|
touch_handle_cancel(void *data, struct wl_touch *wl_touch)
|
|
{
|
|
(void) wl_touch, (void) data;
|
|
}
|
|
|
|
static void
|
|
touch_handle_shape(void *data, struct wl_touch *wl_touch,
|
|
int32_t id, wl_fixed_t major, wl_fixed_t minor)
|
|
{
|
|
(void) wl_touch;
|
|
struct input *input = data;
|
|
struct touch_point *point = get_touch_point(input, id);
|
|
if (point == NULL) {
|
|
return;
|
|
}
|
|
point->event_mask |= TOUCH_EVENT_SHAPE;
|
|
point->major = major, point->minor = minor;
|
|
}
|
|
|
|
static void
|
|
touch_handle_orientation(void *data, struct wl_touch *wl_touch,
|
|
int32_t id, wl_fixed_t orientation)
|
|
{
|
|
(void) wl_touch;
|
|
struct input *input = data;
|
|
struct touch_point *point = get_touch_point(input, id);
|
|
if (point == NULL) {
|
|
return;
|
|
}
|
|
point->event_mask |= TOUCH_EVENT_ORIENTATION;
|
|
point->orientation = orientation;
|
|
}
|
|
|
|
static void
|
|
touch_handle_frame(void *data, struct wl_touch *wl_touch)
|
|
{
|
|
(void) data, (void) wl_touch;
|
|
}
|
|
|
|
static const struct wl_pointer_listener pointer_listener = {
|
|
.enter = pointer_handle_enter,
|
|
.leave = pointer_handle_leave,
|
|
.motion = pointer_handle_motion,
|
|
.button = pointer_handle_button,
|
|
.axis = pointer_handle_axis,
|
|
.frame = pointer_handle_frame,
|
|
.axis_source = pointer_handle_axis_source,
|
|
.axis_stop = pointer_handle_axis_stop,
|
|
.axis_discrete = pointer_handle_axis_discrete,
|
|
};
|
|
|
|
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 const struct wl_touch_listener wl_touch_listener = {
|
|
.down = touch_handle_down,
|
|
.up = touch_handle_up,
|
|
.motion = touch_handle_motion,
|
|
.frame = touch_handle_frame,
|
|
.cancel = touch_handle_cancel,
|
|
.shape = touch_handle_shape,
|
|
.orientation = touch_handle_orientation,
|
|
};
|
|
|
|
static void
|
|
seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps)
|
|
{
|
|
struct input *input = data;
|
|
|
|
if (!input->seat) {
|
|
input->seat = seat;
|
|
}
|
|
|
|
if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
|
|
input->keyboard = wl_seat_get_keyboard(seat);
|
|
wl_keyboard_add_listener(input->keyboard, &keyboard_listener, data);
|
|
}
|
|
|
|
if (caps & WL_SEAT_CAPABILITY_POINTER) {
|
|
input->pointer = wl_seat_get_pointer(seat);
|
|
wl_pointer_add_listener(input->pointer, &pointer_listener, data);
|
|
}
|
|
|
|
if (caps & WL_SEAT_CAPABILITY_TOUCH) {
|
|
input->touch = wl_seat_get_touch(seat);
|
|
wl_touch_add_listener(input->touch, &wl_touch_listener, data);
|
|
}
|
|
|
|
if (seat == input->seat && !(caps & WL_SEAT_CAPABILITY_KEYBOARD) && !(caps & WL_SEAT_CAPABILITY_POINTER)) {
|
|
wl_keyboard_destroy(input->keyboard);
|
|
input->seat = NULL;
|
|
input->keyboard = NULL;
|
|
input->pointer = NULL;
|
|
input->touch = 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 = {
|
|
.capabilities = seat_handle_capabilities,
|
|
.name = seat_handle_name
|
|
};
|
|
|
|
static void
|
|
xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y)
|
|
{
|
|
(void)data, (void)xdg_output, (void)x, (void)y;
|
|
}
|
|
|
|
static void
|
|
xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height)
|
|
{
|
|
(void)data, (void)xdg_output, (void)width, (void)height;
|
|
}
|
|
|
|
static void
|
|
xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
|
|
{
|
|
(void)data, (void)xdg_output;
|
|
}
|
|
|
|
static void
|
|
xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, const char *name)
|
|
{
|
|
(void)xdg_output;
|
|
struct output *output = data;
|
|
output->name = bm_strdup(name);
|
|
}
|
|
|
|
static void
|
|
xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, const char *description)
|
|
{
|
|
(void)data, (void)xdg_output, (void)description;
|
|
}
|
|
|
|
static const struct zxdg_output_v1_listener xdg_output_listener = {
|
|
.logical_position = xdg_output_handle_logical_position,
|
|
.logical_size = xdg_output_handle_logical_size,
|
|
.done = xdg_output_handle_done,
|
|
.name = xdg_output_handle_name,
|
|
.description = xdg_output_handle_description,
|
|
};
|
|
|
|
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)
|
|
{
|
|
(void)data, (void)wl_output, (void)x, (void)y, (void)physical_width, (void)physical_height, (void)subpixel, (void)make, (void)model, (void)transform;
|
|
}
|
|
|
|
static void
|
|
display_handle_done(void *data, struct wl_output *wl_output)
|
|
{
|
|
(void)data, (void)wl_output;
|
|
}
|
|
|
|
static void
|
|
display_handle_scale(void *data, struct wl_output *wl_output, int32_t scale)
|
|
{
|
|
(void)wl_output;
|
|
struct output *output = data;
|
|
|
|
assert(scale > 0);
|
|
output->scale = scale;
|
|
}
|
|
|
|
static void
|
|
display_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, int width, int height, int refresh)
|
|
{
|
|
(void)wl_output, (void)refresh, (void)height, (void)width;
|
|
struct output *output = data;
|
|
|
|
if (flags & WL_OUTPUT_MODE_CURRENT) {
|
|
output->height = height;
|
|
}
|
|
}
|
|
|
|
static const struct wl_output_listener output_listener = {
|
|
.geometry = display_handle_geometry,
|
|
.mode = display_handle_mode,
|
|
.done = display_handle_done,
|
|
.scale = display_handle_scale
|
|
};
|
|
|
|
static void
|
|
registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version)
|
|
{
|
|
(void)version;
|
|
struct wayland *wayland = data;
|
|
|
|
if (strcmp(interface, "wl_compositor") == 0) {
|
|
wayland->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 4);
|
|
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
|
|
wayland->layer_shell = wl_registry_bind(registry, id, &zwlr_layer_shell_v1_interface, 2);
|
|
} else if (strcmp(interface, "wl_seat") == 0) {
|
|
wayland->seat = wl_registry_bind(registry, id, &wl_seat_interface, 7);
|
|
wl_seat_add_listener(wayland->seat, &seat_listener, &wayland->input);
|
|
} else if (strcmp(interface, "wl_shm") == 0) {
|
|
wayland->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
|
|
wl_shm_add_listener(wayland->shm, &shm_listener, data);
|
|
} else if (strcmp(interface, "wl_output") == 0) {
|
|
struct wl_output *wl_output = wl_registry_bind(registry, id, &wl_output_interface, 2);
|
|
struct output *output = calloc(1, sizeof(struct output));
|
|
output->output = wl_output;
|
|
output->scale = 1;
|
|
wl_list_insert(&wayland->outputs, &output->link);
|
|
wl_output_add_listener(wl_output, &output_listener, output);
|
|
} else if (!strcmp(interface, zxdg_output_manager_v1_interface.name)) {
|
|
wayland->xdg_output_manager = wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, 2);
|
|
}
|
|
}
|
|
|
|
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
|
|
};
|
|
|
|
void
|
|
bm_wl_repeat(struct wayland *wayland)
|
|
{
|
|
uint64_t exp;
|
|
if (read(wayland->fds.repeat, &exp, sizeof(exp)) != sizeof(exp))
|
|
return;
|
|
|
|
if (wayland->input.notify.key)
|
|
wayland->input.notify.key(WL_KEYBOARD_KEY_STATE_PRESSED, wayland->input.repeat_sym, wayland->input.repeat_key + 8);
|
|
|
|
press(&wayland->input, wayland->input.repeat_sym, wayland->input.repeat_key, WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
}
|
|
|
|
void
|
|
bm_wl_registry_destroy(struct wayland *wayland)
|
|
{
|
|
assert(wayland);
|
|
|
|
if (wayland->shm)
|
|
wl_shm_destroy(wayland->shm);
|
|
|
|
if (wayland->layer_shell)
|
|
zwlr_layer_shell_v1_destroy(wayland->layer_shell);
|
|
|
|
if (wayland->compositor)
|
|
wl_compositor_destroy(wayland->compositor);
|
|
|
|
if (wayland->registry)
|
|
wl_registry_destroy(wayland->registry);
|
|
|
|
xkb_keymap_unref(wayland->input.xkb.keymap);
|
|
xkb_state_unref(wayland->input.xkb.state);
|
|
}
|
|
|
|
bool
|
|
bm_wl_registry_register(struct wayland *wayland)
|
|
{
|
|
assert(wayland);
|
|
|
|
if (!(wayland->registry = wl_display_get_registry(wayland->display)))
|
|
return false;
|
|
|
|
wl_registry_add_listener(wayland->registry, ®istry_listener, wayland);
|
|
wl_display_roundtrip(wayland->display); // trip 1, registry globals
|
|
if (!wayland->compositor || !wayland->seat || !wayland->shm || !wayland->layer_shell)
|
|
return false;
|
|
|
|
struct output *output;
|
|
wl_list_for_each(output, &wayland->outputs, link) {
|
|
output->xdg_output = zxdg_output_manager_v1_get_xdg_output(
|
|
wayland->xdg_output_manager, output->output);
|
|
zxdg_output_v1_add_listener(
|
|
output->xdg_output, &xdg_output_listener, output);
|
|
}
|
|
|
|
wl_display_roundtrip(wayland->display); // trip 2, global listeners
|
|
if (!wayland->input.keyboard || !(wayland->formats & (1 << WL_SHM_FORMAT_ARGB8888)))
|
|
return false;
|
|
|
|
set_repeat_info(&wayland->input, 40, 400);
|
|
return true;
|
|
}
|
|
|
|
/* vim: set ts=8 sw=4 tw=0 :*/
|