aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Ongyerth <ongy@ongy.net>2018-04-24 08:10:45 +0200
committerMarkus Ongyerth <ongy@ongy.net>2018-07-14 09:40:39 +0200
commite235f7d33621b5879a5f9a8a1d89d4a8515857c3 (patch)
treee1c8a9d3d6966753fdccf3940197929f5681bedf
parent77bac448ccac9827abfa2ab10e798295f07f3980 (diff)
Basic tablet_v2 object lifetime
-rw-r--r--backend/libinput/tablet_pad.c28
-rw-r--r--backend/libinput/tablet_tool.c12
-rw-r--r--include/rootston/cursor.h1
-rw-r--r--include/rootston/desktop.h1
-rw-r--r--include/wlr/types/wlr_tablet_pad.h2
-rw-r--r--include/wlr/types/wlr_tablet_tool.h2
-rw-r--r--include/wlr/types/wlr_tablet_v2.h62
-rw-r--r--rootston/desktop.c4
-rw-r--r--rootston/seat.c26
-rw-r--r--types/wlr_tablet_v2.c673
10 files changed, 763 insertions, 48 deletions
diff --git a/backend/libinput/tablet_pad.c b/backend/libinput/tablet_pad.c
index ed5374c6..2558d09c 100644
--- a/backend/libinput/tablet_pad.c
+++ b/backend/libinput/tablet_pad.c
@@ -1,4 +1,8 @@
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809L
+#endif
#include <assert.h>
+#include <string.h>
#include <libinput.h>
#include <stdlib.h>
#include <wlr/backend/session.h>
@@ -8,12 +12,26 @@
#include "backend/libinput.h"
#include "util/signal.h"
+//TODO: Move out
+static void add_tablet_path(struct wl_list *list, const char *path) {
+ struct wlr_tablet_path *tablet_path = calloc(1, sizeof(struct wlr_tablet_path));
+
+ if (!tablet_path) {
+ return;
+ }
+
+ tablet_path->path = strdup(path);
+ assert(tablet_path->path);
+ wl_list_insert(list, &tablet_path->link);
+}
+
+// FIXME: Decide on how to alloc/count here
static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad,
struct libinput_device *device, unsigned int index) {
struct libinput_tablet_pad_mode_group *li_group =
libinput_device_tablet_pad_get_mode_group(device, index);
- struct wlr_tablet_pad_group_v2 *group =
- calloc(1, sizeof(struct wlr_tablet_pad_group_v2));
+ struct wlr_tablet_pad_group *group =
+ calloc(1, sizeof(struct wlr_tablet_pad_group));
if (!group) {
return;
}
@@ -77,9 +95,11 @@ struct wlr_tablet_pad *libinput_tablet_pad_create(
wlr_tablet_pad->strip_count =
libinput_device_tablet_pad_get_num_strips(libinput_dev);
- //struct udev_device *udev = libinput_device_get_udev_device(libinput_dev);
- //add_tablet_path(&pad->paths, udev_device_get_syspath(udev));
+ wl_list_init(&wlr_tablet_pad->paths);
+ struct udev_device *udev = libinput_device_get_udev_device(libinput_dev);
+ add_tablet_path(&wlr_tablet_pad->paths, udev_device_get_syspath(udev));
+ wl_list_init(&wlr_tablet_pad->groups);
int groups = libinput_device_tablet_pad_get_num_mode_groups(libinput_dev);
for (int i = 0; i < groups; ++i) {
add_pad_group_from_libinput(wlr_tablet_pad, libinput_dev, i);
diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c
index 6c48dcf0..f69e41f8 100644
--- a/backend/libinput/tablet_tool.c
+++ b/backend/libinput/tablet_tool.c
@@ -64,30 +64,32 @@ void wlr_libinput_tablet_tool_destroy(struct wlr_input_device *wlr_dev) {
struct tablet_tool_list_elem *pos;
struct tablet_tool_list_elem *tmp;
wl_list_for_each_safe(pos, tmp, &tablet->tools, link) {
- wl_list_remove(&pos->link);
struct wlr_libinput_tablet_tool *tool = pos->tool;
+ wl_list_remove(&pos->link);
+ free(pos);
if (--tool->pad_refs == 0) {
destroy_tool_tool(tool);
}
-
- free(pos);
}
}
struct wlr_tablet_tool *libinput_tablet_tool_create(
struct libinput_device *libinput_dev) {
assert(libinput_dev);
- struct wlr_tablet_tool *wlr_tablet_tool = calloc(1, sizeof(struct wlr_tablet_tool));
+ struct wlr_libinput_tablet *libinput_tablet_tool =
+ calloc(1, sizeof(struct wlr_libinput_tablet));
+ struct wlr_tablet_tool *wlr_tablet_tool = &libinput_tablet_tool->wlr_tool;
if (!wlr_tablet_tool) {
wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_tool");
return NULL;
}
+ wl_list_init(&wlr_tablet_tool->paths);
struct udev_device *udev = libinput_device_get_udev_device(libinput_dev);
add_tablet_path(&wlr_tablet_tool->paths, udev_device_get_syspath(udev));
wlr_tablet_tool->name = strdup(libinput_device_get_name(libinput_dev));
-
+ wl_list_init(&libinput_tablet_tool->tools);
wlr_tablet_tool_init(wlr_tablet_tool, NULL);
return wlr_tablet_tool;
diff --git a/include/rootston/cursor.h b/include/rootston/cursor.h
index a1a466c2..0478c3ca 100644
--- a/include/rootston/cursor.h
+++ b/include/rootston/cursor.h
@@ -40,6 +40,7 @@ struct roots_cursor {
struct wl_listener tool_axis;
struct wl_listener tool_tip;
+ struct wl_listener tool_proximity;
struct wl_listener request_set_cursor;
};
diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h
index 88c5ca90..d9add26a 100644
--- a/include/rootston/desktop.h
+++ b/include/rootston/desktop.h
@@ -56,6 +56,7 @@ struct roots_desktop {
struct wlr_layer_shell *layer_shell;
struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard;
struct wlr_screencopy_manager_v1 *screencopy;
+ struct wlr_tablet_manager_v2 *tablet_v2;
struct wl_listener new_output;
struct wl_listener layout_change;
diff --git a/include/wlr/types/wlr_tablet_pad.h b/include/wlr/types/wlr_tablet_pad.h
index b633f439..b71f5b9a 100644
--- a/include/wlr/types/wlr_tablet_pad.h
+++ b/include/wlr/types/wlr_tablet_pad.h
@@ -32,7 +32,7 @@ struct wlr_tablet_pad {
void *data;
};
-struct wlr_tablet_pad_group_v2 {
+struct wlr_tablet_pad_group {
struct wl_list link;
size_t button_count;
diff --git a/include/wlr/types/wlr_tablet_tool.h b/include/wlr/types/wlr_tablet_tool.h
index 884b486a..114ce98a 100644
--- a/include/wlr/types/wlr_tablet_tool.h
+++ b/include/wlr/types/wlr_tablet_tool.h
@@ -17,7 +17,7 @@ enum wlr_tablet_tool_type {
Wacom Inking Pen */
WLR_TABLET_TOOL_TYPE_AIRBRUSH, /**< An airbrush-like tool */
WLR_TABLET_TOOL_TYPE_MOUSE, /**< A mouse bound to the tablet */
- WLR_TABLET_TOOL_TYPE_LENS, /**< A mouse tool with a lens */
+ WLR_TABLET_TOOL_TYPE_LENS, /**< A mouse tool with a lens */
};
struct wlr_tablet_tool_tool {
diff --git a/include/wlr/types/wlr_tablet_v2.h b/include/wlr/types/wlr_tablet_v2.h
new file mode 100644
index 00000000..358f0719
--- /dev/null
+++ b/include/wlr/types/wlr_tablet_v2.h
@@ -0,0 +1,62 @@
+#ifndef WLR_TYPES_WLR_TABLET_V2_H
+#define WLR_TYPES_WLR_TABLET_V2_H
+
+#include <wayland-server.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/types/wlr_input_device.h>
+
+struct wlr_tablet_manager_v2 {
+ struct wl_global *wl_global;
+ struct wl_list clients; // wlr_tablet_manager_client_v2::link
+ struct wl_list seats; // wlr_tablet_seat_v2::link
+
+ struct wl_listener display_destroy;
+
+ void *data;
+};
+
+struct wlr_tablet_v2_tablet {
+ struct wl_list link; // wlr_tablet_seat_v2::tablets
+ struct wlr_tablet_tool *wlr_tool;
+ struct wlr_input_device *wlr_device;
+ struct wl_list clients; // wlr_tablet_client_v2::tablet_link
+
+ struct wl_listener tool_destroy;
+};
+
+struct wlr_tablet_v2_tablet_tool {
+ struct wl_list link; // wlr_tablet_seat_v2::tablets
+ struct wlr_tablet_tool_tool *wlr_tool;
+ struct wl_list clients; // wlr_tablet_tool_client_v2::tablet_link
+
+ struct wl_listener tool_destroy;
+};
+
+struct wlr_tablet_v2_tablet_pad {
+ struct wl_list link; // wlr_tablet_seat_v2::pads
+ struct wlr_tablet_pad *wlr_pad;
+ struct wlr_input_device *wlr_device;
+ struct wl_list clients; // wlr_tablet_pad_client_v2::tablet_link
+
+ struct wl_listener pad_destroy;
+};
+
+struct wlr_tablet_v2_tablet *wlr_make_tablet(
+ struct wlr_tablet_manager_v2 *manager,
+ struct wlr_seat *wlr_seat,
+ struct wlr_input_device *wlr_device);
+
+struct wlr_tablet_v2_tablet_pad *wlr_make_tablet_pad(
+ struct wlr_tablet_manager_v2 *manager,
+ struct wlr_seat *wlr_seat,
+ struct wlr_input_device *wlr_device);
+
+struct wlr_tablet_v2_tablet_tool *wlr_make_tablet_tool(
+ struct wlr_tablet_manager_v2 *manager,
+ struct wlr_seat *wlr_seat,
+ struct wlr_tablet_tool_tool *wlr_tool);
+
+struct wlr_tablet_manager_v2 *wlr_tablet_v2_create(struct wl_display *display);
+void wlr_tablet_v2_destroy(struct wlr_tablet_manager_v2 *manager);
+
+#endif /* WLR_TYPES_WLR_TABLET_V2_H */
diff --git a/rootston/desktop.c b/rootston/desktop.c
index 563c5938..3f9faf24 100644
--- a/rootston/desktop.c
+++ b/rootston/desktop.c
@@ -22,6 +22,8 @@
#include <wlr/types/wlr_xdg_output.h>
#include <wlr/types/wlr_xdg_shell_v6.h>
#include <wlr/types/wlr_xdg_shell.h>
+#include <wlr/types/wlr_xdg_output.h>
+#include <wlr/types/wlr_tablet_v2.h>
#include <wlr/util/log.h>
#include "rootston/layers.h"
#include "rootston/seat.h"
@@ -801,6 +803,8 @@ struct roots_desktop *desktop_create(struct roots_server *server,
&desktop->layer_shell_surface);
desktop->layer_shell_surface.notify = handle_layer_shell_surface;
+ desktop->tablet_v2 = wlr_tablet_v2_create(server->wl_display);
+
#ifdef WLR_HAS_XWAYLAND
const char *cursor_theme = NULL;
const char *cursor_default = ROOTS_XCURSOR_DEFAULT;
diff --git a/rootston/seat.c b/rootston/seat.c
index 544cfb90..455e9b00 100644
--- a/rootston/seat.c
+++ b/rootston/seat.c
@@ -8,6 +8,7 @@
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_layer_shell.h>
#include <wlr/types/wlr_xcursor_manager.h>
+#include <wlr/types/wlr_tablet_v2.h>
#include <wlr/util/log.h>
#include "rootston/cursor.h"
#include "rootston/input.h"
@@ -115,6 +116,19 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
roots_cursor_handle_tool_tip(cursor, event);
}
+static void handle_tool_proximity(struct wl_listener *listener, void *data) {
+ struct roots_cursor *cursor =
+ wl_container_of(listener, cursor, tool_proximity);
+ struct roots_desktop *desktop = cursor->seat->input->server->desktop;
+ wlr_idle_notify_activity(desktop->idle, cursor->seat->seat);
+ struct wlr_event_tablet_tool_proximity *event = data;
+
+ struct wlr_tablet_tool_tool *tool = event->tool;
+ if (!tool->data) {
+ tool->data = wlr_make_tablet_tool(desktop->tablet_v2, cursor->seat->seat, tool);
+ }
+}
+
static void handle_request_set_cursor(struct wl_listener *listener,
void *data) {
struct roots_cursor *cursor =
@@ -251,6 +265,9 @@ static void roots_seat_init_cursor(struct roots_seat *seat) {
wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &seat->cursor->tool_tip);
seat->cursor->tool_tip.notify = handle_tool_tip;
+ wl_signal_add(&wlr_cursor->events.tablet_tool_proximity, &seat->cursor->tool_proximity);
+ seat->cursor->tool_proximity.notify = handle_tool_proximity;
+
wl_signal_add(&seat->seat->events.request_set_cursor,
&seat->cursor->request_set_cursor);
seat->cursor->request_set_cursor.notify = handle_request_set_cursor;
@@ -532,6 +549,10 @@ static void seat_add_touch(struct roots_seat *seat,
static void seat_add_tablet_pad(struct roots_seat *seat,
struct wlr_input_device *device) {
// TODO
+ // FIXME: This needs to be stored on the roots_tablet_tool
+ struct roots_desktop *desktop = seat->input->server->desktop;
+ (void)wlr_make_tablet_pad(desktop->tablet_v2, seat->seat, device);
+
}
static void handle_tablet_tool_destroy(struct wl_listener *listener,
@@ -568,6 +589,11 @@ static void seat_add_tablet_tool(struct roots_seat *seat,
wlr_cursor_attach_input_device(seat->cursor->cursor, device);
roots_seat_configure_cursor(seat);
+
+ struct roots_desktop *desktop = seat->input->server->desktop;
+
+ // FIXME: This needs to be stored on the roots_tablet_tool
+ (void)wlr_make_tablet(desktop->tablet_v2, seat->seat, device);
}
void roots_seat_add_device(struct roots_seat *seat,
diff --git a/types/wlr_tablet_v2.c b/types/wlr_tablet_v2.c
index 56f4d567..db08c184 100644
--- a/types/wlr_tablet_v2.c
+++ b/types/wlr_tablet_v2.c
@@ -2,6 +2,9 @@
#define _POSIX_C_SOURCE 200809L
#endif
+#include <wlr/types/wlr_tablet_v2.h>
+
+#include <wlr/util/log.h>
#include <assert.h>
#include <libinput.h>
#include <string.h>
@@ -9,17 +12,22 @@
#include <wayland-server.h>
#include <wlr/config.h>
#include <wlr/types/wlr_seat.h>
+#include <wlr/types/wlr_tablet_tool.h>
#include "tablet-unstable-v2-protocol.h"
+struct wlr_tablet_seat_v2 {
+ struct wl_list link;
+ struct wlr_seat *wlr_seat;
+ struct wlr_tablet_manager_v2 *manager;
-struct wlr_tablet_manager_v2 {
- struct wl_global *wl_global;
- struct wl_list clients; // wlr_tablet_manager_client_v2::link
+ struct wl_list tablets; // wlr_tablet_v2_tablet::link
+ struct wl_list tools;
+ struct wl_list pads;
- struct wl_listener display_destroy;
+ struct wl_list clients; //wlr_tablet_seat_v2_client::link;
- void *data;
+ struct wl_listener seat_destroy;
};
struct wlr_tablet_manager_client_v2 {
@@ -29,19 +37,19 @@ struct wlr_tablet_manager_client_v2 {
struct wlr_tablet_manager_v2 *manager;
- struct wl_list tablet_seats; // wlr_tablet_seat_v2::link
+ struct wl_list tablet_seats; // wlr_tablet_seat_client_v2::link
};
-struct wlr_tablet_seat_v2 {
- struct wl_list link;
+struct wlr_tablet_seat_client_v2 {
+ struct wl_list seat_link;
+ struct wl_list client_link;
struct wl_client *wl_client;
struct wl_resource *resource;
struct wlr_tablet_manager_client_v2 *client;
struct wlr_seat_client *seat;
- struct wl_listener seat_destroy;
- struct wl_listener client_destroy;
+ struct wl_listener seat_client_destroy;
struct wl_list tools;
struct wl_list tablets;
@@ -49,16 +57,17 @@ struct wlr_tablet_seat_v2 {
};
struct wlr_tablet_client_v2 {
- struct wl_list link;
+ struct wl_list seat_link; // wlr_tablet_seat_client_v2::tablet
+ struct wl_list tablet_link; // wlr_tablet_v2_tablet::clients
struct wl_client *client;
struct wl_resource *resource;
struct wl_listener device_destroy;
- struct wl_listener client_destroy;
};
struct wlr_tablet_tool_client_v2 {
- struct wl_list link;
+ struct wl_list seat_link;
+ struct wl_list tool_link;
struct wl_client *client;
struct wl_resource *resource;
@@ -66,26 +75,587 @@ struct wlr_tablet_tool_client_v2 {
struct wl_listener cursor_destroy;
struct wl_listener tool_destroy;
- struct wl_listener client_destroy;
};
struct wlr_tablet_pad_client_v2 {
- struct wl_list link;
+ struct wl_list seat_link;
+ struct wl_list pad_link;
struct wl_client *client;
struct wl_resource *resource;
size_t button_count;
- size_t ring_cout;
+ size_t group_count;
+ struct wl_resource **groups;
+
+ size_t ring_count;
struct wl_resource **rings;
- size_t strip_cout;
+ size_t strip_count;
struct wl_resource **strips;
struct wl_listener device_destroy;
- struct wl_listener client_destroy;
};
+static struct zwp_tablet_v2_interface tablet_impl;
+
+static struct wlr_tablet_client_v2 *tablet_client_from_resource(struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &zwp_tablet_v2_interface,
+ &tablet_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+static void destroy_tablet_v2(struct wl_resource *resource) {
+ struct wlr_tablet_client_v2 *tablet = tablet_client_from_resource(resource);
+
+ wl_list_remove(&tablet->seat_link);
+ wl_list_remove(&tablet->tablet_link);
+
+ //wl_list_remove(tablet->device_destroy.link);
+ //wl_list_remove(tablet->client_destroy.link);
+}
+
+static void handle_tablet_v2_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static struct zwp_tablet_v2_interface tablet_impl = {
+ .destroy = handle_tablet_v2_destroy,
+};
+
+static struct wlr_tablet_seat_v2 *make_tablet_seat(
+ struct wlr_tablet_manager_v2 *manager,
+ struct wlr_seat *wlr_seat) {
+ struct wlr_tablet_seat_v2 *tablet_seat =
+ calloc(1, sizeof(struct wlr_tablet_seat_v2));
+ if (!tablet_seat) {
+ return NULL;
+ }
+
+ tablet_seat->manager = manager;
+ tablet_seat->wlr_seat = wlr_seat;
+
+ wl_list_init(&tablet_seat->clients);
+
+ wl_list_init(&tablet_seat->tablets);
+ wl_list_init(&tablet_seat->tools);
+ wl_list_init(&tablet_seat->pads);
+
+ wl_list_insert(&manager->seats, &tablet_seat->link);
+ return tablet_seat;
+}
+
+static struct wlr_tablet_seat_v2 *get_or_make_tablet_seat(
+ struct wlr_tablet_manager_v2 *manager,
+ struct wlr_seat *wlr_seat) {
+ struct wlr_tablet_seat_v2 *pos;
+ wl_list_for_each(pos, &manager->seats, link) {
+ if (pos->wlr_seat == wlr_seat) {
+ return pos;
+ }
+ }
+
+ return make_tablet_seat(manager, wlr_seat);
+}
+
+static void add_tablet_client(struct wlr_tablet_seat_client_v2 *seat,
+ struct wlr_tablet_v2_tablet *tablet) {
+ struct wlr_tablet_client_v2 *client =
+ calloc(1, sizeof(struct wlr_tablet_client_v2));
+ if (!client) {
+ return;
+ }
+
+ client->resource =
+ wl_resource_create(seat->wl_client, &zwp_tablet_v2_interface, 1, 0);
+ if (!client->resource) {
+ free(client);
+ return;
+ }
+ wl_resource_set_implementation(client->resource, &tablet_impl,
+ client, destroy_tablet_v2);
+ zwp_tablet_seat_v2_send_tablet_added(seat->resource, client->resource);
+
+ // Send the expected events
+ if (tablet->wlr_tool->name) {
+ zwp_tablet_v2_send_name(client->resource, tablet->wlr_tool->name);
+ }
+ zwp_tablet_v2_send_id(client->resource,
+ tablet->wlr_device->vendor, tablet->wlr_device->product);
+ struct wlr_tablet_path *path;
+ wl_list_for_each(path, &tablet->wlr_tool->paths, link) {
+ zwp_tablet_v2_send_path(client->resource, path->path);
+ }
+ zwp_tablet_v2_send_done(client->resource);
+
+ client->client = seat->wl_client;
+ wl_list_insert(&seat->tablets, &client->seat_link);
+ wl_list_insert(&tablet->clients, &client->tablet_link);
+}
+
+static void handle_wlr_tablet_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_tablet_v2_tablet *tablet =
+ wl_container_of(listener, tablet, tool_destroy);
+
+ struct wlr_tablet_client_v2 *pos;
+ struct wlr_tablet_client_v2 *tmp;
+ wl_list_for_each_safe(pos, tmp, &tablet->clients, tablet_link) {
+ // XXX: Add a timer/flag to destroy if client is slow?
+ zwp_tablet_v2_send_removed(pos->resource);
+ }
+
+ wl_list_remove(&tablet->clients);
+ wl_list_remove(&tablet->link);
+ wl_list_remove(&tablet->tool_destroy.link);
+ free(tablet);
+}
+
+static void handle_tablet_tool_v2_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+static struct zwp_tablet_tool_v2_interface tablet_tool_impl = {
+ .set_cursor = NULL,
+ .destroy = handle_tablet_tool_v2_destroy,
+};
+
+static enum zwp_tablet_tool_v2_type tablet_type_from_wlr_type(
+ enum wlr_tablet_tool_type wlr_type) {
+ switch(wlr_type) {
+ case WLR_TABLET_TOOL_TYPE_PEN:
+ return ZWP_TABLET_TOOL_V2_TYPE_PEN;
+ case WLR_TABLET_TOOL_TYPE_ERASER:
+ return ZWP_TABLET_TOOL_V2_TYPE_ERASER;
+ case WLR_TABLET_TOOL_TYPE_BRUSH:
+ return ZWP_TABLET_TOOL_V2_TYPE_BRUSH;
+ case WLR_TABLET_TOOL_TYPE_PENCIL:
+ return ZWP_TABLET_TOOL_V2_TYPE_PENCIL;
+ case WLR_TABLET_TOOL_TYPE_AIRBRUSH:
+ return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH;
+ case WLR_TABLET_TOOL_TYPE_MOUSE:
+ return ZWP_TABLET_TOOL_V2_TYPE_MOUSE;
+ case WLR_TABLET_TOOL_TYPE_LENS:
+ return ZWP_TABLET_TOOL_V2_TYPE_LENS;
+ }
+
+ assert(false && "Unreachable");
+}
+
+static void add_tablet_tool_client(struct wlr_tablet_seat_client_v2 *seat,
+ struct wlr_tablet_v2_tablet_tool *tool) {
+ struct wlr_tablet_tool_client_v2 *client =
+ calloc(1, sizeof(struct wlr_tablet_tool_client_v2));
+ if (!client) {
+ return;
+ }
+
+ client->resource =
+ wl_resource_create(seat->wl_client, &zwp_tablet_tool_v2_interface, 1, 0);
+ if (!client->resource) {
+ free(client);
+ return;
+ }
+ wl_resource_set_implementation(client->resource, &tablet_tool_impl,
+ client, NULL);
+ zwp_tablet_seat_v2_send_tool_added(seat->resource, client->resource);
+
+ // Send the expected events
+ if (tool->wlr_tool->hardware_serial) {
+ zwp_tablet_tool_v2_send_hardware_serial(
+ client->resource,
+ tool->wlr_tool->hardware_serial >> 32,
+ tool->wlr_tool->hardware_serial & 0xFFFFFFFF);
+ }
+ if (tool->wlr_tool->hardware_wacom) {
+ zwp_tablet_tool_v2_send_hardware_id_wacom(
+ client->resource,
+ tool->wlr_tool->hardware_wacom >> 32,
+ tool->wlr_tool->hardware_wacom & 0xFFFFFFFF);
+ }
+ zwp_tablet_tool_v2_send_type(client->resource,
+ tablet_type_from_wlr_type(tool->wlr_tool->type));
+
+ if (tool->wlr_tool->tilt) {
+ zwp_tablet_tool_v2_send_capability(client->resource,
+ ZWP_TABLET_TOOL_V2_CAPABILITY_TILT);
+ }
+
+ if (tool->wlr_tool->pressure) {
+ zwp_tablet_tool_v2_send_capability(client->resource,
+ ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE);
+ }
+
+ if (tool->wlr_tool->distance) {
+ zwp_tablet_tool_v2_send_capability(client->resource,
+ ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE);
+ }
+
+ if (tool->wlr_tool->rotation) {
+ zwp_tablet_tool_v2_send_capability(client->resource,
+ ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION);
+ }
+
+ if (tool->wlr_tool->slider) {
+ zwp_tablet_tool_v2_send_capability(client->resource,
+ ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER);
+ }
+
+ if (tool->wlr_tool->wheel) {
+ zwp_tablet_tool_v2_send_capability(client->resource,
+ ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL);
+ }
+
+ zwp_tablet_tool_v2_send_done(client->resource);
+
+ client->client = seat->wl_client;
+ wl_list_insert(&seat->tools, &client->seat_link);
+ wl_list_insert(&tool->clients, &client->tool_link);
+}
+
+struct wlr_tablet_v2_tablet *wlr_make_tablet(
+ struct wlr_tablet_manager_v2 *manager,
+ struct wlr_seat *wlr_seat,
+ struct wlr_input_device *wlr_device) {
+ assert(wlr_device->type == WLR_INPUT_DEVICE_TABLET_TOOL);
+ struct wlr_tablet_seat_v2 *seat = get_or_make_tablet_seat(manager, wlr_seat);
+ if (!seat) {
+ return NULL;
+ }
+ struct wlr_tablet_tool *tool = wlr_device->tablet_tool;
+ struct wlr_tablet_v2_tablet *tablet = calloc(1, sizeof(struct wlr_tablet_v2_tablet));
+ if (!tablet) {
+ return NULL;
+ }
+
+ tablet->wlr_tool = tool;
+ tablet->wlr_device = wlr_device;
+ wl_list_init(&tablet->clients);
+
+
+ tablet->tool_destroy.notify = handle_wlr_tablet_destroy;
+ wl_signal_add(&wlr_device->events.destroy, &tablet->tool_destroy);
+ wl_list_insert(&seat->tablets, &tablet->link);
+
+ // We need to create a tablet client for all clients on the seat
+ struct wlr_tablet_seat_client_v2 *pos;
+ wl_list_for_each(pos, &seat->clients, seat_link) {
+ // Tell the clients about the new tool
+ add_tablet_client(pos, tablet);
+ }
+
+ return tablet;
+}
+
+static void handle_wlr_tablet_tool_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_tablet_v2_tablet_tool *tool =
+ wl_container_of(listener, tool, tool_destroy);
+
+ struct wlr_tablet_tool_client_v2 *pos;
+ struct wlr_tablet_tool_client_v2 *tmp;
+ wl_list_for_each_safe(pos, tmp, &tool->clients, tool_link) {
+ // XXX: Add a timer/flag to destroy if client is slow?
+ zwp_tablet_tool_v2_send_removed(pos->resource);
+ }
+
+ wl_list_remove(&tool->clients);
+ wl_list_remove(&tool->link);
+ wl_list_remove(&tool->tool_destroy.link);
+ free(tool);
+}
+
+struct wlr_tablet_v2_tablet_tool *wlr_make_tablet_tool(
+ struct wlr_tablet_manager_v2 *manager,
+ struct wlr_seat *wlr_seat,
+ struct wlr_tablet_tool_tool *wlr_tool) {
+ struct wlr_tablet_seat_v2 *seat = get_or_make_tablet_seat(manager, wlr_seat);
+ if (!seat) {
+ return NULL;
+ }
+ struct wlr_tablet_v2_tablet_tool *tool =
+ calloc(1, sizeof(struct wlr_tablet_v2_tablet_tool));
+ if (!tool) {
+ return NULL;
+ }
+
+ tool->wlr_tool = wlr_tool;
+ wl_list_init(&tool->clients);
+
+
+ tool->tool_destroy.notify = handle_wlr_tablet_tool_destroy;
+ wl_signal_add(&wlr_tool->events.destroy, &tool->tool_destroy);
+ wl_list_insert(&seat->tools, &tool->link);
+
+ // We need to create a tablet client for all clients on the seat
+ struct wlr_tablet_seat_client_v2 *pos;
+ wl_list_for_each(pos, &seat->clients, seat_link) {
+ // Tell the clients about the new tool
+ add_tablet_tool_client(pos, tool);
+ }
+
+ return tool;
+}
+
+static struct zwp_tablet_pad_v2_interface tablet_pad_impl;
+
+static struct wlr_tablet_pad_client_v2 *tablet_pad_client_from_resource(struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &zwp_tablet_pad_v2_interface,
+ &tablet_pad_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+
+static void destroy_tablet_pad_v2(struct wl_resource *resource) {
+ struct wlr_tablet_pad_client_v2 *pad =
+ tablet_pad_client_from_resource(resource);
+
+ wl_list_remove(&pad->seat_link);
+ wl_list_remove(&pad->pad_link);
+
+ //wl_list_remove(tablet->device_destroy.link);
+ //wl_list_remove(tablet->client_destroy.link);
+}
+
+static void handle_tablet_pad_v2_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static void destroy_tablet_pad_ring_v2(struct wl_resource *resource) {
+ struct wlr_tablet_pad_client_v2 *client = wl_resource_get_user_data(resource);
+
+ for (size_t i = 0; i < client->ring_count; ++i) {
+ if (client->rings[i] == resource) {
+ client->rings[i] = NULL;
+ return;
+ }
+ }
+}
+
+static void handle_tablet_pad_ring_v2_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static struct zwp_tablet_pad_ring_v2_interface tablet_pad_ring_impl = {
+ .set_feedback = NULL,
+ .destroy = handle_tablet_pad_ring_v2_destroy,
+};
+
+static void destroy_tablet_pad_strip_v2(struct wl_resource *resource) {
+ struct wlr_tablet_pad_client_v2 *client = wl_resource_get_user_data(resource);
+
+ for (size_t i = 0; i < client->strip_count; ++i) {
+ if (client->strips[i] == resource) {
+ client->strips[i] = NULL;
+ return;
+ }
+ }
+}
+
+static void handle_tablet_pad_strip_v2_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static struct zwp_tablet_pad_strip_v2_interface tablet_pad_strip_impl = {
+ .set_feedback = NULL,
+ .destroy = handle_tablet_pad_strip_v2_destroy,
+};
+
+static struct zwp_tablet_pad_v2_interface tablet_pad_impl = {
+ .set_feedback = NULL,
+ .destroy = handle_tablet_pad_v2_destroy,
+};
+
+static void destroy_tablet_pad_group_v2(struct wl_resource *resource) {
+ struct wlr_tablet_pad_client_v2 *client = wl_resource_get_user_data(resource);
+
+ for (size_t i = 0; i < client->group_count; ++i) {
+ if (client->groups[i] == resource) {
+ client->groups[i] = NULL;
+ return;
+ }
+ }
+}
+
+static void handle_tablet_pad_group_v2_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static struct zwp_tablet_pad_group_v2_interface tablet_pad_group_impl = {
+ .destroy = handle_tablet_pad_group_v2_destroy,
+};
+
+static void add_tablet_pad_group(struct wlr_tablet_v2_tablet_pad *pad,
+ struct wlr_tablet_pad_client_v2 *client,
+ struct wlr_tablet_pad_group *group, size_t index) {
+ client->groups[index] =
+ wl_resource_create(client->client, &zwp_tablet_pad_group_v2_interface, 1, 0);
+ if (!client->groups[index]) {
+ wl_client_post_no_memory(client->client);
+ return;
+ }
+ wl_resource_set_implementation(client->groups[index], &tablet_pad_group_impl,
+ client, destroy_tablet_pad_group_v2);
+
+ zwp_tablet_pad_v2_send_group(client->resource, client->groups[index]);
+ zwp_tablet_pad_group_v2_send_modes(client->groups[index], group->mode_count);
+
+ struct wl_array button_array;
+ wl_array_init(&button_array);
+ wl_array_add(&button_array, group->button_count * sizeof(int));
+ memcpy(button_array.data, group->buttons, group->button_count * sizeof(int));
+ zwp_tablet_pad_group_v2_send_buttons(client->groups[index], &button_array);
+
+ client->strip_count = group->strip_count;
+ for (size_t i = 0; i < group->strip_count; ++i) {
+ size_t strip = group->strips[i];
+ client->strips[strip] =
+ wl_resource_create(client->client, &zwp_tablet_pad_strip_v2_interface, 1, 0);
+ wl_resource_set_implementation(client->strips[strip],
+ &tablet_pad_strip_impl,
+ client, destroy_tablet_pad_strip_v2);
+ zwp_tablet_pad_group_v2_send_strip(client->groups[index], client->strips[strip]);
+ }
+
+ client->ring_count = group->ring_count;
+ for (size_t i = 0; i < group->ring_count; ++i) {
+ size_t ring = group->rings[i];
+ client->rings[ring] =
+ wl_resource_create(client->client, &zwp_tablet_pad_ring_v2_interface, 1, 0);
+ wl_resource_set_implementation(client->rings[ring],
+ &tablet_pad_ring_impl,
+ client, destroy_tablet_pad_ring_v2);
+ zwp_tablet_pad_group_v2_send_ring(client->groups[index], client->rings[ring]);
+ }
+
+ zwp_tablet_pad_group_v2_send_done(client->groups[index]);
+}
+
+static void add_tablet_pad_client(struct wlr_tablet_seat_client_v2 *seat,
+ struct wlr_tablet_v2_tablet_pad *pad) {
+ struct wlr_tablet_pad_client_v2 *client =
+ calloc(1, sizeof(struct wlr_tablet_pad_client_v2));
+ if (!client) {
+ wl_client_post_no_memory(seat->wl_client);
+ return;
+ }
+
+ client->groups = calloc(sizeof(int), wl_list_length(&pad->wlr_pad->groups));
+ if (!client->groups) {
+ wl_client_post_no_memory(seat->wl_client);
+ free(client);
+ return;
+ }
+
+ client->rings = calloc(sizeof(struct wl_resource*), pad->wlr_pad->ring_count);
+ if (!client->rings) {
+ wl_client_post_no_memory(seat->wl_client);
+ free(client->groups);
+ free(client);
+ return;
+ }
+
+ client->strips = calloc(sizeof(struct wl_resource*), pad->wlr_pad->strip_count);
+ if (!client->strips) {
+ wl_client_post_no_memory(seat->wl_client);
+ free(client->groups);
+ free(client->rings);
+ free(client);
+ return;
+ }
+
+ client->resource =
+ wl_resource_create(seat->wl_client, &zwp_tablet_pad_v2_interface, 1, 0);
+ if (!client->resource) {
+ wl_client_post_no_memory(seat->wl_client);
+ free(client->groups);
+ free(client->rings);
+ free(client->strips);
+ free(client);
+ return;
+ }
+ wl_resource_set_implementation(client->resource, &tablet_pad_impl,
+ client, destroy_tablet_pad_v2);
+ zwp_tablet_seat_v2_send_pad_added(seat->resource, client->resource);
+ client->client = seat->wl_client;
+
+ // Send the expected events
+ if (pad->wlr_pad->button_count) {
+ zwp_tablet_pad_v2_send_buttons(client->resource, pad->wlr_pad->button_count);
+ }
+ struct wlr_tablet_path *path;
+ wl_list_for_each(path, &pad->wlr_pad->paths, link) {
+ zwp_tablet_pad_v2_send_path(client->resource, path->path);
+ }
+ size_t i = 0;
+ struct wlr_tablet_pad_group *group;
+ wl_list_for_each(group, &pad->wlr_pad->groups, link) {
+ add_tablet_pad_group(pad, client, group, i++);
+ }
+ zwp_tablet_pad_v2_send_done(client->resource);
+
+ wl_list_insert(&seat->pads, &client->seat_link);
+ wl_list_insert(&pad->clients, &client->pad_link);
+}
+
+static void handle_wlr_tablet_pad_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_tablet_v2_tablet_pad *pad =
+ wl_container_of(listener, pad, pad_destroy);
+
+ struct wlr_tablet_pad_client_v2 *pos;
+ struct wlr_tablet_pad_client_v2 *tmp;
+ wl_list_for_each_safe(pos, tmp, &pad->clients, pad_link) {
+ // XXX: Add a timer/flag to destroy if client is slow?
+ zwp_tablet_pad_v2_send_removed(pos->resource);
+ }
+
+ wl_list_remove(&pad->clients);
+ wl_list_remove(&pad->link);
+ wl_list_remove(&pad->pad_destroy.link);
+ free(pad);
+}
+
+struct wlr_tablet_v2_tablet_pad *wlr_make_tablet_pad(
+ struct wlr_tablet_manager_v2 *manager,
+ struct wlr_seat *wlr_seat,
+ struct wlr_input_device *wlr_device) {
+ assert(wlr_device->type == WLR_INPUT_DEVICE_TABLET_PAD);
+ struct wlr_tablet_seat_v2 *seat = get_or_make_tablet_seat(manager, wlr_seat);
+ if (!seat) {
+ return NULL;
+ }
+ struct wlr_tablet_pad *wlr_pad = wlr_device->tablet_pad;
+ struct wlr_tablet_v2_tablet_pad *pad = calloc(1, sizeof(struct wlr_tablet_v2_tablet_pad));
+ if (!pad) {
+ return NULL;
+ }
+
+ pad->wlr_pad = wlr_pad;
+ wl_list_init(&pad->clients);
+
+ pad->pad_destroy.notify = handle_wlr_tablet_pad_destroy;
+ wl_signal_add(&wlr_device->events.destroy, &pad->pad_destroy);
+ wl_list_insert(&seat->pads, &pad->link);
+
+ // We need to create a tablet client for all clients on the seat
+ struct wlr_tablet_seat_client_v2 *pos;
+ wl_list_for_each(pos, &seat->clients, seat_link) {
+ // Tell the clients about the new tool
+ add_tablet_pad_client(pos, pad);
+ }
+
+ wlr_log(L_DEBUG, "Created tablet v2 pad:");
+ struct wlr_tablet_path *path;
+ wl_list_for_each(path, &wlr_pad->paths, link) {
+ wlr_log(L_DEBUG, "%s", path->path);
+ }
+
+ return pad;
+}
+
void wlr_tablet_v2_destroy(struct wlr_tablet_manager_v2 *manager);
static struct wlr_tablet_manager_client_v2 *tablet_manager_client_from_resource(struct wl_resource *resource);
@@ -98,15 +668,15 @@ static struct zwp_tablet_seat_v2_interface seat_impl = {
.destroy = tablet_seat_destroy,
};
-static struct wlr_tablet_seat_v2 *tablet_seat_from_resource (
+static struct wlr_tablet_seat_client_v2 *tablet_seat_from_resource (
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &zwp_tablet_seat_v2_interface,
&seat_impl));
return wl_resource_get_user_data(resource);
}
-static void wlr_tablet_seat_v2_destroy(struct wl_resource *resource) {
- struct wlr_tablet_seat_v2 *seat = tablet_seat_from_resource(resource);
+static void wlr_tablet_seat_client_v2_destroy(struct wl_resource *resource) {
+ struct wlr_tablet_seat_client_v2 *seat = tablet_seat_from_resource(resource);
seat->resource = NULL;
/* We can't just destroy the struct, because we may need to iterate it
@@ -116,15 +686,15 @@ static void wlr_tablet_seat_v2_destroy(struct wl_resource *resource) {
}
static void handle_seat_destroy(struct wl_listener *listener, void *data) {
- struct wlr_tablet_seat_v2 *seat =
- wl_container_of(listener, seat, seat_destroy);
+ struct wlr_tablet_seat_client_v2 *seat =
+ wl_container_of(listener, seat, seat_client_destroy);
seat->seat = NULL;
- wl_list_remove(&seat->seat_destroy.link);
+ wl_list_remove(&seat->seat_client_destroy.link);
/* Remove leaves it in a defunct state, we will remove again in the
* actual destroy sequence
*/
- wl_list_init(&seat->seat_destroy.link);
+ wl_list_init(&seat->seat_client_destroy.link);
}
static void tablet_manager_destroy(struct wl_client *client,
@@ -137,32 +707,60 @@ static void get_tablet_seat(struct wl_client *wl_client, struct wl_resource *res
{
struct wlr_tablet_manager_client_v2 *manager = tablet_manager_client_from_resource(resource);
struct wlr_seat_client *seat = wlr_seat_client_from_resource(seat_resource);
-
struct wlr_tablet_seat_v2 *tablet_seat =
- calloc(1, sizeof(struct wlr_tablet_seat_v2));
+ get_or_make_tablet_seat(manager->manager, seat->seat);
+
+ if (!tablet_seat) {// This can only happen when we ran out of memory
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ struct wlr_tablet_seat_client_v2 *seat_client =
+ calloc(1, sizeof(struct wlr_tablet_seat_client_v2));
if (tablet_seat == NULL) {
wl_client_post_no_memory(wl_client);
return;
}
- tablet_seat->resource =
+ seat_client->resource =
wl_resource_create(wl_client, &zwp_tablet_seat_v2_interface, 1, id);
- if (tablet_seat->resource == NULL) {
- free(tablet_seat);
+ if (seat_client->resource == NULL) {
+ free(seat_client);
wl_client_post_no_memory(wl_client);
return;
}
+ wl_resource_set_implementation(seat_client->resource, &seat_impl, seat_client,
+ wlr_tablet_seat_client_v2_destroy);
+
+ seat_client->seat = seat;
+ seat_client->client = manager;
+ seat_client->wl_client = wl_client;
+ wl_list_init(&seat_client->tools);
+ wl_list_init(&seat_client->tablets);
+ wl_list_init(&seat_client->pads);
- tablet_seat->seat = seat;
- tablet_seat->client = manager;
+ seat_client->seat_client_destroy.notify = handle_seat_destroy;
+ wl_signal_add(&seat->events.destroy, &seat_client->seat_client_destroy);
- tablet_seat->seat_destroy.notify = handle_seat_destroy;
- wl_signal_add(&seat->events.destroy, &tablet_seat->seat_destroy);
+ wl_list_insert(&manager->tablet_seats, &seat_client->client_link);
+ wl_list_insert(&tablet_seat->clients, &seat_client->seat_link);
+
+ // We need to emmit the devices allready on the seat
+ struct wlr_tablet_v2_tablet *tablet_pos;
+ wl_list_for_each(tablet_pos, &tablet_seat->tablets, link) {
+ add_tablet_client(seat_client, tablet_pos);
+ }
- wl_resource_set_implementation(tablet_seat->resource, &seat_impl, tablet_seat,
- wlr_tablet_seat_v2_destroy);
- wl_list_insert(&manager->tablet_seats, &tablet_seat->link);
+ struct wlr_tablet_v2_tablet_pad *pad_pos;
+ wl_list_for_each(pad_pos, &tablet_seat->pads, link) {
+ add_tablet_pad_client(seat_client, pad_pos);
+ }
+
+ struct wlr_tablet_v2_tablet_tool *tool_pos;
+ wl_list_for_each(tool_pos, &tablet_seat->tools, link) {
+ add_tablet_tool_client(seat_client, tool_pos);
+ }
}
static struct zwp_tablet_manager_v2_interface manager_impl = {
@@ -242,6 +840,7 @@ struct wlr_tablet_manager_v2 *wlr_tablet_v2_create(struct wl_display *display) {
}
wl_list_init(&tablet->clients);
+ wl_list_init(&tablet->seats);
tablet->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &tablet->display_destroy);