diff --git a/patches/tablet-and-touch/README.md b/patches/tablet-and-touch/README.md index f458bcb..426ae81 100644 --- a/patches/tablet-and-touch/README.md +++ b/patches/tablet-and-touch/README.md @@ -1,9 +1,13 @@ ### Description -This combines [touch-input](../touch-input) and [tablet-input](../tablet-input) into a single appliable patch. +This combines +[tablet-input](../tablet-input) and +[touch-input](../touch-input) +into a single appliable patch. The two patches modify similar code areas in `dwl.c` and will conflict if one attempts to direcly apply both. ### Download -- [main 2026-02-17](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tablet-and-touch/tablet-and-touch.patch) +- [tablet-and-touch-wlroots-next-f4249db.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tablet-and-touch/tablet-and-touch-wlroots-next-f4249db.patch) +- [tablet-and-touch-0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tablet-and-touch/tablet-and-touch-0.8.patch) ### Authors - [fauxmight](https://codeberg.org/fauxmight) diff --git a/patches/tablet-and-touch/tablet-and-touch-0.8.patch b/patches/tablet-and-touch/tablet-and-touch-0.8.patch new file mode 100644 index 0000000..16ece16 --- /dev/null +++ b/patches/tablet-and-touch/tablet-and-touch-0.8.patch @@ -0,0 +1,584 @@ +From f0f797f8abebc4624c7e6bdfbb1ec2a3122f3914 Mon Sep 17 00:00:00 2001 +From: A Frederick Christensen +Date: Thu, 26 Feb 2026 23:20:03 -0600 +Subject: [PATCH] Apply tablet-and-touch patch + +--- + Makefile | 6 +- + config.def.h | 1 + + dwl.c | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 404 insertions(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 578194f..e0d1835 100644 +--- a/Makefile ++++ b/Makefile +@@ -21,7 +21,8 @@ dwl: dwl.o util.o + $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ + dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \ + pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \ +- wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h ++ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h \ ++ tablet-v2-protocol.h + util.o: util.c util.h + + # wayland-scanner is a tool which generates C headers and rigging for Wayland +@@ -45,6 +46,9 @@ wlr-output-power-management-unstable-v1-protocol.h: + xdg-shell-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ ++tablet-v2-protocol.h: ++ $(WAYLAND_SCANNER) server-header \ ++ $(WAYLAND_PROTOCOLS)/unstable/tablet/tablet-unstable-v2.xml $@ + + config.h: + cp config.def.h $@ +diff --git a/config.def.h b/config.def.h +index 8a6eda0..1f20dfd 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -4,6 +4,7 @@ + ((hex >> 8) & 0xFF) / 255.0f, \ + (hex & 0xFF) / 255.0f } + /* appearance */ ++static const int tabletmaptosurface = 0; /* map tablet input to surface(1) or monitor(0) */ + static const int sloppyfocus = 1; /* focus follows mouse */ + static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ + static const unsigned int borderpx = 1; /* border pixel of windows */ +diff --git a/dwl.c b/dwl.c +index 44f3ad9..5ed467d 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -51,6 +51,10 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + #include + #include + #include +@@ -161,6 +165,12 @@ typedef struct { + struct wl_listener destroy; + } KeyboardGroup; + ++typedef struct TouchGroup { ++ struct wl_list link; ++ struct wlr_touch *touch; ++ Monitor *m; ++} TouchGroup; ++ + typedef struct { + /* Must keep this field first */ + unsigned int type; /* LayerShell */ +@@ -268,7 +278,10 @@ 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 createpopup(struct wl_listener *listener, void *data); ++static void createtablet(struct wlr_input_device *device); ++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); +@@ -281,6 +294,9 @@ static void destroynotify(struct wl_listener *listener, void *data); + static void destroypointerconstraint(struct wl_listener *listener, void *data); + static void destroysessionlock(struct wl_listener *listener, void *data); + static void destroykeyboardgroup(struct wl_listener *listener, void *data); ++static void destroytablet(struct wl_listener *listener, void *data); ++static void destroytabletsurfacenotify(struct wl_listener *listener, void *data); ++static void destroytablettool(struct wl_listener *listener, void *data); + static Monitor *dirtomon(enum wlr_direction dir); + static void focusclient(Client *c, int lift); + static void focusmon(const Arg *arg); +@@ -333,11 +349,20 @@ static void spawn(const Arg *arg); + static void startdrag(struct wl_listener *listener, void *data); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); ++static void tablettoolmotion(struct wlr_tablet_v2_tablet_tool *tool, bool change_x, bool change_y, double x, double y, double dx, double dy); ++static void tablettoolproximity(struct wl_listener *listener, void *data); ++static void tablettoolaxis(struct wl_listener *listener, void *data); ++static void tablettoolbutton(struct wl_listener *listener, void *data); ++static void tablettooltip(struct wl_listener *listener, void *data); + static void tile(Monitor *m); + 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); +@@ -390,6 +415,13 @@ static struct wlr_pointer_constraint_v1 *active_constraint; + static struct wlr_cursor *cursor; + static struct wlr_xcursor_manager *cursor_mgr; + ++static struct wlr_tablet_manager_v2 *tablet_mgr; ++static struct wlr_tablet_v2_tablet *tablet = NULL; ++static struct wlr_tablet_v2_tablet_tool *tablet_tool = NULL; ++static struct wlr_tablet_v2_tablet_pad *tablet_pad = NULL; ++static struct wlr_surface *tablet_curr_surface = NULL; ++static struct wl_listener destroy_tablet_surface_listener = {.notify = destroytabletsurfacenotify}; ++ + static struct wlr_scene_rect *root_bg; + static struct wlr_session_lock_manager_v1 *session_lock_mgr; + static struct wlr_scene_rect *locked_bg; +@@ -405,6 +437,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; + + /* global event handlers */ + static struct wl_listener cursor_axis = {.notify = axisnotify}; +@@ -412,6 +445,12 @@ static struct wl_listener cursor_button = {.notify = buttonpress}; + static struct wl_listener cursor_frame = {.notify = cursorframe}; + static struct wl_listener cursor_motion = {.notify = motionrelative}; + static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; ++static struct wl_listener tablet_device_destroy = {.notify = destroytablet}; ++static struct wl_listener tablet_tool_axis = {.notify = tablettoolaxis}; ++static struct wl_listener tablet_tool_button = {.notify = tablettoolbutton}; ++static struct wl_listener tablet_tool_destroy = {.notify = destroytablettool}; ++static struct wl_listener tablet_tool_proximity = {.notify = tablettoolproximity}; ++static struct wl_listener tablet_tool_tip = {.notify = tablettooltip}; + static struct wl_listener gpu_reset = {.notify = gpureset}; + static struct wl_listener layout_change = {.notify = updatemons}; + static struct wl_listener new_idle_inhibitor = {.notify = createidleinhibitor}; +@@ -434,6 +473,10 @@ static struct wl_listener request_set_sel = {.notify = setsel}; + static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape}; + static struct wl_listener request_start_drag = {.notify = requeststartdrag}; + static struct wl_listener start_drag = {.notify = startdrag}; ++static struct wl_listener touch_down = {.notify = touchdown}; ++static struct wl_listener touch_frame = {.notify = touchframe}; ++static struct wl_listener touch_motion = {.notify = touchmotion}; ++static struct wl_listener touch_up = {.notify = touchup}; + static struct wl_listener new_session_lock = {.notify = locksession}; + + #ifdef XWAYLAND +@@ -781,6 +824,10 @@ cleanuplisteners(void) + wl_list_remove(&request_set_cursor_shape.link); + wl_list_remove(&request_start_drag.link); + wl_list_remove(&start_drag.link); ++ wl_list_remove(&touch_down.link); ++ wl_list_remove(&touch_frame.link); ++ wl_list_remove(&touch_motion.link); ++ wl_list_remove(&touch_up.link); + wl_list_remove(&new_session_lock.link); + #ifdef XWAYLAND + wl_list_remove(&new_xwayland_surface.link); +@@ -1199,6 +1246,38 @@ createpopup(struct wl_listener *listener, void *data) + LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); + } + ++void ++createtablet(struct wlr_input_device *device) ++{ ++ if (!tablet) { ++ struct libinput_device *device_handle = NULL; ++ if (!wlr_input_device_is_libinput(device) || ++ !(device_handle = wlr_libinput_get_device_handle(device))) ++ return; ++ ++ tablet = wlr_tablet_create(tablet_mgr, seat, device); ++ wl_signal_add(&tablet->wlr_device->events.destroy, &tablet_device_destroy); ++ if (libinput_device_config_send_events_get_modes(device_handle)) { ++ libinput_device_config_send_events_set_mode(device_handle, send_events_mode); ++ wlr_cursor_attach_input_device(cursor, device); ++ } ++ } else if (device == tablet->wlr_device) { ++ wlr_log(WLR_ERROR, "createtablet: duplicate device"); ++ } else { ++ wlr_log(WLR_ERROR, "createtablet: already have one tablet"); ++ } ++} ++ ++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) + { +@@ -1383,6 +1462,29 @@ destroykeyboardgroup(struct wl_listener *listener, void *data) + free(group); + } + ++void ++destroytablet(struct wl_listener *listener, void *data) ++{ ++ wl_list_remove(&tablet_device_destroy.link); ++ wlr_cursor_detach_input_device(cursor, tablet->wlr_device); ++ tablet = NULL; ++} ++ ++void ++destroytabletsurfacenotify(struct wl_listener *listener, void *data) ++{ ++ if (tablet_curr_surface) ++ wl_list_remove(&destroy_tablet_surface_listener.link); ++ tablet_curr_surface = NULL; ++} ++ ++void ++destroytablettool(struct wl_listener *listener, void *data) ++{ ++ destroytabletsurfacenotify(NULL, NULL); ++ tablet_tool = NULL; ++} ++ + Monitor * + dirtomon(enum wlr_direction dir) + { +@@ -1590,6 +1692,15 @@ inputdevice(struct wl_listener *listener, void *data) + case WLR_INPUT_DEVICE_POINTER: + createpointer(wlr_pointer_from_input_device(device)); + break; ++ case WLR_INPUT_DEVICE_TABLET: ++ createtablet(device); ++ break; ++ case WLR_INPUT_DEVICE_TABLET_PAD: ++ tablet_pad = wlr_tablet_pad_create(tablet_mgr, seat, device); ++ break; ++ case WLR_INPUT_DEVICE_TOUCH: ++ createtouch(wlr_touch_from_input_device(device)); ++ break; + default: + /* TODO handle other input device types */ + break; +@@ -1602,6 +1713,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); + } + +@@ -2585,6 +2698,8 @@ setup(void) + + relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); + ++ tablet_mgr = wlr_tablet_v2_create(dpy); ++ + /* + * Creates a cursor, which is a wlroots utility for tracking the cursor + * image shown on screen. +@@ -2614,6 +2729,18 @@ setup(void) + wl_signal_add(&cursor->events.button, &cursor_button); + wl_signal_add(&cursor->events.axis, &cursor_axis); + wl_signal_add(&cursor->events.frame, &cursor_frame); ++ wl_signal_add(&cursor->events.tablet_tool_proximity, &tablet_tool_proximity); ++ wl_signal_add(&cursor->events.tablet_tool_axis, &tablet_tool_axis); ++ wl_signal_add(&cursor->events.tablet_tool_button, &tablet_tool_button); ++ wl_signal_add(&cursor->events.tablet_tool_tip, &tablet_tool_tip); ++ ++ ++ wl_list_init(&touches); ++ ++ wl_signal_add(&cursor->events.touch_down, &touch_down); ++ wl_signal_add(&cursor->events.touch_frame, &touch_frame); ++ wl_signal_add(&cursor->events.touch_motion, &touch_motion); ++ wl_signal_add(&cursor->events.touch_up, &touch_up); + + cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); + wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape); +@@ -2709,6 +2836,163 @@ tagmon(const Arg *arg) + setmon(sel, dirtomon(arg->i), 0); + } + ++void ++tabletapplymap(double x, double y, struct wlr_input_device *dev) ++{ ++ Client *p; ++ struct wlr_box geom = {0}; ++ if (tabletmaptosurface && tablet_curr_surface) { ++ toplevel_from_wlr_surface(tablet_curr_surface, &p, NULL); ++ if (p) { ++ for (; client_get_parent(p); p = client_get_parent(p)); ++ geom.x = p->geom.x + p->bw; ++ geom.y = p->geom.y + p->bw; ++ geom.width = p->geom.width - 2 * p->bw; ++ geom.height = p->geom.height - 2 * p->bw; ++ } ++ } ++ wlr_cursor_map_input_to_region(cursor, dev, &geom); ++ wlr_cursor_map_input_to_output(cursor, dev, selmon->wlr_output); ++} ++ ++void ++tablettoolmotion(struct wlr_tablet_v2_tablet_tool *tool, bool change_x, bool change_y, ++ double x, double y, double dx, double dy) ++{ ++ struct wlr_surface *surface = NULL; ++ double sx, sy; ++ ++ if (!change_x && !change_y) ++ return; ++ ++ tabletapplymap(x, y, tablet->wlr_device); ++ ++ // TODO: apply constraints ++ switch (tablet_tool->wlr_tool->type) { ++ case WLR_TABLET_TOOL_TYPE_LENS: ++ case WLR_TABLET_TOOL_TYPE_MOUSE: ++ wlr_cursor_move(cursor, tablet->wlr_device, dx, dy); ++ break; ++ default: ++ wlr_cursor_warp_absolute(cursor, tablet->wlr_device, change_x ? x : NAN, change_y ? y : NAN); ++ break; ++ } ++ ++ motionnotify(0, NULL, 0, 0, 0, 0); ++ ++ xytonode(cursor->x, cursor->y, &surface, NULL, NULL, &sx, &sy); ++ if (surface && !wlr_surface_accepts_tablet_v2(surface, tablet)) ++ surface = NULL; ++ ++ if (surface != tablet_curr_surface) { ++ if (tablet_curr_surface) { ++ // TODO: wait until all buttons released before leaving ++ if (tablet_tool) ++ wlr_tablet_v2_tablet_tool_notify_proximity_out(tablet_tool); ++ if (tablet_pad) ++ wlr_tablet_v2_tablet_pad_notify_leave(tablet_pad, tablet_curr_surface); ++ wl_list_remove(&destroy_tablet_surface_listener.link); ++ } ++ if (surface) { ++ if (tablet_pad) ++ wlr_tablet_v2_tablet_pad_notify_enter(tablet_pad, tablet, surface); ++ if (tablet_tool) ++ wlr_tablet_v2_tablet_tool_notify_proximity_in(tablet_tool, tablet, surface); ++ wl_signal_add(&surface->events.destroy, &destroy_tablet_surface_listener); ++ } ++ tablet_curr_surface = surface; ++ } ++ ++ if (surface) ++ wlr_tablet_v2_tablet_tool_notify_motion(tablet_tool, sx, sy); ++} ++ ++void ++tablettoolproximity(struct wl_listener *listener, void *data) ++{ ++ struct wlr_tablet_tool_proximity_event *event = data; ++ struct wlr_tablet_tool *tool = event->tool; ++ ++ if (!tablet_tool) { ++ tablet_tool = wlr_tablet_tool_create(tablet_mgr, seat, tool); ++ wl_signal_add(&tablet_tool->wlr_tool->events.destroy, &tablet_tool_destroy); ++ wl_signal_add(&tablet_tool->events.set_cursor, &request_cursor); ++ } ++ ++ switch (event->state) { ++ case WLR_TABLET_TOOL_PROXIMITY_OUT: ++ wlr_tablet_v2_tablet_tool_notify_proximity_out(tablet_tool); ++ destroytabletsurfacenotify(NULL, NULL); ++ break; ++ case WLR_TABLET_TOOL_PROXIMITY_IN: ++ tablettoolmotion(tablet_tool, true, true, event->x, event->y, 0, 0); ++ break; ++ } ++} ++ ++double tilt_x = 0; ++double tilt_y = 0; ++ ++void ++tablettoolaxis(struct wl_listener *listener, void *data) ++{ ++ struct wlr_tablet_tool_axis_event *event = data; ++ ++ tablettoolmotion(tablet_tool, ++ event->updated_axes & WLR_TABLET_TOOL_AXIS_X, ++ event->updated_axes & WLR_TABLET_TOOL_AXIS_Y, ++ event->x, event->y, event->dx, event->dy); ++ ++ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE) ++ wlr_tablet_v2_tablet_tool_notify_pressure(tablet_tool, event->pressure); ++ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE) ++ wlr_tablet_v2_tablet_tool_notify_distance(tablet_tool, event->distance); ++ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X) ++ tilt_x = event->tilt_x; ++ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y) ++ tilt_y = event->tilt_y; ++ if (event->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y)) ++ wlr_tablet_v2_tablet_tool_notify_tilt(tablet_tool, tilt_x, tilt_y); ++ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION) ++ wlr_tablet_v2_tablet_tool_notify_rotation(tablet_tool, event->rotation); ++ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER) ++ wlr_tablet_v2_tablet_tool_notify_slider(tablet_tool, event->slider); ++ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL) ++ wlr_tablet_v2_tablet_tool_notify_wheel(tablet_tool, event->wheel_delta, 0); ++} ++ ++void ++tablettoolbutton(struct wl_listener *listener, void *data) ++{ ++ struct wlr_tablet_tool_button_event *event = data; ++ wlr_tablet_v2_tablet_tool_notify_button(tablet_tool, event->button, ++ (enum zwp_tablet_pad_v2_button_state)event->state); ++} ++ ++void ++tablettooltip(struct wl_listener *listener, void *data) ++{ ++ struct wlr_tablet_tool_tip_event *event = data; ++ ++ if (!tablet_curr_surface) { ++ struct wlr_pointer_button_event fakeptrbtnevent = { ++ .button = BTN_LEFT, ++ .state = event->state == WLR_TABLET_TOOL_TIP_UP ? ++ WL_POINTER_BUTTON_STATE_RELEASED : WL_POINTER_BUTTON_STATE_PRESSED, ++ .time_msec = event->time_msec, ++ }; ++ buttonpress(NULL, (void *)&fakeptrbtnevent); ++ } ++ ++ if (event->state == WLR_TABLET_TOOL_TIP_UP) { ++ wlr_tablet_v2_tablet_tool_notify_up(tablet_tool); ++ return; ++ } ++ ++ wlr_tablet_v2_tablet_tool_notify_down(tablet_tool); ++ wlr_tablet_tool_v2_start_implicit_grab(tablet_tool); ++} ++ + void + tile(Monitor *m) + { +@@ -2787,6 +3071,120 @@ 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); ++ if (sloppyfocus) ++ focusclient(c, 0); ++ ++ 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 = WL_POINTER_BUTTON_STATE_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 = WL_POINTER_BUTTON_STATE_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 && 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); ++ ++ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); ++} ++ ++ + void + unlocksession(struct wl_listener *listener, void *data) + { +-- +2.52.0 + diff --git a/patches/tablet-and-touch/tablet-and-touch.patch b/patches/tablet-and-touch/tablet-and-touch-wlroots-next-f4249db.patch similarity index 94% rename from patches/tablet-and-touch/tablet-and-touch.patch rename to patches/tablet-and-touch/tablet-and-touch-wlroots-next-f4249db.patch index 932f68d..bf577d4 100644 --- a/patches/tablet-and-touch/tablet-and-touch.patch +++ b/patches/tablet-and-touch/tablet-and-touch-wlroots-next-f4249db.patch @@ -1,7 +1,7 @@ -From f74eef46583348237814b4559c5e00b7d2ed5761 Mon Sep 17 00:00:00 2001 +From 78eda59b86ca01188fd645fe4062dda75d60acb1 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen -Date: Tue, 17 Feb 2026 08:33:50 -0600 -Subject: [PATCH] Apply both tablet-input and touch-input patches +Date: Thu, 26 Feb 2026 23:23:49 -0600 +Subject: [PATCH] Apply tablet-and-touch patch --- Makefile | 6 +- @@ -46,7 +46,7 @@ index 8a6eda0..1f20dfd 100644 static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ static const unsigned int borderpx = 1; /* border pixel of windows */ diff --git a/dwl.c b/dwl.c -index 320910d..4e32240 100644 +index 8a9715d..6dc462a 100644 --- a/dwl.c +++ b/dwl.c @@ -52,6 +52,10 @@ @@ -60,7 +60,7 @@ index 320910d..4e32240 100644 #include #include #include -@@ -162,6 +166,12 @@ typedef struct { +@@ -163,6 +167,12 @@ typedef struct { struct wl_listener destroy; } KeyboardGroup; @@ -73,7 +73,7 @@ index 320910d..4e32240 100644 typedef struct { /* Must keep this field first */ unsigned int type; /* LayerShell */ -@@ -269,7 +279,10 @@ static void createnotify(struct wl_listener *listener, void *data); +@@ -270,7 +280,10 @@ 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 createpopup(struct wl_listener *listener, void *data); @@ -84,7 +84,7 @@ index 320910d..4e32240 100644 static void cursorframe(struct wl_listener *listener, void *data); static void cursorwarptohint(void); static void destroydecoration(struct wl_listener *listener, void *data); -@@ -282,6 +295,9 @@ static void destroynotify(struct wl_listener *listener, void *data); +@@ -283,6 +296,9 @@ static void destroynotify(struct wl_listener *listener, void *data); static void destroypointerconstraint(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data); static void destroykeyboardgroup(struct wl_listener *listener, void *data); @@ -94,7 +94,7 @@ index 320910d..4e32240 100644 static Monitor *dirtomon(enum wlr_direction dir); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); -@@ -334,11 +350,20 @@ static void spawn(const Arg *arg); +@@ -335,11 +351,20 @@ static void spawn(const Arg *arg); static void startdrag(struct wl_listener *listener, void *data); static void tag(const Arg *arg); static void tagmon(const Arg *arg); @@ -115,7 +115,7 @@ index 320910d..4e32240 100644 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); -@@ -391,6 +416,13 @@ static struct wlr_pointer_constraint_v1 *active_constraint; +@@ -392,6 +417,13 @@ static struct wlr_pointer_constraint_v1 *active_constraint; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; @@ -129,7 +129,7 @@ index 320910d..4e32240 100644 static struct wlr_scene_rect *root_bg; static struct wlr_session_lock_manager_v1 *session_lock_mgr; static struct wlr_scene_rect *locked_bg; -@@ -406,6 +438,7 @@ static struct wlr_output_layout *output_layout; +@@ -407,6 +439,7 @@ static struct wlr_output_layout *output_layout; static struct wlr_box sgeom; static struct wl_list mons; static Monitor *selmon; @@ -137,7 +137,7 @@ index 320910d..4e32240 100644 /* global event handlers */ static struct wl_listener cursor_axis = {.notify = axisnotify}; -@@ -413,6 +446,12 @@ static struct wl_listener cursor_button = {.notify = buttonpress}; +@@ -414,6 +447,12 @@ static struct wl_listener cursor_button = {.notify = buttonpress}; static struct wl_listener cursor_frame = {.notify = cursorframe}; static struct wl_listener cursor_motion = {.notify = motionrelative}; static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; @@ -150,7 +150,7 @@ index 320910d..4e32240 100644 static struct wl_listener gpu_reset = {.notify = gpureset}; static struct wl_listener layout_change = {.notify = updatemons}; static struct wl_listener new_idle_inhibitor = {.notify = createidleinhibitor}; -@@ -435,6 +474,10 @@ static struct wl_listener request_set_sel = {.notify = setsel}; +@@ -436,6 +475,10 @@ static struct wl_listener request_set_sel = {.notify = setsel}; static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape}; static struct wl_listener request_start_drag = {.notify = requeststartdrag}; static struct wl_listener start_drag = {.notify = startdrag}; @@ -161,7 +161,7 @@ index 320910d..4e32240 100644 static struct wl_listener new_session_lock = {.notify = locksession}; #ifdef XWAYLAND -@@ -782,6 +825,10 @@ cleanuplisteners(void) +@@ -783,6 +826,10 @@ cleanuplisteners(void) wl_list_remove(&request_set_cursor_shape.link); wl_list_remove(&request_start_drag.link); wl_list_remove(&start_drag.link); @@ -172,7 +172,7 @@ index 320910d..4e32240 100644 wl_list_remove(&new_session_lock.link); #ifdef XWAYLAND wl_list_remove(&new_xwayland_surface.link); -@@ -1200,6 +1247,38 @@ createpopup(struct wl_listener *listener, void *data) +@@ -1201,6 +1248,38 @@ createpopup(struct wl_listener *listener, void *data) LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); } @@ -211,7 +211,7 @@ index 320910d..4e32240 100644 void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) { -@@ -1384,6 +1463,29 @@ destroykeyboardgroup(struct wl_listener *listener, void *data) +@@ -1385,6 +1464,29 @@ destroykeyboardgroup(struct wl_listener *listener, void *data) free(group); } @@ -241,7 +241,7 @@ index 320910d..4e32240 100644 Monitor * dirtomon(enum wlr_direction dir) { -@@ -1591,6 +1693,15 @@ inputdevice(struct wl_listener *listener, void *data) +@@ -1592,6 +1694,15 @@ inputdevice(struct wl_listener *listener, void *data) case WLR_INPUT_DEVICE_POINTER: createpointer(wlr_pointer_from_input_device(device)); break; @@ -257,7 +257,7 @@ index 320910d..4e32240 100644 default: /* TODO handle other input device types */ break; -@@ -1603,6 +1714,8 @@ inputdevice(struct wl_listener *listener, void *data) +@@ -1604,6 +1715,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; @@ -266,7 +266,7 @@ index 320910d..4e32240 100644 wlr_seat_set_capabilities(seat, caps); } -@@ -2587,6 +2700,8 @@ setup(void) +@@ -2588,6 +2701,8 @@ setup(void) relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); @@ -275,7 +275,7 @@ index 320910d..4e32240 100644 /* * Creates a cursor, which is a wlroots utility for tracking the cursor * image shown on screen. -@@ -2616,6 +2731,18 @@ setup(void) +@@ -2617,6 +2732,18 @@ setup(void) wl_signal_add(&cursor->events.button, &cursor_button); wl_signal_add(&cursor->events.axis, &cursor_axis); wl_signal_add(&cursor->events.frame, &cursor_frame); @@ -294,7 +294,7 @@ index 320910d..4e32240 100644 cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape); -@@ -2711,6 +2838,163 @@ tagmon(const Arg *arg) +@@ -2712,6 +2839,163 @@ tagmon(const Arg *arg) setmon(sel, dirtomon(arg->i), 0); } @@ -458,7 +458,7 @@ index 320910d..4e32240 100644 void tile(Monitor *m) { -@@ -2789,6 +3073,120 @@ toggleview(const Arg *arg) +@@ -2790,6 +3074,120 @@ toggleview(const Arg *arg) printstatus(); }