initial support for touch events

Calls lua handlers, then passes the event to the appropriate client

Doesn't do pointer emulation (unlike sway) because in the
GNOME/Gtk worldview that's done client-side, so my assumption is
anything else that wants to co-exist with GNOME also has to
do it client-side

Still to do:

- verify whether return value of the lua handler will affect whether
event passed to child

- clean up the hacky int we use to track whether to set touch
seat capability
main
Daniel Barlow 2022-07-08 22:50:45 +01:00
parent 2c51676436
commit c980f7fe20
5 changed files with 221 additions and 0 deletions

View File

@ -39,6 +39,10 @@ struct kiwmi_cursor {
struct wl_listener cursor_button;
struct wl_listener cursor_axis;
struct wl_listener cursor_frame;
struct wl_listener cursor_touch_up;
struct wl_listener cursor_touch_down;
struct wl_listener cursor_touch_motion;
struct wl_listener cursor_touch_frame;
struct {
struct wl_signal button_down;
@ -46,6 +50,7 @@ struct kiwmi_cursor {
struct wl_signal destroy;
struct wl_signal motion;
struct wl_signal scroll;
struct wl_signal touch;
} events;
};
@ -61,6 +66,14 @@ struct kiwmi_cursor_motion_event {
double newy;
};
struct kiwmi_cursor_touch_event {
char *event;
int id;
double x;
double y;
bool handled;
};
struct kiwmi_cursor_scroll_event {
const char *device_name;
bool is_vertical;

View File

@ -15,6 +15,7 @@ struct kiwmi_input {
struct wl_listener new_input;
struct kiwmi_cursor *cursor;
struct kiwmi_seat *seat;
int touchpads;
struct {
struct wl_signal keyboard_new;

View File

@ -14,6 +14,7 @@
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/util/log.h>
@ -119,6 +120,130 @@ cursor_motion_notify(struct wl_listener *listener, void *data)
process_cursor_motion(server, event->time_msec);
}
static void
cursor_touch_down_notify(struct wl_listener *listener, void *data)
{
struct kiwmi_cursor *cursor =
wl_container_of(listener, cursor, cursor_touch_down);
struct kiwmi_server *server = cursor->server;
struct kiwmi_desktop *desktop = &server->desktop;
struct wlr_event_touch_down *event = data;
struct kiwmi_input *input = &server->input;
struct wlr_seat *seat = input->seat->seat;
struct wlr_surface *surface = NULL;
/* FIXME figure out what scaling should be done here.
* Does the touch co-ordinate system map onto a single output
* (e.g. phone screen) or onto the entire layout (tablet,
* maybe?)
*/
double lx = 720 * event->x;
double ly = 1440 * event->y;
double sx, sy;
struct kiwmi_view *view = view_at(
desktop,
lx, ly,
&surface,
&sx, &sy);
wlr_log(WLR_DEBUG, "view %x surface %x %f,%f %f,%f\n",
view, surface, lx, ly, sx, sy);
/* we send the event to lua with 0..1 co-ordinates, because
* it may not be over any surface
*/
struct kiwmi_cursor_touch_event new_event = {
.event = "down",
.id = event->touch_id,
.x = event->x,
.y = event->y,
};
wl_signal_emit(&cursor->events.touch, &new_event);
if(!new_event.handled &&
surface &&
wlr_surface_accepts_touch(seat, surface)) {
wlr_log(WLR_DEBUG, "surface %x %f %f\n",
surface, sx, sy);
wlr_seat_touch_notify_down(seat, surface, event->time_msec,
event->touch_id, sx, sy);
}
}
static void
cursor_touch_up_notify(struct wl_listener *listener, void *data)
{
struct kiwmi_cursor *cursor =
wl_container_of(listener, cursor, cursor_touch_up);
struct kiwmi_server *server = cursor->server;
struct wlr_event_touch_up *event = data;
struct kiwmi_input *input = &server->input;
struct wlr_seat *seat = input->seat->seat;
struct kiwmi_cursor_touch_event new_event = {
.event = "up",
.id = event->touch_id,
};
wl_signal_emit(&cursor->events.touch, &new_event);
if(!new_event.handled) {
wlr_seat_touch_notify_up(seat, event->time_msec, event->touch_id);
}
}
static void
cursor_touch_motion_notify(struct wl_listener *listener, void *data)
{
struct kiwmi_cursor *cursor =
wl_container_of(listener, cursor, cursor_touch_motion);
struct kiwmi_server *server = cursor->server;
struct wlr_event_touch_motion *event = data;
struct kiwmi_input *input = &server->input;
struct wlr_seat *seat = input->seat->seat;
struct kiwmi_cursor_touch_event new_event = {
.event = "motion",
.id = event->touch_id,
.x = event->x,
.y = event->y,
};
wl_signal_emit(&cursor->events.touch, &new_event);
if(!new_event.handled) {
/* UNSURE: should we still send this even if the touch_down
* didn't get sent because the surface doesn't accept
* touch? */
wlr_seat_touch_notify_motion(seat, event->time_msec,
event->touch_id, event->x, event->y);
}
}
static void
cursor_touch_frame_notify(struct wl_listener *listener, void *data)
{
struct kiwmi_cursor *cursor =
wl_container_of(listener, cursor, cursor_touch_frame);
struct kiwmi_server *server = cursor->server;
struct kiwmi_input *input = &server->input;
struct wlr_seat *seat = input->seat->seat;
struct kiwmi_cursor_touch_event new_event = {
.event = "frame",
};
wl_signal_emit(&cursor->events.touch, &new_event);
if(!new_event.handled) {
wlr_seat_touch_notify_frame(seat);
}
}
static void
cursor_motion_absolute_notify(struct wl_listener *listener, void *data)
{
@ -252,10 +377,23 @@ cursor_create(
cursor->cursor_frame.notify = cursor_frame_notify;
wl_signal_add(&cursor->cursor->events.frame, &cursor->cursor_frame);
cursor->cursor_touch_down.notify = cursor_touch_down_notify;
wl_signal_add(&cursor->cursor->events.touch_down, &cursor->cursor_touch_down);
cursor->cursor_touch_up.notify = cursor_touch_up_notify;
wl_signal_add(&cursor->cursor->events.touch_up, &cursor->cursor_touch_up);
cursor->cursor_touch_motion.notify = cursor_touch_motion_notify;
wl_signal_add(&cursor->cursor->events.touch_motion, &cursor->cursor_touch_motion);
cursor->cursor_touch_frame.notify = cursor_touch_frame_notify;
wl_signal_add(&cursor->cursor->events.touch_frame, &cursor->cursor_touch_frame);
wl_signal_init(&cursor->events.button_down);
wl_signal_init(&cursor->events.button_up);
wl_signal_init(&cursor->events.destroy);
wl_signal_init(&cursor->events.motion);
wl_signal_init(&cursor->events.touch);
wl_signal_init(&cursor->events.scroll);
return cursor;

View File

@ -28,6 +28,13 @@ new_pointer(struct kiwmi_input *input, struct wlr_input_device *device)
wlr_cursor_attach_input_device(input->cursor->cursor, device);
}
static void
new_touch(struct kiwmi_input *input, struct wlr_input_device *device)
{
wlr_cursor_attach_input_device(input->cursor->cursor, device);
input->touchpads++;
}
static void
new_keyboard(struct kiwmi_input *input, struct wlr_input_device *device)
{
@ -53,6 +60,9 @@ new_input_notify(struct wl_listener *listener, void *data)
case WLR_INPUT_DEVICE_POINTER:
new_pointer(input, device);
break;
case WLR_INPUT_DEVICE_TOUCH:
new_touch(input, device);
break;
case WLR_INPUT_DEVICE_KEYBOARD:
new_keyboard(input, device);
break;
@ -65,6 +75,9 @@ new_input_notify(struct wl_listener *listener, void *data)
if (!wl_list_empty(&input->keyboards)) {
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
}
if(input->touchpads) {
caps |= WL_SEAT_CAPABILITY_TOUCH;
}
wlr_seat_set_capabilities(input->seat->seat, caps);
}

View File

@ -162,6 +162,36 @@ kiwmi_cursor_on_motion_notify(struct wl_listener *listener, void *data)
}
}
static void
kiwmi_cursor_on_touch_notify(struct wl_listener *listener, void *data)
{
struct kiwmi_lua_callback *lc = wl_container_of(listener, lc, listener);
struct kiwmi_server *server = lc->server;
lua_State *L = server->lua->L;
struct kiwmi_cursor_touch_event *event = data;
lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref);
lua_newtable(L);
lua_pushnumber(L, event->x);
lua_setfield(L, -2, "x");
lua_pushnumber(L, event->y);
lua_setfield(L, -2, "y");
lua_pushnumber(L, event->id);
lua_setfield(L, -2, "id");
lua_pushstring(L, event->event);
lua_setfield(L, -2, "name");
if (lua_pcall(L, 1, 0, 0)) {
wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1));
lua_pop(L, 1);
}
}
static void
kiwmi_cursor_on_scroll_notify(struct wl_listener *listener, void *data)
{
@ -267,6 +297,31 @@ l_kiwmi_cursor_on_motion(lua_State *L)
return 0;
}
static int
l_kiwmi_cursor_on_touch(lua_State *L)
{
struct kiwmi_object *obj =
*(struct kiwmi_object **)luaL_checkudata(L, 1, "kiwmi_cursor");
luaL_checktype(L, 2, LUA_TFUNCTION);
struct kiwmi_cursor *cursor = obj->object;
struct kiwmi_server *server = cursor->server;
lua_pushcfunction(L, luaK_kiwmi_lua_callback_new);
lua_pushlightuserdata(L, server);
lua_pushvalue(L, 2);
lua_pushlightuserdata(L, kiwmi_cursor_on_touch_notify);
lua_pushlightuserdata(L, &cursor->events.touch);
lua_pushlightuserdata(L, obj);
if (lua_pcall(L, 5, 0, 0)) {
wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1));
return 0;
}
return 0;
}
static int
l_kiwmi_cursor_on_scroll(lua_State *L)
{
@ -296,6 +351,7 @@ static const luaL_Reg kiwmi_cursor_events[] = {
{"button_down", l_kiwmi_cursor_on_button_down},
{"button_up", l_kiwmi_cursor_on_button_up},
{"motion", l_kiwmi_cursor_on_motion},
{"touch", l_kiwmi_cursor_on_touch},
{"scroll", l_kiwmi_cursor_on_scroll},
{NULL, NULL},
};