commit c980f7fe20b16361f08272cd1d3702f7aee0f477
parent 2c51676436546ae4217ed023e97832c13db1d52e
Author: Daniel Barlow <dan@telent.net>
Date: Fri, 8 Jul 2022 22:50:45 +0100
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
Diffstat:
5 files changed, 221 insertions(+), 0 deletions(-)
diff --git a/kiwmi/include/input/cursor.h b/kiwmi/include/input/cursor.h
@@ -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;
diff --git a/kiwmi/include/input/input.h b/kiwmi/include/input/input.h
@@ -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;
diff --git a/kiwmi/kiwmi/input/cursor.c b/kiwmi/kiwmi/input/cursor.c
@@ -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>
@@ -120,6 +121,130 @@ cursor_motion_notify(struct wl_listener *listener, void *data)
}
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)
{
struct kiwmi_cursor *cursor =
@@ -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;
diff --git a/kiwmi/kiwmi/input/input.c b/kiwmi/kiwmi/input/input.c
@@ -29,6 +29,13 @@ new_pointer(struct kiwmi_input *input, struct wlr_input_device *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)
{
struct kiwmi_server *server = wl_container_of(input, server, input);
@@ -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);
}
diff --git a/kiwmi/kiwmi/luak/kiwmi_cursor.c b/kiwmi/kiwmi/luak/kiwmi_cursor.c
@@ -163,6 +163,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)
{
struct kiwmi_lua_callback *lc = wl_container_of(listener, lc, listener);
@@ -268,6 +298,31 @@ l_kiwmi_cursor_on_motion(lua_State *L)
}
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)
{
struct kiwmi_object *obj =
@@ -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},
};