wayland: Basic support for zwp_tablet_*v2 protocol

This commit is contained in:
Florian "sp1rit"​ 2022-03-23 13:46:25 -04:00 committed by Ethan Lee
parent 13337e17a5
commit 9125b244e7
5 changed files with 1586 additions and 0 deletions

View file

@ -40,6 +40,7 @@
#include "xdg-shell-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@ -1646,6 +1647,361 @@ Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
}
}
static void
tablet_tool_handle_type(void* data, struct zwp_tablet_tool_v2* tool, uint32_t type)
{
/* unimplemented */
}
static void
tablet_tool_handle_hardware_serial(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial_hi, uint32_t serial_lo)
{
/* unimplemented */
}
static void
tablet_tool_handle_hardware_id_wacom(void* data, struct zwp_tablet_tool_v2* tool, uint32_t id_hi, uint32_t id_lo)
{
/* unimplemented */
}
static void
tablet_tool_handle_capability(void* data, struct zwp_tablet_tool_v2* tool, uint32_t capability)
{
/* unimplemented */
}
static void
tablet_tool_handle_done(void* data, struct zwp_tablet_tool_v2* tool)
{
/* unimplemented */
}
static void
tablet_tool_handle_removed(void* data, struct zwp_tablet_tool_v2* tool)
{
/* unimplemented */
}
static void
tablet_tool_handle_proximity_in(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial, struct zwp_tablet_v2* tablet, struct wl_surface* surface)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window;
if (!surface) {
return;
}
if (!SDL_WAYLAND_own_surface(surface)) {
return;
}
window = (SDL_WindowData*)wl_surface_get_user_data(surface);
if (window) {
input->tool_focus = window;
input->tool_prox_serial = serial;
input->is_down = SDL_FALSE;
input->btn_stylus = SDL_FALSE;
input->btn_stylus2 = SDL_FALSE;
input->btn_stylus3 = SDL_FALSE;
SDL_SetMouseFocus(window->sdlwindow);
SDL_SetCursor(NULL);
}
}
static void
tablet_tool_handle_proximity_out(void* data, struct zwp_tablet_tool_v2* tool)
{
struct SDL_WaylandTabletInput* input = data;
if (input->tool_focus) {
SDL_SetMouseFocus(NULL);
input->tool_focus = NULL;
}
}
uint32_t
tablet_tool_btn_to_sdl_button(struct SDL_WaylandTabletInput* input)
{
unsigned int tool_btn = input->btn_stylus3 << 2 | input->btn_stylus2 << 1 | input->btn_stylus << 0;
switch (tool_btn) {
case 0b000:
return SDL_BUTTON_LEFT;
case 0b001:
return SDL_BUTTON_RIGHT;
case 0b010:
return SDL_BUTTON_MIDDLE;
case 0b100:
return SDL_BUTTON_X1;
default:
return SDL_BUTTON_LEFT;
}
}
static void
tablet_tool_handle_down(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window = input->tool_focus;
input->is_down = SDL_TRUE;
if (!window) {
/* tablet_tool_handle_proximity_out gets called when moving over the libdecoration csd.
* that sets input->tool_focus (window) to NULL, but handle_{down,up} events are still
* received. To prevent SIGSEGV this returns when this is the case.
*/
return;
}
SDL_SendMouseButton(window->sdlwindow, 0, SDL_PRESSED, tablet_tool_btn_to_sdl_button(input));
}
static void
tablet_tool_handle_up(void* data, struct zwp_tablet_tool_v2* tool)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window = input->tool_focus;
input->is_down = SDL_FALSE;
if (!window) {
/* tablet_tool_handle_proximity_out gets called when moving over the libdecoration csd.
* that sets input->tool_focus (window) to NULL, but handle_{down,up} events are still
* received. To prevent SIGSEGV this returns when this is the case.
*/
return;
}
SDL_SendMouseButton(window->sdlwindow, 0, SDL_RELEASED, tablet_tool_btn_to_sdl_button(input));
}
static void
tablet_tool_handle_motion(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t sx_w, wl_fixed_t sy_w)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window = input->tool_focus;
input->sx_w = sx_w;
input->sy_w = sy_w;
if (input->tool_focus) {
const int sx = wl_fixed_to_int(sx_w);
const int sy = wl_fixed_to_int(sy_w);
SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
}
}
static void
tablet_tool_handle_pressure(void* data, struct zwp_tablet_tool_v2* tool, uint32_t pressure)
{
/* unimplemented */
}
static void
tablet_tool_handle_distance(void* data, struct zwp_tablet_tool_v2* tool, uint32_t distance)
{
/* unimplemented */
}
static void
tablet_tool_handle_tilt(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t xtilt, wl_fixed_t ytilt)
{
/* unimplemented */
}
static void
tablet_tool_handle_button(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial, uint32_t button, uint32_t state)
{
struct SDL_WaylandTabletInput* input = data;
if (input->is_down) {
tablet_tool_handle_up(data, tool);
input->is_down = SDL_TRUE;
}
switch (button) {
/* see %{_includedir}/linux/input-event-codes.h */
case 0x14b: /* BTN_STYLUS */
input->btn_stylus = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE;
break;
case 0x14c: /* BTN_STYLUS2 */
input->btn_stylus2 = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE;
break;
case 0x149: /* BTN_STYLUS3 */
input->btn_stylus3 = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE;
break;
}
if (input->is_down) {
tablet_tool_handle_down(data, tool, serial);
}
}
static void
tablet_tool_handle_rotation(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t degrees)
{
/* unimplemented */
}
static void
tablet_tool_handle_slider(void* data, struct zwp_tablet_tool_v2* tool, int32_t position)
{
/* unimplemented */
}
static void
tablet_tool_handle_wheel(void* data, struct zwp_tablet_tool_v2* tool, int32_t degrees, int32_t clicks)
{
/* unimplemented */
}
static void
tablet_tool_handle_frame(void* data, struct zwp_tablet_tool_v2* tool, uint32_t time)
{
/* unimplemented */
}
static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
tablet_tool_handle_type,
tablet_tool_handle_hardware_serial,
tablet_tool_handle_hardware_id_wacom,
tablet_tool_handle_capability,
tablet_tool_handle_done,
tablet_tool_handle_removed,
tablet_tool_handle_proximity_in,
tablet_tool_handle_proximity_out,
tablet_tool_handle_down,
tablet_tool_handle_up,
tablet_tool_handle_motion,
tablet_tool_handle_pressure,
tablet_tool_handle_distance,
tablet_tool_handle_tilt,
tablet_tool_handle_rotation,
tablet_tool_handle_slider,
tablet_tool_handle_wheel,
tablet_tool_handle_button,
tablet_tool_handle_frame
};
struct SDL_WaylandTabletObjectListNode*
tablet_object_list_new_node(void* object)
{
struct SDL_WaylandTabletObjectListNode* node;
node = SDL_calloc(1, sizeof *node);
if (node == NULL) {
return NULL;
}
node->next = NULL;
node->object = object;
return node;
}
void tablet_object_list_append(struct SDL_WaylandTabletObjectListNode* head, void* object)
{
if (head->object == NULL) {
head->object = object;
return;
}
while (head->next) {
head = head->next;
}
head->next = tablet_object_list_new_node(object);
}
void tablet_object_list_destroy(struct SDL_WaylandTabletObjectListNode* head, void (*deleter)(void* object))
{
while (head) {
struct SDL_WaylandTabletObjectListNode* next = head->next;
if (head->object) {
(*deleter)(head->object);
}
SDL_free(head);
head = next;
}
}
static void
tablet_seat_handle_tablet_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_v2* tablet)
{
struct SDL_WaylandTabletInput* input = data;
tablet_object_list_append(input->tablets, tablet);
}
static void
tablet_seat_handle_tool_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_tool_v2* tool)
{
struct SDL_WaylandTabletInput* input = data;
zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, data);
zwp_tablet_tool_v2_set_user_data(tool, data);
tablet_object_list_append(input->tools, tool);
}
static void
tablet_seat_handle_pad_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_pad_v2* pad)
{
struct SDL_WaylandTabletInput* input = data;
tablet_object_list_append(input->pads, pad);
}
static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
tablet_seat_handle_tablet_added,
tablet_seat_handle_tool_added,
tablet_seat_handle_pad_added
};
void
Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager* tablet_manager)
{
struct SDL_WaylandTabletInput* tablet_input;
if (!tablet_manager || !input || !input->seat) {
return;
}
tablet_input = SDL_calloc(1, sizeof *tablet_input);
if (tablet_input == NULL) {
return;
}
input->tablet = tablet_input;
tablet_input->seat = (struct SDL_WaylandTabletSeat*)zwp_tablet_manager_v2_get_tablet_seat((struct zwp_tablet_manager_v2*)tablet_manager, input->seat);
tablet_input->tablets = tablet_object_list_new_node(NULL);
tablet_input->tools = tablet_object_list_new_node(NULL);
tablet_input->pads = tablet_object_list_new_node(NULL);
zwp_tablet_seat_v2_add_listener((struct zwp_tablet_seat_v2*)tablet_input->seat, &tablet_seat_listener, tablet_input);
}
#define TABLET_OBJECT_LIST_DELETER(fun) (void (*)(void*))fun
void
Wayland_input_destroy_tablet(struct SDL_WaylandInput* input)
{
tablet_object_list_destroy(input->tablet->pads, TABLET_OBJECT_LIST_DELETER(zwp_tablet_pad_v2_destroy));
tablet_object_list_destroy(input->tablet->tools, TABLET_OBJECT_LIST_DELETER(zwp_tablet_tool_v2_destroy));
tablet_object_list_destroy(input->tablet->tablets, TABLET_OBJECT_LIST_DELETER(zwp_tablet_v2_destroy));
zwp_tablet_seat_v2_destroy((struct zwp_tablet_seat_v2*)input->tablet->seat);
SDL_free(input->tablet);
input->tablet = NULL;
}
void
Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
{
@ -1671,6 +2027,10 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
wl_seat_add_listener(input->seat, &seat_listener, input);
wl_seat_set_user_data(input->seat, input);
if (d->tablet_manager) {
Wayland_input_add_tablet(input, d->tablet_manager);
}
WAYLAND_wl_display_flush(d->display);
}
@ -1711,6 +2071,10 @@ void Wayland_display_destroy_input(SDL_VideoData *d)
wl_touch_destroy(input->touch);
}
if (input->tablet) {
Wayland_input_destroy_tablet(input);
}
if (input->seat)
wl_seat_destroy(input->seat);

