diff --git a/patches/tablet-input/README.md b/patches/tablet-input/README.md index 518c4db..b57ca29 100644 --- a/patches/tablet-input/README.md +++ b/patches/tablet-input/README.md @@ -1,14 +1,18 @@ ### Description implements wlr-tablet-v2 for drawing tablets and supports cursor emulation - inspired by @guyuming76's [branch](https://codeberg.org/guyuming76/dwl/commits/branch/graphic_tablet), with coding help from @Palanix and testing by @Thanatos +extended with: +- specify the active drawing zone on the physical tablet +- pad and tool button bindings to compositor actions + ### Download -- [git branch](https://codeberg.org/fauxmight/dwl/src/branch/tablet-input) -- [tablet-input-wlroots-next-f4249db.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tablet-input/tablet-input-wlroots-next-f4249db.patch) +- [git branch](https://codeberg.org/pi66/dwl/src/branch/tablet-input) +- [tablet-input-main-a2d03cf618.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tablet-input/tablet-input-main-a2d03cf618.patch) - [tablet-input-0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tablet-input/tablet-input-0.8.patch) ### Authors - [fauxmight](https://codeberg.org/fauxmight) - [notchoc](https://codeberg.org/notchoc) - [Palanix](https://codeberg.org/Palanix) +- [pi66](https://codeberg.org/pi66) diff --git a/patches/tablet-input/tablet-input-0.8.patch b/patches/tablet-input/tablet-input-0.8.patch index 3c64854..9af55c2 100644 --- a/patches/tablet-input/tablet-input-0.8.patch +++ b/patches/tablet-input/tablet-input-0.8.patch @@ -1,13 +1,13 @@ -From 1069919d0252e554faddccc1f9da154e171ccdda Mon Sep 17 00:00:00 2001 -From: A Frederick Christensen -Date: Thu, 26 Feb 2026 21:56:13 -0600 -Subject: [PATCH] Apply tablet-input patch +From 27a9f5b7a0446f212785e7e8d6413f2a8e6af1ff Mon Sep 17 00:00:00 2001 +From: pi66 +Date: Sat, 4 Apr 2026 01:38:16 +0100 +Subject: [PATCH] feat: add pad/tool bindings and pen region --- Makefile | 6 +- - config.def.h | 1 + - dwl.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 246 insertions(+), 1 deletion(-) + config.def.h | 19 ++++ + dwl.c | 303 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 327 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 578194f..e0d1835 100644 @@ -34,19 +34,48 @@ index 578194f..e0d1835 100644 config.h: cp config.def.h $@ diff --git a/config.def.h b/config.def.h -index 8a6eda0..1f20dfd 100644 +index 8a6eda0..1286eeb 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 tabletmaptosurface = 1; /* 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 */ +@@ -13,6 +14,8 @@ static const float focuscolor[] = COLOR(0x005577ff); + static const float urgentcolor[] = COLOR(0xff0000ff); + /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ + static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */ ++/* Pen active area: value 0.0 => 1.0 { x, y, width, height } */ ++static const double tablet_area[4] = { 0.4, 0.4, 0.4, 0.4 }; + + /* tagging - TAGCOUNT must be no greater than 31 */ + #define TAGCOUNT (9) +@@ -170,3 +173,19 @@ static const Button buttons[] = { + { MODKEY, BTN_MIDDLE, togglefloating, {0} }, + { MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} }, + }; ++ ++static const TabletButton tabletbuttons[] = { ++ /* button state function argument */ ++// { BTN_STYLUS, WLR_BUTTON_PRESSED, spawn, {.v = termcmd} }, ++// { BTN_STYLUS2, WLR_BUTTON_PRESSED, killclient, {0} }, ++ { 0, 0, NULL, {0} } ++}; ++ ++static const TabletPadButton tabletpadbuttons[] = { ++ /* button state function argument */ ++// { 0, WLR_BUTTON_PRESSED, spawn, {.v = termcmd} }, ++// { 1, WLR_BUTTON_PRESSED, killclient, {0} }, ++// { 2, WLR_BUTTON_PRESSED, togglefloating, {0} }, ++// { 3, WLR_BUTTON_PRESSED, zoom, {0} }, ++ { 0, 0, NULL, {0} } ++}; diff --git a/dwl.c b/dwl.c -index 44f3ad9..4ef2cc8 100644 +index 44f3ad9..7572756 100644 --- a/dwl.c +++ b/dwl.c @@ -51,6 +51,9 @@ @@ -59,7 +88,28 @@ index 44f3ad9..4ef2cc8 100644 #include #include #include -@@ -268,6 +271,7 @@ static void createnotify(struct wl_listener *listener, void *data); +@@ -239,6 +242,20 @@ typedef struct { + struct wl_listener destroy; + } SessionLock; + ++typedef struct { ++ uint32_t button; ++ uint32_t state; ++ void (*func)(const Arg *); ++ const Arg arg; ++} TabletPadButton; ++ ++typedef struct { ++ uint32_t button; ++ uint32_t state; ++ void (*func)(const Arg *); ++ const Arg arg; ++} TabletButton; ++ + /* function declarations */ + static void applybounds(Client *c, struct wlr_box *bbox); + static void applyrules(Client *c); +@@ -268,6 +285,7 @@ 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); @@ -67,29 +117,31 @@ index 44f3ad9..4ef2cc8 100644 static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); static void cursorframe(struct wl_listener *listener, void *data); static void cursorwarptohint(void); -@@ -281,6 +285,9 @@ static void destroynotify(struct wl_listener *listener, void *data); +@@ -281,6 +299,10 @@ 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 destroytabletpad(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,6 +340,11 @@ static void spawn(const Arg *arg); +@@ -333,6 +355,12 @@ 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 tabletpadbutton(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); -@@ -390,6 +402,13 @@ static struct wlr_pointer_constraint_v1 *active_constraint; +@@ -390,6 +418,13 @@ static struct wlr_pointer_constraint_v1 *active_constraint; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; @@ -103,11 +155,13 @@ index 44f3ad9..4ef2cc8 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; -@@ -412,6 +431,12 @@ static struct wl_listener cursor_button = {.notify = buttonpress}; +@@ -412,6 +447,14 @@ 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_pad_destroy = {.notify = destroytabletpad}; ++static struct wl_listener tablet_pad_button = {.notify = tabletpadbutton}; +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}; @@ -116,7 +170,7 @@ index 44f3ad9..4ef2cc8 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}; -@@ -1199,6 +1224,28 @@ createpopup(struct wl_listener *listener, void *data) +@@ -1199,6 +1242,27 @@ createpopup(struct wl_listener *listener, void *data) LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); } @@ -128,7 +182,6 @@ index 44f3ad9..4ef2cc8 100644 + 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)) { @@ -145,19 +198,27 @@ index 44f3ad9..4ef2cc8 100644 void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) { -@@ -1383,6 +1430,29 @@ destroykeyboardgroup(struct wl_listener *listener, void *data) +@@ -1383,6 +1447,37 @@ 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); ++ wl_list_remove(&tablet_device_destroy.link); ++ wlr_cursor_detach_input_device(cursor, tablet->wlr_device); + tablet = NULL; +} + +void ++destroytabletpad(struct wl_listener *listener, void *data) ++{ ++ wl_list_remove(&tablet_pad_button.link); ++ wl_list_remove(&tablet_pad_destroy.link); ++ tablet_pad = NULL; ++} ++ ++void +destroytabletsurfacenotify(struct wl_listener *listener, void *data) +{ + if (tablet_curr_surface) @@ -175,7 +236,15 @@ index 44f3ad9..4ef2cc8 100644 Monitor * dirtomon(enum wlr_direction dir) { -@@ -1590,6 +1660,12 @@ inputdevice(struct wl_listener *listener, void *data) +@@ -1581,6 +1676,7 @@ inputdevice(struct wl_listener *listener, void *data) + /* This event is raised by the backend when a new input device becomes + * available. */ + struct wlr_input_device *device = data; ++ struct wlr_tablet_pad *pad = NULL; + uint32_t caps; + + switch (device->type) { +@@ -1590,6 +1686,15 @@ inputdevice(struct wl_listener *listener, void *data) case WLR_INPUT_DEVICE_POINTER: createpointer(wlr_pointer_from_input_device(device)); break; @@ -183,12 +252,15 @@ index 44f3ad9..4ef2cc8 100644 + createtablet(device); + break; + case WLR_INPUT_DEVICE_TABLET_PAD: -+ tablet_pad = wlr_tablet_pad_create(tablet_mgr, seat, device); ++ pad = wlr_tablet_pad_from_input_device(device); ++ tablet_pad = wlr_tablet_pad_create(tablet_mgr, seat, device); ++ wl_signal_add(&pad->events.button, &tablet_pad_button); ++ wl_signal_add(&device->events.destroy, &tablet_pad_destroy); + break; default: /* TODO handle other input device types */ break; -@@ -2585,6 +2661,8 @@ setup(void) +@@ -2585,6 +2690,8 @@ setup(void) relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); @@ -197,7 +269,7 @@ index 44f3ad9..4ef2cc8 100644 /* * Creates a cursor, which is a wlroots utility for tracking the cursor * image shown on screen. -@@ -2614,6 +2692,11 @@ setup(void) +@@ -2614,6 +2721,11 @@ 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); @@ -209,7 +281,7 @@ index 44f3ad9..4ef2cc8 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); -@@ -2709,6 +2792,163 @@ tagmon(const Arg *arg) +@@ -2709,6 +2821,197 @@ tagmon(const Arg *arg) setmon(sel, dirtomon(arg->i), 0); } @@ -226,13 +298,33 @@ index 44f3ad9..4ef2cc8 100644 + 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_region(cursor, dev, &geom); + wlr_cursor_map_input_to_output(cursor, dev, selmon->wlr_output); +} + +void ++tabletpadbutton(struct wl_listener *listener, void *data) ++{ ++ struct wlr_tablet_pad_button_event *event = data; ++ const TabletPadButton *pb; ++ ++ for (pb = tabletpadbuttons; pb < END(tabletpadbuttons); pb++) { ++ if (event->button == pb->button ++ && event->state == pb->state ++ && pb->func) { ++ pb->func(&pb->arg); ++ } ++ } ++ ++ if (tablet_pad) ++ wlr_tablet_v2_tablet_pad_notify_button(tablet_pad, ++ event->button, event->time_msec, ++ (enum zwp_tablet_pad_v2_button_state)event->state); ++} ++ ++void +tablettoolmotion(struct wlr_tablet_v2_tablet_tool *tool, bool change_x, bool change_y, + double x, double y, double dx, double dy) +{ @@ -244,6 +336,10 @@ index 44f3ad9..4ef2cc8 100644 + + tabletapplymap(x, y, tablet->wlr_device); + ++ x = (MAX(tablet_area[0], MIN(tablet_area[0] + tablet_area[2], x)) - tablet_area[0]) / tablet_area[2]; ++ y = (MAX(tablet_area[1], MIN(tablet_area[1] + tablet_area[3], y)) - tablet_area[1]) / tablet_area[3]; ++ ++ + // TODO: apply constraints + switch (tablet_tool->wlr_tool->type) { + case WLR_TABLET_TOOL_TYPE_LENS: @@ -341,9 +437,19 @@ index 44f3ad9..4ef2cc8 100644 +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); ++ struct wlr_tablet_tool_button_event *event = data; ++ const TabletButton *tb; ++ ++ for (tb = tabletbuttons; tb < END(tabletbuttons); tb++) { ++ if (event->button == tb->button ++ && event->state == tb->state ++ && tb->func) { ++ tb->func(&tb->arg); ++ } ++ } ++ ++ wlr_tablet_v2_tablet_tool_notify_button(tablet_tool, event->button, ++ (enum zwp_tablet_pad_v2_button_state)event->state); +} + +void @@ -374,5 +480,5 @@ index 44f3ad9..4ef2cc8 100644 tile(Monitor *m) { -- -2.52.0 +2.53.0 diff --git a/patches/tablet-input/tablet-input-wlroots-next-f4249db.patch b/patches/tablet-input/tablet-input-main-a2d03cf618.patch similarity index 69% rename from patches/tablet-input/tablet-input-wlroots-next-f4249db.patch rename to patches/tablet-input/tablet-input-main-a2d03cf618.patch index 8fb44ab..9af55c2 100644 --- a/patches/tablet-input/tablet-input-wlroots-next-f4249db.patch +++ b/patches/tablet-input/tablet-input-main-a2d03cf618.patch @@ -1,13 +1,13 @@ -From 55f35863fa9c5a379c9315192c6bc072c3b2ebb6 Mon Sep 17 00:00:00 2001 -From: A Frederick Christensen -Date: Thu, 26 Feb 2026 21:58:37 -0600 -Subject: [PATCH] Apply tablet-input patch +From 27a9f5b7a0446f212785e7e8d6413f2a8e6af1ff Mon Sep 17 00:00:00 2001 +From: pi66 +Date: Sat, 4 Apr 2026 01:38:16 +0100 +Subject: [PATCH] feat: add pad/tool bindings and pen region --- Makefile | 6 +- - config.def.h | 1 + - dwl.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 246 insertions(+), 1 deletion(-) + config.def.h | 19 ++++ + dwl.c | 303 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 327 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 578194f..e0d1835 100644 @@ -34,22 +34,51 @@ index 578194f..e0d1835 100644 config.h: cp config.def.h $@ diff --git a/config.def.h b/config.def.h -index 8a6eda0..1f20dfd 100644 +index 8a6eda0..1286eeb 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 tabletmaptosurface = 1; /* 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 */ +@@ -13,6 +14,8 @@ static const float focuscolor[] = COLOR(0x005577ff); + static const float urgentcolor[] = COLOR(0xff0000ff); + /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ + static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */ ++/* Pen active area: value 0.0 => 1.0 { x, y, width, height } */ ++static const double tablet_area[4] = { 0.4, 0.4, 0.4, 0.4 }; + + /* tagging - TAGCOUNT must be no greater than 31 */ + #define TAGCOUNT (9) +@@ -170,3 +173,19 @@ static const Button buttons[] = { + { MODKEY, BTN_MIDDLE, togglefloating, {0} }, + { MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} }, + }; ++ ++static const TabletButton tabletbuttons[] = { ++ /* button state function argument */ ++// { BTN_STYLUS, WLR_BUTTON_PRESSED, spawn, {.v = termcmd} }, ++// { BTN_STYLUS2, WLR_BUTTON_PRESSED, killclient, {0} }, ++ { 0, 0, NULL, {0} } ++}; ++ ++static const TabletPadButton tabletpadbuttons[] = { ++ /* button state function argument */ ++// { 0, WLR_BUTTON_PRESSED, spawn, {.v = termcmd} }, ++// { 1, WLR_BUTTON_PRESSED, killclient, {0} }, ++// { 2, WLR_BUTTON_PRESSED, togglefloating, {0} }, ++// { 3, WLR_BUTTON_PRESSED, zoom, {0} }, ++ { 0, 0, NULL, {0} } ++}; diff --git a/dwl.c b/dwl.c -index 8a9715d..e7d796b 100644 +index 44f3ad9..7572756 100644 --- a/dwl.c +++ b/dwl.c -@@ -52,6 +52,9 @@ +@@ -51,6 +51,9 @@ #include #include #include @@ -59,7 +88,28 @@ index 8a9715d..e7d796b 100644 #include #include #include -@@ -270,6 +273,7 @@ static void createnotify(struct wl_listener *listener, void *data); +@@ -239,6 +242,20 @@ typedef struct { + struct wl_listener destroy; + } SessionLock; + ++typedef struct { ++ uint32_t button; ++ uint32_t state; ++ void (*func)(const Arg *); ++ const Arg arg; ++} TabletPadButton; ++ ++typedef struct { ++ uint32_t button; ++ uint32_t state; ++ void (*func)(const Arg *); ++ const Arg arg; ++} TabletButton; ++ + /* function declarations */ + static void applybounds(Client *c, struct wlr_box *bbox); + static void applyrules(Client *c); +@@ -268,6 +285,7 @@ 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); @@ -67,29 +117,31 @@ index 8a9715d..e7d796b 100644 static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); static void cursorframe(struct wl_listener *listener, void *data); static void cursorwarptohint(void); -@@ -283,6 +287,9 @@ static void destroynotify(struct wl_listener *listener, void *data); +@@ -281,6 +299,10 @@ 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 destroytabletpad(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); -@@ -335,6 +342,11 @@ static void spawn(const Arg *arg); +@@ -333,6 +355,12 @@ 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 tabletpadbutton(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); -@@ -392,6 +404,13 @@ static struct wlr_pointer_constraint_v1 *active_constraint; +@@ -390,6 +418,13 @@ static struct wlr_pointer_constraint_v1 *active_constraint; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; @@ -103,11 +155,13 @@ index 8a9715d..e7d796b 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; -@@ -414,6 +433,12 @@ static struct wl_listener cursor_button = {.notify = buttonpress}; +@@ -412,6 +447,14 @@ 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_pad_destroy = {.notify = destroytabletpad}; ++static struct wl_listener tablet_pad_button = {.notify = tabletpadbutton}; +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}; @@ -116,7 +170,7 @@ index 8a9715d..e7d796b 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}; -@@ -1201,6 +1226,28 @@ createpopup(struct wl_listener *listener, void *data) +@@ -1199,6 +1242,27 @@ createpopup(struct wl_listener *listener, void *data) LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); } @@ -128,7 +182,6 @@ index 8a9715d..e7d796b 100644 + 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)) { @@ -145,19 +198,27 @@ index 8a9715d..e7d796b 100644 void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) { -@@ -1385,6 +1432,29 @@ destroykeyboardgroup(struct wl_listener *listener, void *data) +@@ -1383,6 +1447,37 @@ 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); ++ wl_list_remove(&tablet_device_destroy.link); ++ wlr_cursor_detach_input_device(cursor, tablet->wlr_device); + tablet = NULL; +} + +void ++destroytabletpad(struct wl_listener *listener, void *data) ++{ ++ wl_list_remove(&tablet_pad_button.link); ++ wl_list_remove(&tablet_pad_destroy.link); ++ tablet_pad = NULL; ++} ++ ++void +destroytabletsurfacenotify(struct wl_listener *listener, void *data) +{ + if (tablet_curr_surface) @@ -175,7 +236,15 @@ index 8a9715d..e7d796b 100644 Monitor * dirtomon(enum wlr_direction dir) { -@@ -1592,6 +1662,12 @@ inputdevice(struct wl_listener *listener, void *data) +@@ -1581,6 +1676,7 @@ inputdevice(struct wl_listener *listener, void *data) + /* This event is raised by the backend when a new input device becomes + * available. */ + struct wlr_input_device *device = data; ++ struct wlr_tablet_pad *pad = NULL; + uint32_t caps; + + switch (device->type) { +@@ -1590,6 +1686,15 @@ inputdevice(struct wl_listener *listener, void *data) case WLR_INPUT_DEVICE_POINTER: createpointer(wlr_pointer_from_input_device(device)); break; @@ -183,12 +252,15 @@ index 8a9715d..e7d796b 100644 + createtablet(device); + break; + case WLR_INPUT_DEVICE_TABLET_PAD: -+ tablet_pad = wlr_tablet_pad_create(tablet_mgr, seat, device); ++ pad = wlr_tablet_pad_from_input_device(device); ++ tablet_pad = wlr_tablet_pad_create(tablet_mgr, seat, device); ++ wl_signal_add(&pad->events.button, &tablet_pad_button); ++ wl_signal_add(&device->events.destroy, &tablet_pad_destroy); + break; default: /* TODO handle other input device types */ break; -@@ -2588,6 +2664,8 @@ setup(void) +@@ -2585,6 +2690,8 @@ setup(void) relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); @@ -197,7 +269,7 @@ index 8a9715d..e7d796b 100644 /* * Creates a cursor, which is a wlroots utility for tracking the cursor * image shown on screen. -@@ -2617,6 +2695,11 @@ setup(void) +@@ -2614,6 +2721,11 @@ 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); @@ -209,7 +281,7 @@ index 8a9715d..e7d796b 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); -@@ -2712,6 +2795,163 @@ tagmon(const Arg *arg) +@@ -2709,6 +2821,197 @@ tagmon(const Arg *arg) setmon(sel, dirtomon(arg->i), 0); } @@ -226,13 +298,33 @@ index 8a9715d..e7d796b 100644 + 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_region(cursor, dev, &geom); + wlr_cursor_map_input_to_output(cursor, dev, selmon->wlr_output); +} + +void ++tabletpadbutton(struct wl_listener *listener, void *data) ++{ ++ struct wlr_tablet_pad_button_event *event = data; ++ const TabletPadButton *pb; ++ ++ for (pb = tabletpadbuttons; pb < END(tabletpadbuttons); pb++) { ++ if (event->button == pb->button ++ && event->state == pb->state ++ && pb->func) { ++ pb->func(&pb->arg); ++ } ++ } ++ ++ if (tablet_pad) ++ wlr_tablet_v2_tablet_pad_notify_button(tablet_pad, ++ event->button, event->time_msec, ++ (enum zwp_tablet_pad_v2_button_state)event->state); ++} ++ ++void +tablettoolmotion(struct wlr_tablet_v2_tablet_tool *tool, bool change_x, bool change_y, + double x, double y, double dx, double dy) +{ @@ -244,6 +336,10 @@ index 8a9715d..e7d796b 100644 + + tabletapplymap(x, y, tablet->wlr_device); + ++ x = (MAX(tablet_area[0], MIN(tablet_area[0] + tablet_area[2], x)) - tablet_area[0]) / tablet_area[2]; ++ y = (MAX(tablet_area[1], MIN(tablet_area[1] + tablet_area[3], y)) - tablet_area[1]) / tablet_area[3]; ++ ++ + // TODO: apply constraints + switch (tablet_tool->wlr_tool->type) { + case WLR_TABLET_TOOL_TYPE_LENS: @@ -341,9 +437,19 @@ index 8a9715d..e7d796b 100644 +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); ++ struct wlr_tablet_tool_button_event *event = data; ++ const TabletButton *tb; ++ ++ for (tb = tabletbuttons; tb < END(tabletbuttons); tb++) { ++ if (event->button == tb->button ++ && event->state == tb->state ++ && tb->func) { ++ tb->func(&tb->arg); ++ } ++ } ++ ++ wlr_tablet_v2_tablet_tool_notify_button(tablet_tool, event->button, ++ (enum zwp_tablet_pad_v2_button_state)event->state); +} + +void @@ -374,5 +480,5 @@ index 8a9715d..e7d796b 100644 tile(Monitor *m) { -- -2.52.0 +2.53.0