From adc8734017644f44443db30e976cf03147c7c3c4 Mon Sep 17 00:00:00 2001
From: Micah N Gorrell <m@minego.net>
Date: Fri, 9 Feb 2024 17:08:20 -0700
Subject: [PATCH 1/3] Add support for touch screen input devices, and send the
 appropriate events to clients

Send notification of touch motition events even if there is no client to focus. This is important for swiping on an OSK.

Add support for touch screen input devices, and send the appropriate events to clients

Removed #ifdef around code that needs pointer constraints now that that is merged to upstream
---
 dwl.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 145 insertions(+)

diff --git a/dwl.c b/dwl.c
index 5867b0c..fe447fb 100644
--- a/dwl.c
+++ b/dwl.c
@@ -47,6 +47,7 @@
 #include <wlr/types/wlr_session_lock_v1.h>
 #include <wlr/types/wlr_single_pixel_buffer_v1.h>
 #include <wlr/types/wlr_subcompositor.h>
+#include <wlr/types/wlr_touch.h>
 #include <wlr/types/wlr_viewporter.h>
 #include <wlr/types/wlr_virtual_keyboard_v1.h>
 #include <wlr/types/wlr_virtual_pointer_v1.h>
@@ -161,6 +162,12 @@ typedef struct {
 	struct wl_listener key;
 } KeyboardGroup;
 
+typedef struct TouchGroup {
+	struct wl_list link;
+	struct wlr_touch *touch;
+	Monitor *m;
+} TouchGroup;
+
 typedef struct {
 	/* Must keep these three elements in this order */
 	unsigned int type; /* LayerShell */
@@ -264,7 +271,9 @@ static void createmon(struct wl_listener *listener, void *data);
 static void createnotify(struct wl_listener *listener, void *data);
 static void createpointer(struct wlr_pointer *pointer);
 static void createpointerconstraint(struct wl_listener *listener, void *data);
+static void createtouch(struct wlr_touch *touch);
 static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
+static void createtouch(struct wlr_touch *touch);
 static void cursorframe(struct wl_listener *listener, void *data);
 static void cursorwarptohint(void);
 static void destroydecoration(struct wl_listener *listener, void *data);
@@ -334,6 +343,10 @@ static void togglefloating(const Arg *arg);
 static void togglefullscreen(const Arg *arg);
 static void toggletag(const Arg *arg);
 static void toggleview(const Arg *arg);
+static void touchdown(struct wl_listener *listener, void *data);
+static void touchup(struct wl_listener *listener, void *data);
+static void touchframe(struct wl_listener *listener, void *data);
+static void touchmotion(struct wl_listener *listener, void *data);
 static void unlocksession(struct wl_listener *listener, void *data);
 static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
 static void unmapnotify(struct wl_listener *listener, void *data);
@@ -404,6 +417,7 @@ static struct wlr_output_layout *output_layout;
 static struct wlr_box sgeom;
 static struct wl_list mons;
 static Monitor *selmon;
+static struct wl_list touches;
 
 #ifdef XWAYLAND
 static void activatex11(struct wl_listener *listener, void *data);
@@ -1041,6 +1055,16 @@ createpointerconstraint(struct wl_listener *listener, void *data)
 			&pointer_constraint->destroy, destroypointerconstraint);
 }
 
+void
+createtouch(struct wlr_touch *wlr_touch)
+{
+	TouchGroup *touch = ecalloc(1, sizeof(TouchGroup));
+
+	touch->touch = wlr_touch;
+	wl_list_insert(&touches, &touch->link);
+	wlr_cursor_attach_input_device(cursor, &wlr_touch->base);
+}
+
 void
 cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
 {
@@ -1412,6 +1436,9 @@ inputdevice(struct wl_listener *listener, void *data)
 	case WLR_INPUT_DEVICE_POINTER:
 		createpointer(wlr_pointer_from_input_device(device));
 		break;
+	case WLR_INPUT_DEVICE_TOUCH:
+		createtouch(wlr_touch_from_input_device(device));
+		break;
 	default:
 		/* TODO handle other input device types */
 		break;
@@ -1424,6 +1451,8 @@ inputdevice(struct wl_listener *listener, void *data)
 	caps = WL_SEAT_CAPABILITY_POINTER;
 	if (!wl_list_empty(&kb_group.wlr_group->devices))
 		caps |= WL_SEAT_CAPABILITY_KEYBOARD;
+	if (!wl_list_empty(&touches))
+		caps |= WL_SEAT_CAPABILITY_TOUCH;
 	wlr_seat_set_capabilities(seat, caps);
 }
 
@@ -2431,6 +2460,13 @@ setup(void)
 	LISTEN_STATIC(&cursor->events.axis, axisnotify);
 	LISTEN_STATIC(&cursor->events.frame, cursorframe);
 
+	wl_list_init(&touches);
+
+	LISTEN_STATIC(&cursor->events.touch_down, touchdown);
+	LISTEN_STATIC(&cursor->events.touch_frame, touchframe);
+	LISTEN_STATIC(&cursor->events.touch_motion, touchmotion);
+	LISTEN_STATIC(&cursor->events.touch_up, touchup);
+
 	cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
 	LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape);
 
@@ -2647,6 +2683,115 @@ toggleview(const Arg *arg)
 	printstatus();
 }
 