View file

@ -29,6 +29,34 @@
#include "SDL_waylanddatamanager.h"
#include "SDL_waylandkeyboard.h"
struct SDL_WaylandTabletSeat;
struct SDL_WaylandTabletObjectListNode {
void* object;
struct SDL_WaylandTabletObjectListNode* next;
};
struct SDL_WaylandTabletInput {
struct SDL_WaylandTabletSeat* seat;
struct SDL_WaylandTabletObjectListNode* tablets;
struct SDL_WaylandTabletObjectListNode* tools;
struct SDL_WaylandTabletObjectListNode* pads;
SDL_WindowData *tool_focus;
uint32_t tool_prox_serial;
/* Last motion location */
wl_fixed_t sx_w;
wl_fixed_t sy_w;
SDL_bool is_down;
SDL_bool btn_stylus;
SDL_bool btn_stylus2;
SDL_bool btn_stylus3;
};
typedef struct {
// repeat_rate in range of [1, 1000]
int32_t repeat_rate;
@ -80,6 +108,8 @@ struct SDL_WaylandInput {
} pointer_curr_axis_info;
SDL_WaylandKeyboardRepeat keyboard_repeat;
struct SDL_WaylandTabletInput* tablet;
};
extern void Wayland_PumpEvents(_THIS);
@ -107,6 +137,9 @@ extern void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d);
extern int Wayland_input_grab_keyboard(SDL_Window *window, struct SDL_WaylandInput *input);
extern int Wayland_input_ungrab_keyboard(SDL_Window *window);
extern void Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager* tablet_manager);
extern void Wayland_input_destroy_tablet(struct SDL_WaylandInput *input);
#endif /* SDL_waylandevents_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -52,6 +52,7 @@
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@ -610,6 +611,11 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
Wayland_add_data_device_manager(d, id, version);
} else if (SDL_strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
d->decoration_manager = wl_registry_bind(d->registry, id, &zxdg_decoration_manager_v1_interface, 1);
} else if (SDL_strcmp(interface, "zwp_tablet_manager_v2") == 0) {
d->tablet_manager = wl_registry_bind(d->registry, id, &zwp_tablet_manager_v2_interface, 1);
if (d->input) {
Wayland_input_add_tablet(d->input, d->tablet_manager);
}
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
} else if (SDL_strcmp(interface, "qt_touch_extension") == 0) {
@ -769,6 +775,9 @@ Wayland_VideoQuit(_THIS)
Wayland_touch_destroy(data);
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
if (data->tablet_manager)
zwp_tablet_manager_v2_destroy((struct zwp_tablet_manager_v2*)data->tablet_manager);
if (data->data_device_manager)
wl_data_device_manager_destroy(data->data_device_manager);

View file

@ -34,6 +34,7 @@
struct xkb_context;
struct SDL_WaylandInput;
struct SDL_WaylandTabletManager;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct SDL_WaylandTouch;
@ -77,6 +78,7 @@ typedef struct {
struct xkb_context *xkb_context;
struct SDL_WaylandInput *input;
struct SDL_WaylandTabletManager *tablet_manager;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct SDL_WaylandTouch *touch;

File diff suppressed because it is too large Load diff