diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c index fdae3ce85..c95f4e830 100644 --- a/hw/xwayland/xwayland-cursor.c +++ b/hw/xwayland/xwayland-cursor.c @@ -175,11 +175,62 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat) wl_surface_commit(xwl_cursor->surface); } +void +xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool) +{ + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor; + PixmapPtr pixmap; + CursorPtr cursor; + int stride; + + if (!xwl_seat->x_cursor) { + zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool, + xwl_tablet_tool->proximity_in_serial, + NULL, 0, 0); + return; + } + + if (xwl_cursor->frame_cb) { + xwl_cursor->needs_update = TRUE; + return; + } + + cursor = xwl_seat->x_cursor; + pixmap = dixGetPrivate(&cursor->devPrivates, &xwl_cursor_private_key); + if (!pixmap) + return; + + stride = cursor->bits->width * 4; + if (cursor->bits->argb) + memcpy(pixmap->devPrivate.ptr, + cursor->bits->argb, cursor->bits->height * stride); + else + expand_source_and_mask(cursor, pixmap->devPrivate.ptr); + + zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool, + xwl_tablet_tool->proximity_in_serial, + xwl_cursor->surface, + xwl_seat->x_cursor->bits->xhot, + xwl_seat->x_cursor->bits->yhot); + wl_surface_attach(xwl_cursor->surface, + xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0); + wl_surface_damage(xwl_cursor->surface, 0, 0, + xwl_seat->x_cursor->bits->width, + xwl_seat->x_cursor->bits->height); + + xwl_cursor->frame_cb = wl_surface_frame(xwl_cursor->surface); + wl_callback_add_listener(xwl_cursor->frame_cb, &frame_listener, xwl_cursor); + + wl_surface_commit(xwl_cursor->surface); +} + static void xwl_set_cursor(DeviceIntPtr device, ScreenPtr screen, CursorPtr cursor, int x, int y) { struct xwl_seat *xwl_seat; + struct xwl_tablet_tool *xwl_tablet_tool; Bool cursor_visibility_changed; xwl_seat = device->public.devicePrivate; @@ -194,6 +245,11 @@ xwl_set_cursor(DeviceIntPtr device, xwl_seat_cursor_visibility_changed(xwl_seat); xwl_seat_set_cursor(xwl_seat); + + xorg_list_for_each_entry(xwl_tablet_tool, &xwl_seat->tablet_tools, link) { + if (xwl_tablet_tool->proximity_in_serial != 0) + xwl_tablet_tool_set_cursor(xwl_tablet_tool); + } } static void diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index 93cf72109..e80b94e08 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -1399,6 +1399,7 @@ tablet_tool_receive_removed(void *data, struct zwp_tablet_tool_v2 *tool) struct xwl_tablet_tool *xwl_tablet_tool = data; xorg_list_del(&xwl_tablet_tool->link); + xwl_cursor_release(&xwl_tablet_tool->cursor); zwp_tablet_tool_v2_destroy(tool); free(xwl_tablet_tool); } @@ -1422,7 +1423,10 @@ tablet_tool_proximity_in(void *data, struct zwp_tablet_tool_v2 *tool, if (wl_surface == NULL) return; + xwl_tablet_tool->proximity_in_serial = serial; xwl_seat->focus_window = wl_surface_get_user_data(wl_surface); + + xwl_tablet_tool_set_cursor(xwl_tablet_tool); } static void @@ -1431,6 +1435,7 @@ tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *tool) struct xwl_tablet_tool *xwl_tablet_tool = data; struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + xwl_tablet_tool->proximity_in_serial = 0; xwl_seat->focus_window = NULL; xwl_tablet_tool->pressure = 0; @@ -1710,11 +1715,21 @@ tablet_seat_handle_add_tablet(void *data, struct zwp_tablet_seat_v2 *tablet_seat zwp_tablet_v2_add_listener(tablet, &tablet_listener, xwl_tablet); } +static void +xwl_tablet_tool_update_cursor(struct xwl_cursor *xwl_cursor) +{ + struct xwl_tablet_tool *xwl_tablet_tool = wl_container_of(xwl_cursor, + xwl_tablet_tool, + cursor); + xwl_tablet_tool_set_cursor(xwl_tablet_tool); +} + static void tablet_seat_handle_add_tool(void *data, struct zwp_tablet_seat_v2 *tablet_seat, struct zwp_tablet_tool_v2 *tool) { struct xwl_seat *xwl_seat = data; + struct xwl_screen *xwl_screen = xwl_seat->xwl_screen; struct xwl_tablet_tool *xwl_tablet_tool; xwl_tablet_tool = calloc(sizeof *xwl_tablet_tool, 1); @@ -1725,6 +1740,8 @@ tablet_seat_handle_add_tool(void *data, struct zwp_tablet_seat_v2 *tablet_seat, xwl_tablet_tool->tool = tool; xwl_tablet_tool->seat = xwl_seat; + xwl_cursor_init(&xwl_tablet_tool->cursor, xwl_screen, + xwl_tablet_tool_update_cursor); xorg_list_add(&xwl_tablet_tool->link, &xwl_seat->tablet_tools); diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index a152eab97..e611c2995 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -44,6 +44,7 @@ #include "relative-pointer-unstable-v1-client-protocol.h" #include "pointer-constraints-unstable-v1-client-protocol.h" +#include "tablet-unstable-v2-client-protocol.h" struct xwl_screen { int width; @@ -203,6 +204,7 @@ struct xwl_tablet_tool { struct xwl_seat *seat; DeviceIntPtr xdevice; + uint32_t proximity_in_serial; uint32_t x; uint32_t y; uint32_t pressure; @@ -213,6 +215,8 @@ struct xwl_tablet_tool { uint32_t buttons_now, buttons_prev; + + struct xwl_cursor cursor; }; struct xwl_tablet_pad { @@ -240,6 +244,7 @@ Bool xwl_screen_init_cursor(struct xwl_screen *xwl_screen); struct xwl_screen *xwl_screen_get(ScreenPtr screen); +void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *tool); void xwl_seat_set_cursor(struct xwl_seat *xwl_seat); void xwl_seat_destroy(struct xwl_seat *xwl_seat);