+void
+touchdown(struct wl_listener *listener, void *data)
+{
+	struct wlr_touch_down_event *event = data;
+	double lx, ly;
+	double sx, sy;
+	struct wlr_surface *surface;
+	Client *c = NULL;
+	uint32_t serial = 0;
+	Monitor *m;
+
+	wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+
+	// Map the input to the appropriate output, to ensure that rotation is
+	// handled.
+	wl_list_for_each(m, &mons, link) {
+		if (m == NULL || m->wlr_output == NULL) {
+			continue;
+		}
+		if (event->touch->output_name != NULL && 0 != strcmp(event->touch->output_name, m->wlr_output->name)) {
+			continue;
+		}
+
+		wlr_cursor_map_input_to_output(cursor, &event->touch->base, m->wlr_output);
+	}
+
+	wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x, event->y, &lx, &ly);
+
+	/* Find the client under the pointer and send the event along. */
+	xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
+	// fprintf(stderr, "touch_down at %lf, %lf\n", lx, ly);
+
+	if (surface != NULL) {
+		serial = wlr_seat_touch_notify_down(seat, surface, event->time_msec, event->touch_id, sx, sy);
+	}
+
+	if (serial && wlr_seat_touch_num_points(seat) == 1) {
+		/* Emulate a mouse click if the touch event wasn't handled */
+		struct wlr_pointer_button_event *button_event = data;
+		struct wlr_pointer_motion_absolute_event *motion_event = data;
+		double dx, dy;
+
+		wlr_cursor_absolute_to_layout_coords(cursor, &motion_event->pointer->base, motion_event->x, motion_event->y, &lx, &ly);
+		wlr_cursor_warp_closest(cursor, &motion_event->pointer->base, lx, ly);
+		dx = lx - cursor->x;
+		dy = ly - cursor->y;
+		motionnotify(motion_event->time_msec, &motion_event->pointer->base, dx, dy, dx, dy);
+
+		button_event->button = BTN_LEFT;
+		button_event->state = WLR_BUTTON_PRESSED;
+		buttonpress(listener, button_event);
+	}
+}
+
+void
+touchup(struct wl_listener *listener, void *data)
+{
+	struct wlr_touch_up_event *event = data;
+
+	if (!wlr_seat_touch_get_point(seat, event->touch_id)) {
+		return;
+	}
+
+	if (wlr_seat_touch_num_points(seat) == 1) {
+		struct wlr_pointer_button_event *button_event = data;
+
+		button_event->button = BTN_LEFT;
+		button_event->state = WLR_BUTTON_RELEASED;
+		buttonpress(listener, button_event);
+	}
+
+	wlr_seat_touch_notify_up(seat, event->time_msec, event->touch_id);
+	wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+}
+
+void
+touchframe(struct wl_listener *listener, void *data)
+{
+	wlr_seat_touch_notify_frame(seat);
+	wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+}
+
+void
+touchmotion(struct wl_listener *listener, void *data)
+{
+	struct wlr_touch_motion_event *event = data;
+	double lx, ly;
+	double sx, sy;
+	struct wlr_surface *surface;
+	Client *c = NULL;
+
+	if (!wlr_seat_touch_get_point(seat, event->touch_id)) {
+		return;
+	}
+
+	wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x, event->y, &lx, &ly);
+	xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
+
+	if (c != NULL) {
+		wlr_seat_touch_point_focus(seat, surface, event->time_msec, event->touch_id, sx, sy);
+	} else {
+		wlr_seat_touch_point_clear_focus(seat, event->time_msec, event->touch_id);
+	}
+	wlr_seat_touch_notify_motion(seat, event->time_msec, event->touch_id, sx, sy);
+
+	wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+}
+
+
 void
 unlocksession(struct wl_listener *listener, void *data)
 {
-- 
2.44.0


From c2e4ff7253f33c80552abe9126e3c57d0aa23560 Mon Sep 17 00:00:00 2001
From: Micah N Gorrell <m@minego.net>
Date: Thu, 28 Mar 2024 11:25:59 -0600
Subject: [PATCH 2/3] Removed debug

---
 dwl.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/dwl.c b/dwl.c
index fe447fb..c26c581 100644
--- a/dwl.c
+++ b/dwl.c
@@ -2713,7 +2713,6 @@ touchdown(struct wl_listener *listener, void *data)
 
 	/* Find the client under the pointer and send the event along. */
 	xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
-	// fprintf(stderr, "touch_down at %lf, %lf\n", lx, ly);
 
 	if (surface != NULL) {
 		serial = wlr_seat_touch_notify_down(seat, surface, event->time_msec, event->touch_id, sx, sy);
-- 
2.44.0


From ae64e0c3b51c8600de7c081034ea267c08134635 Mon Sep 17 00:00:00 2001
From: anabasis <anabasis@noreply.codeberg.org>
Date: Sat, 11 May 2024 20:19:18 -0400
Subject: [PATCH 3/3] fix bug and focus client according to sloppyfocus

---
 dwl.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/dwl.c b/dwl.c
index c26c581..75b44d7 100644
--- a/dwl.c
+++ b/dwl.c
@@ -2713,6 +2713,8 @@ touchdown(struct wl_listener *listener, void *data)
 
 	/* Find the client under the pointer and send the event along. */
 	xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
+	if (sloppyfocus)
+		focusclient(c, 0);
 
 	if (surface != NULL) {
 		serial = wlr_seat_touch_notify_down(seat, surface, event->time_msec, event->touch_id, sx, sy);
@@ -2780,9 +2782,13 @@ touchmotion(struct wl_listener *listener, void *data)
 	wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x, event->y, &lx, &ly);
 	xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
 
-	if (c != NULL) {
+	if (c != NULL && surface != NULL) {
+		if (sloppyfocus)
+			focusclient(c, 0);
 		wlr_seat_touch_point_focus(seat, surface, event->time_msec, event->touch_id, sx, sy);
 	} else {
+		if (sloppyfocus)
+			focusclient(NULL, 0);
 		wlr_seat_touch_point_clear_focus(seat, event->time_msec, event->touch_id);
 	}
 	wlr_seat_touch_notify_motion(seat, event->time_msec, event->touch_id, sx, sy);
-- 
2.44.0

