Created
August 26, 2025 07:12
-
-
Save Yappaholic/a34cbe3cc07d781ef8032795d112b2f0 to your computer and use it in GitHub Desktop.
Tablet patch for the Mangowc (DWL fork)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| From a649365d12b236af9a096d37484cfc82168d28b2 Mon Sep 17 00:00:00 2001 | |
| From: Yappaholic <[email protected]> | |
| Date: Tue, 26 Aug 2025 10:03:12 +0300 | |
| Subject: [PATCH] nothing | |
| --- | |
| src/ext-protocol/all.h | 3 +- | |
| src/ext-protocol/tablet.h | 220 ++++++++++++++++++++++++++++++++++++++ | |
| src/mango.c | 15 +++ | |
| 3 files changed, 237 insertions(+), 1 deletion(-) | |
| create mode 100644 src/ext-protocol/tablet.h | |
| diff --git a/src/ext-protocol/all.h b/src/ext-protocol/all.h | |
| index c657e0d..6b54c33 100644 | |
| --- a/src/ext-protocol/all.h | |
| +++ b/src/ext-protocol/all.h | |
| @@ -1,3 +1,4 @@ | |
| #include "dwl-ipc.h" | |
| #include "foreign-toplevel.h" | |
| -#include "text-input.h" | |
| \ No newline at end of file | |
| +#include "tablet.h" | |
| +#include "text-input.h" | |
| diff --git a/src/ext-protocol/tablet.h b/src/ext-protocol/tablet.h | |
| new file mode 100644 | |
| index 0000000..bd67973 | |
| --- /dev/null | |
| +++ b/src/ext-protocol/tablet.h | |
| @@ -0,0 +1,220 @@ | |
| +#include <wlr/types/wlr_tablet_pad.h> | |
| +#include <wlr/types/wlr_tablet_tool.h> | |
| +#include <wlr/types/wlr_tablet_v2.h> | |
| + | |
| +static const int tabletmaptosurface = | |
| + 0; /* map tablet input to surface(1) or monitor(0) */ | |
| + | |
| +static void createtablet(struct wlr_input_device *device); | |
| +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 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 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 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}; | |
| + | |
| +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 destroytablet(struct wl_listener *listener, void *data) { 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; | |
| +} | |
| + | |
| +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; | |
| + } | |
| +} | |
| + | |
| +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 | WLR_TABLET_TOOL_AXIS_TILT_Y)) { | |
| + printf("DEBUGGING: In axis event handling\n"); | |
| + wlr_tablet_v2_tablet_tool_notify_tilt(tablet_tool, event->tilt_x, | |
| + event->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); | |
| +} | |
| diff --git a/src/mango.c b/src/mango.c | |
| index 3700441..7e2e818 100644 | |
| --- a/src/mango.c | |
| +++ b/src/mango.c | |
| @@ -67,6 +67,9 @@ | |
| #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_tablet_pad.h> | |
| +#include <wlr/types/wlr_tablet_tool.h> | |
| +#include <wlr/types/wlr_tablet_v2.h> | |
| #include <wlr/types/wlr_viewporter.h> | |
| #include <wlr/types/wlr_virtual_keyboard_v1.h> | |
| #include <wlr/types/wlr_virtual_pointer_v1.h> | |
| @@ -3017,6 +3020,12 @@ void inputdevice(struct wl_listener *listener, void *data) { | |
| case WLR_INPUT_DEVICE_KEYBOARD: | |
| createkeyboard(wlr_keyboard_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_POINTER: | |
| createpointer(wlr_pointer_from_input_device(device)); | |
| break; | |
| @@ -4422,6 +4431,7 @@ void setup(void) { | |
| dpy = wl_display_create(); | |
| event_loop = wl_display_get_event_loop(dpy); | |
| pointer_manager = wlr_relative_pointer_manager_v1_create(dpy); | |
| + tablet_mgr = wlr_tablet_v2_create(dpy); | |
| /* The backend is a wlroots feature which abstracts the underlying input and | |
| * output hardware. The autocreate option will choose the most suitable | |
| * backend based on the current environment, such as opening an X11 window | |
| @@ -4594,6 +4604,11 @@ void 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); | |
| // 这两句代码会造成obs窗口里的鼠标光标消失,不知道注释有什么影响 | |
| cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); | |
| -- | |
| 2.49.1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for posting this patch though, just wanted to mention it if anyone was seeing this gist. I could try to poke at it as it seems somewhat easily replicatable but i don't know c.