mouse and touch support on wayland

This commit is contained in:
Stacy Harper 2021-08-14 17:31:28 +02:00 committed by Jari Vetoniemi
parent 391bf16c85
commit a111aa2afa
7 changed files with 850 additions and 5 deletions

View File

@ -502,11 +502,15 @@ run_menu(const struct client *client, struct bm_menu *menu, void (*item_cb)(cons
uint32_t unicode;
enum bm_key key;
struct bm_pointer pointer;
struct bm_touch touch;
enum bm_run_result status = BM_RUN_RESULT_RUNNING;
do {
bm_menu_render(menu);
key = bm_menu_poll_key(menu, &unicode);
} while ((status = bm_menu_run_with_key(menu, key, unicode)) == BM_RUN_RESULT_RUNNING);
pointer = bm_menu_poll_pointer(menu);
touch = bm_menu_poll_touch(menu);
} while ((status = bm_menu_run_with_events(menu, key, pointer, touch, unicode)) == BM_RUN_RESULT_RUNNING);
switch (status) {
case BM_RUN_RESULT_SELECTED:

View File

@ -253,6 +253,70 @@ enum bm_key {
BM_KEY_LAST
};
enum bm_pointer_key {
BM_POINTER_KEY_NONE,
BM_POINTER_KEY_PRIMARY,
};
enum bm_pointer_axis {
BM_POINTER_AXIS_VERTICAL = 0,
BM_POINTER_AXIS_HORIZONTAL = 1,
};
enum bm_pointer_event_mask {
POINTER_EVENT_ENTER = 1 << 1,
POINTER_EVENT_LEAVE = 1 << 2,
POINTER_EVENT_MOTION = 1 << 3,
POINTER_EVENT_BUTTON = 1 << 4,
POINTER_EVENT_AXIS = 1 << 5,
POINTER_EVENT_AXIS_SOURCE = 1 << 6,
POINTER_EVENT_AXIS_STOP = 1 << 7,
POINTER_EVENT_AXIS_DISCRETE = 1 << 8,
};
enum bm_pointer_state_mask {
POINTER_STATE_RELEASED,
POINTER_STATE_PRESSED,
};
struct bm_pointer {
uint32_t event_mask;
uint32_t pos_x, pos_y;
uint32_t button, state;
uint32_t time;
struct {
bool valid;
int32_t value;
int32_t discrete;
} axes[2];
uint32_t axis_source;
};
enum bm_touch_event_mask {
TOUCH_EVENT_DOWN = 1 << 0,
TOUCH_EVENT_UP = 1 << 1,
TOUCH_EVENT_MOTION = 1 << 2,
TOUCH_EVENT_CANCEL = 1 << 3,
TOUCH_EVENT_SHAPE = 1 << 4,
TOUCH_EVENT_ORIENTATION = 1 << 5,
};
struct bm_touch_point {
bool valid;
int32_t id;
uint32_t event_mask;
int32_t start_x, start_y;
int32_t pos_x, pos_y;
uint32_t major, minor;
uint32_t orientation;
};
struct bm_touch {
uint32_t time;
uint32_t serial;
struct bm_touch_point points[2];
};
/**
* Colorable element constants.
*
@ -486,6 +550,22 @@ BM_PUBLIC void bm_menu_set_cursor_height(struct bm_menu *menu, uint32_t cursor_h
*/
BM_PUBLIC uint32_t bm_menu_get_cursor_height(struct bm_menu *menu);
/**
* Get with of menu in pixels.
*
* @param menu bm_menu instance where to get line height.
* @return uint32_t for max amount the menu height.
*/
BM_PUBLIC uint32_t bm_menu_get_height(struct bm_menu *menu);
/**
* Get with of menu in pixels.
*
* @param menu bm_menu instance where to get line width.
* @return uint32_t for max amount the menu width.
*/
BM_PUBLIC uint32_t bm_menu_get_width(struct bm_menu *menu);
/**
* Set a hexadecimal color for element.
*
@ -809,15 +889,44 @@ BM_PUBLIC void bm_menu_filter(struct bm_menu *menu);
*/
BM_PUBLIC enum bm_key bm_menu_poll_key(struct bm_menu *menu, uint32_t *out_unicode);
/**
* Poll pointer and unicode from underlying UI toolkit.
*
* This function will block on **curses** renderer.
*
* @param menu bm_menu instance from which to poll.
* @return bm_pointer for polled pointer.
*/
BM_PUBLIC struct bm_pointer bm_menu_poll_pointer(struct bm_menu *menu);
/**
* Poll touch and unicode from underlying UI toolkit.
*
* This function will block on **curses** renderer.
*
* @param menu bm_menu instance from which to poll.
* @return bm_touch for polled touch.
*/
BM_PUBLIC struct bm_touch bm_menu_poll_touch(struct bm_menu *menu);
/**
* Enforce a release of the touches.
*
* @param menu bm_menu instance from which to poll.
*/
BM_PUBLIC void bm_menu_release_touch(struct bm_menu *menu);
/**
* Advances menu logic with key and unicode as input.
*
* @param menu bm_menu instance to be advanced.
* @param key Key input that will advance menu logic.
* @param pointer Pointer input that will advance menu logic.
* @param touch Touch input that will advance menu logic.
* @param unicode Unicode input that will advance menu logic.
* @return bm_run_result for menu state.
*/
BM_PUBLIC enum bm_run_result bm_menu_run_with_key(struct bm_menu *menu, enum bm_key key, uint32_t unicode);
BM_PUBLIC enum bm_run_result bm_menu_run_with_events(struct bm_menu *menu, enum bm_key key, struct bm_pointer pointer, struct bm_touch touch, uint32_t unicode);
/** @} Menu Logic */

View File

@ -66,12 +66,40 @@ struct render_api {
*/
uint32_t (*get_displayed_count)(const struct bm_menu *menu);
/**
* Get height by the underlying renderer;
*/
uint32_t (*get_height)(const struct bm_menu *menu);
/**
* Get width by the underlying renderer;
*/
uint32_t (*get_width)(const struct bm_menu *menu);
/**
* If the underlying renderer is a UI toolkit. (curses, etc...)
* There might be possibility to get user input, and this should be thus implemented.
*/
enum bm_key (*poll_key)(const struct bm_menu *menu, uint32_t *unicode);
/**
* If the underlying renderer is a UI toolkit. (curses, etc...)
* There might be possibility to get user pointer, and this should be thus implemented.
*/
struct bm_pointer (*poll_pointer)(const struct bm_menu *menu);
/**
* If the underlying renderer is a UI toolkit. (curses, etc...)
* There might be possibility to get user touch, and this should be thus implemented.
*/
struct bm_touch (*poll_touch)(const struct bm_menu *menu);
/**
* Enforce a release of the touches
* There might be possibility to get user touch, and this should be thus implemented.
*/
void (*release_touch)(const struct bm_menu *menu);
/**
* Tells underlying renderer to draw the menu.
*/

View File

@ -293,6 +293,7 @@ uint32_t
bm_menu_get_line_height(struct bm_menu *menu)
{
assert(menu);
return menu->line_height;
}
@ -310,6 +311,34 @@ bm_menu_get_cursor_height(struct bm_menu *menu)
return menu->cursor_height;
}
uint32_t
bm_menu_get_height(struct bm_menu *menu)
{
assert(menu);
uint32_t height = 0;
if (menu->renderer->api.get_height) {
height = menu->renderer->api.get_height(menu);
}
return height;
}
uint32_t
bm_menu_get_width(struct bm_menu *menu)
{
assert(menu);
uint32_t width = 0;
if (menu->renderer->api.get_width) {
width = menu->renderer->api.get_width(menu);
}
return width;
}
bool
bm_menu_set_color(struct bm_menu *menu, enum bm_color color, const char *hex)
{
@ -707,6 +736,41 @@ bm_menu_poll_key(struct bm_menu *menu, uint32_t *out_unicode)
return key;
}
struct bm_pointer
bm_menu_poll_pointer(struct bm_menu *menu)
{
assert(menu);
struct bm_pointer pointer = {0};
if (menu->renderer->api.poll_pointer)
pointer = menu->renderer->api.poll_pointer(menu);
return pointer;
}
struct bm_touch
bm_menu_poll_touch(struct bm_menu *menu)
{
assert(menu);
struct bm_touch touch = {0};
if (menu->renderer->api.poll_touch)
touch = menu->renderer->api.poll_touch(menu);
return touch;
}
void
bm_menu_release_touch(struct bm_menu *menu)
{
assert(menu);
if (menu->renderer->api.release_touch)
menu->renderer->api.release_touch(menu);
}
static void
menu_next(struct bm_menu *menu, uint32_t count, bool wrap)
{
@ -727,6 +791,41 @@ menu_prev(struct bm_menu *menu, uint32_t count, bool wrap)
}
}
static void
menu_point_select(struct bm_menu *menu, uint32_t posx, uint32_t posy, uint32_t displayed)
{
(void) posx;
uint32_t selected_line = posy / (bm_menu_get_height(menu) / displayed);
uint16_t current_page_index = menu->index / menu->lines;
if (0 == selected_line) { // Mouse over title bar
return;
}
if (selected_line >= displayed) { // This might be useless
return;
}
menu->index = current_page_index * menu->lines + (selected_line - 1);
}
static void
menu_scroll_down(struct bm_menu *menu, uint16_t count)
{
if (menu->index / menu->lines != count / menu->lines) { // not last page
menu->index = ((menu->index / menu->lines) + 1) * menu->lines;
}
}
static void
menu_scroll_up(struct bm_menu *menu, uint16_t count)
{
(void) count;
if (menu->index / menu->lines) { // not first page
menu->index = ((menu->index / menu->lines) - 1) * menu->lines + menu->lines - 1;
}
}
enum bm_run_result
bm_menu_run_with_key(struct bm_menu *menu, enum bm_key key, uint32_t unicode)
{
@ -954,4 +1053,169 @@ bm_menu_run_with_key(struct bm_menu *menu, enum bm_key key, uint32_t unicode)
return BM_RUN_RESULT_RUNNING;
}
enum bm_run_result
bm_menu_run_with_pointer(struct bm_menu *menu, struct bm_pointer pointer, uint32_t unicode)
{
(void) unicode;
uint32_t count;
bm_menu_get_filtered_items(menu, &count);
uint32_t displayed = 0;
if (menu->renderer->api.get_displayed_count)
displayed = menu->renderer->api.get_displayed_count(menu);
if (!displayed)
displayed = count;
if (!menu->lines) {
if (pointer.axes[BM_POINTER_AXIS_VERTICAL].valid) {
if (0 < pointer.axes[BM_POINTER_AXIS_VERTICAL].value) {
menu_next(menu, count, menu->wrap);
} else {
menu_prev(menu, count, menu->wrap);
}
}
if (pointer.event_mask & POINTER_EVENT_BUTTON && pointer.state == POINTER_STATE_PRESSED) {
switch (pointer.button) {
case BM_POINTER_KEY_PRIMARY:
{
struct bm_item *highlighted = bm_menu_get_highlighted_item(menu);
if (highlighted && !bm_menu_item_is_selected(menu, highlighted))
list_add_item(&menu->selection, highlighted);
}
return BM_RUN_RESULT_SELECTED;
}
}
return BM_RUN_RESULT_RUNNING;
}
if (pointer.axes[BM_POINTER_AXIS_VERTICAL].valid) {
if (0 < pointer.axes[BM_POINTER_AXIS_VERTICAL].value) {
menu_scroll_down(menu, count);
} else {
menu_scroll_up(menu, count);
}
}
if (pointer.event_mask & POINTER_EVENT_MOTION) {
menu_point_select(menu, pointer.pos_x, pointer.pos_y, displayed);
}
if (pointer.event_mask & POINTER_EVENT_BUTTON && pointer.state == POINTER_STATE_PRESSED) {
switch (pointer.button) {
case BM_POINTER_KEY_PRIMARY:
{
struct bm_item *highlighted = bm_menu_get_highlighted_item(menu);
if (highlighted && !bm_menu_item_is_selected(menu, highlighted))
list_add_item(&menu->selection, highlighted);
}
return BM_RUN_RESULT_SELECTED;
}
}
return BM_RUN_RESULT_RUNNING;
}
enum bm_run_result
bm_menu_run_with_touch(struct bm_menu *menu, struct bm_touch touch, uint32_t unicode)
{
(void) unicode;
uint32_t count;
bm_menu_get_filtered_items(menu, &count);
uint32_t displayed = 0;
if (menu->renderer->api.get_displayed_count)
displayed = menu->renderer->api.get_displayed_count(menu);
if (!displayed)
displayed = count;
if (!menu->lines) {
// Not implemented yet
return BM_RUN_RESULT_RUNNING;
}
uint16_t count_down = 0;
for (size_t i = 0; i < 2; ++i) {
struct bm_touch_point point = touch.points[i];
if (point.event_mask & TOUCH_EVENT_DOWN) {
count_down += 1;
}
}
if (count_down == 2) {
int16_t scroll_count = 0;
int16_t scroll_directions[2];
int16_t distance_trigger = displayed * bm_menu_get_line_height(menu) / 4;
for (size_t i = 0; i < 2; ++i) {
struct bm_touch_point point = touch.points[i];
if (!(point.event_mask & TOUCH_EVENT_DOWN))
continue;
int32_t movement_y = point.pos_y - point.start_y;
if (abs(movement_y) > distance_trigger) {
scroll_directions[i] = movement_y / abs(movement_y);
scroll_count++;
}
}
int16_t scroll_direction_sum = scroll_directions[0] + scroll_directions[1];
if (2 == abs(scroll_direction_sum)) {
uint16_t current_page = menu->index / menu->lines;
if (scroll_direction_sum < 0 && current_page != count / menu->lines) { // not already the first page
menu_scroll_down(menu, count);
bm_menu_release_touch(menu);
} else if (scroll_direction_sum > 0 && current_page) { // not already the first page
menu_scroll_up(menu, count);
bm_menu_release_touch(menu);
}
}
}
if (count_down != 1)
return BM_RUN_RESULT_RUNNING;
for (size_t i = 0; i < 2; ++i) {
struct bm_touch_point point = touch.points[i];
if (!(point.event_mask & TOUCH_EVENT_DOWN))
continue;
menu_point_select(menu, point.pos_x, point.pos_y, displayed);
if (point.event_mask & TOUCH_EVENT_UP) {
if (point.pos_y < (int32_t) (bm_menu_get_height(menu) / displayed)) {
menu_scroll_up(menu, count);
} else if ((uint32_t) point.pos_y > bm_menu_get_height(menu)) {
menu_scroll_down(menu, count);
} else if (point.pos_x > 0
&& (uint32_t) point.pos_x < bm_menu_get_width(menu)) {
{
struct bm_item *highlighted = bm_menu_get_highlighted_item(menu);
if (highlighted && !bm_menu_item_is_selected(menu, highlighted))
list_add_item(&menu->selection, highlighted);
}
return BM_RUN_RESULT_SELECTED;
}
}
}
return BM_RUN_RESULT_RUNNING;
}
enum bm_run_result
bm_menu_run_with_events(struct bm_menu *menu, enum bm_key key,
struct bm_pointer pointer, struct bm_touch touch, uint32_t unicode)
{
enum bm_run_result key_result = bm_menu_run_with_key(menu, key, unicode);
if (key_result != BM_RUN_RESULT_RUNNING) {
return key_result;
}
enum bm_run_result pointer_result = bm_menu_run_with_pointer(menu, pointer, unicode);
if (pointer_result != BM_RUN_RESULT_RUNNING) {
return pointer_result;
}
return bm_menu_run_with_touch(menu, touch, unicode);
}
/* vim: set ts=8 sw=4 tw=0 :*/

View File

@ -201,6 +201,258 @@ keyboard_handle_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t ra
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,
@ -210,19 +462,46 @@ static const struct wl_keyboard_listener keyboard_listener = {
.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 ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->seat) {
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);
} else if (seat == input->seat && !(caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
}
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;
}
}

View File

@ -43,7 +43,9 @@ render(const struct bm_menu *menu)
}
}
if (wayland->input.code != wayland->input.last_code) {
if (wayland->input.code != wayland->input.last_code ||
wayland->input.touch_event.active ||
wayland->input.pointer_event.event_mask) {
wl_list_for_each(window, &wayland->windows, link) {
bm_wl_window_schedule_render(window);
}
@ -217,6 +219,96 @@ poll_key(const struct bm_menu *menu, unsigned int *unicode)
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)
{
@ -231,6 +323,34 @@ get_displayed_count(const struct bm_menu *menu)
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)
{
@ -447,7 +567,12 @@ 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;

View File

@ -5,6 +5,7 @@
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
#include <linux/input-event-codes.h>
#include "wlr-layer-shell-unstable-v1.h"
#include "xdg-output-unstable-v1.h"
@ -45,11 +46,46 @@ struct xkb {
xkb_mod_mask_t masks[MASK_LAST];
};
struct pointer_event {
uint32_t event_mask;
wl_fixed_t surface_x, surface_y;
uint32_t button, state;
uint32_t time;
uint32_t serial;
struct {
bool valid;
wl_fixed_t value;
int32_t discrete;
} axes[2];
uint32_t axis_source;
};
struct touch_point {
bool valid;
int32_t id;
uint32_t event_mask;
wl_fixed_t surface_x, surface_y;
wl_fixed_t surface_start_x, surface_start_y;
wl_fixed_t major, minor;
wl_fixed_t orientation;
};
struct touch_event {
uint32_t time;
uint32_t serial;
uint16_t active;
struct touch_point points[2];
};
struct input {
int *repeat_fd;
struct wl_seat *seat;
struct wl_keyboard *keyboard;
struct wl_pointer *pointer;
struct wl_touch *touch;
struct pointer_event pointer_event;
struct touch_event touch_event;
struct xkb xkb;
xkb_keysym_t sym;