stabilise tablet_v2 code (prevent bunch of crashes)

This commit is contained in:
Markus Ongyerth 2018-04-24 15:47:41 +02:00
parent e235f7d336
commit f696e980f1
1 changed files with 110 additions and 44 deletions

View File

@ -34,9 +34,9 @@ struct wlr_tablet_manager_client_v2 {
struct wl_list link; struct wl_list link;
struct wl_client *client; struct wl_client *client;
struct wl_resource *resource; struct wl_resource *resource;
struct wlr_tablet_manager_v2 *manager; struct wlr_tablet_manager_v2 *manager;
struct wl_listener client_destroy;
struct wl_list tablet_seats; // wlr_tablet_seat_client_v2::link struct wl_list tablet_seats; // wlr_tablet_seat_client_v2::link
}; };
@ -51,9 +51,9 @@ struct wlr_tablet_seat_client_v2 {
struct wl_listener seat_client_destroy; struct wl_listener seat_client_destroy;
struct wl_list tools; struct wl_list tools; //wlr_tablet_tool_client_v2::link
struct wl_list tablets; struct wl_list tablets; //wlr_tablet_client_v2::link
struct wl_list pads; //wlr_tablet_pad_client_v2::link struct wl_list pads; //wlr_tablet_pad_client_v2::link
}; };
struct wlr_tablet_client_v2 { struct wlr_tablet_client_v2 {
@ -61,8 +61,6 @@ struct wlr_tablet_client_v2 {
struct wl_list tablet_link; // wlr_tablet_v2_tablet::clients struct wl_list tablet_link; // wlr_tablet_v2_tablet::clients
struct wl_client *client; struct wl_client *client;
struct wl_resource *resource; struct wl_resource *resource;
struct wl_listener device_destroy;
}; };
struct wlr_tablet_tool_client_v2 { struct wlr_tablet_tool_client_v2 {
@ -70,11 +68,6 @@ struct wlr_tablet_tool_client_v2 {
struct wl_list tool_link; struct wl_list tool_link;
struct wl_client *client; struct wl_client *client;
struct wl_resource *resource; struct wl_resource *resource;
struct wlr_surface *cursor;
struct wl_listener cursor_destroy;
struct wl_listener tool_destroy;
}; };
struct wlr_tablet_pad_client_v2 { struct wlr_tablet_pad_client_v2 {
@ -93,8 +86,6 @@ struct wlr_tablet_pad_client_v2 {
size_t strip_count; size_t strip_count;
struct wl_resource **strips; struct wl_resource **strips;
struct wl_listener device_destroy;
}; };
static struct zwp_tablet_v2_interface tablet_impl; static struct zwp_tablet_v2_interface tablet_impl;
@ -110,9 +101,7 @@ static void destroy_tablet_v2(struct wl_resource *resource) {
wl_list_remove(&tablet->seat_link); wl_list_remove(&tablet->seat_link);
wl_list_remove(&tablet->tablet_link); wl_list_remove(&tablet->tablet_link);
free(tablet);
//wl_list_remove(tablet->device_destroy.link);
//wl_list_remove(tablet->client_destroy.link);
} }
static void handle_tablet_v2_destroy(struct wl_client *client, static void handle_tablet_v2_destroy(struct wl_client *client,
@ -124,6 +113,52 @@ static struct zwp_tablet_v2_interface tablet_impl = {
.destroy = handle_tablet_v2_destroy, .destroy = handle_tablet_v2_destroy,
}; };
static void destroy_tablet_seat_client(struct wlr_tablet_seat_client_v2 *client) {
/* This is only called when the seat or client gets destroyed.
* The client is liable to make a request on a deleted resource either
* way, so we don't do the removed->destroy process, but just remove
* all structs immediatly.
*/
struct wlr_tablet_client_v2 *tablet;
struct wlr_tablet_client_v2 *tmp_tablet;
wl_list_for_each_safe(tablet, tmp_tablet, &client->tablets, seat_link) {
wl_resource_destroy(tablet->resource);
}
struct wlr_tablet_pad_client_v2 *pad;
struct wlr_tablet_pad_client_v2 *tmp_pad;
wl_list_for_each_safe(pad, tmp_pad, &client->pads, seat_link) {
wl_resource_destroy(pad->resource);
}
struct wlr_tablet_tool_client_v2 *tool;
struct wlr_tablet_tool_client_v2 *tmp_tool;
wl_list_for_each_safe(tool, tmp_tool, &client->tools, seat_link) {
wl_resource_destroy(tool->resource);
}
wl_resource_destroy(client->resource);
}
static void handle_wlr_seat_destroy(struct wl_listener *listener, void *data) {
struct wlr_tablet_seat_v2 *seat =
wl_container_of(listener, seat, seat_destroy);
wl_list_remove(&seat->link);
wl_list_remove(&seat->seat_destroy.link);
struct wlr_tablet_seat_client_v2 *client;
struct wlr_tablet_seat_client_v2 *tmp;
/* wl_seat doesn't have a removed event/destroy request, so we can just
* destroy all attached tablet_seat_clients -> tablet_v2 resources.
* The client can call requests on gone resources either way
*/
wl_list_for_each_safe(client, tmp, &seat->clients, seat_link) {
destroy_tablet_seat_client(client);
}
}
static struct wlr_tablet_seat_v2 *make_tablet_seat( static struct wlr_tablet_seat_v2 *make_tablet_seat(
struct wlr_tablet_manager_v2 *manager, struct wlr_tablet_manager_v2 *manager,
struct wlr_seat *wlr_seat) { struct wlr_seat *wlr_seat) {
@ -142,6 +177,9 @@ static struct wlr_tablet_seat_v2 *make_tablet_seat(
wl_list_init(&tablet_seat->tools); wl_list_init(&tablet_seat->tools);
wl_list_init(&tablet_seat->pads); wl_list_init(&tablet_seat->pads);
tablet_seat->seat_destroy.notify = handle_wlr_seat_destroy;
wl_signal_add(&wlr_seat->events.destroy, &tablet_seat->seat_destroy);
wl_list_insert(&manager->seats, &tablet_seat->link); wl_list_insert(&manager->seats, &tablet_seat->link);
return tablet_seat; return tablet_seat;
} }
@ -242,6 +280,15 @@ static enum zwp_tablet_tool_v2_type tablet_type_from_wlr_type(
assert(false && "Unreachable"); assert(false && "Unreachable");
} }
static void destroy_tablet_tool(struct wl_resource *resource) {
struct wlr_tablet_tool_client_v2 *client =
wl_resource_get_user_data(resource);
wl_list_remove(&client->seat_link);
wl_list_remove(&client->tool_link);
free(client);
}
static void add_tablet_tool_client(struct wlr_tablet_seat_client_v2 *seat, static void add_tablet_tool_client(struct wlr_tablet_seat_client_v2 *seat,
struct wlr_tablet_v2_tablet_tool *tool) { struct wlr_tablet_v2_tablet_tool *tool) {
struct wlr_tablet_tool_client_v2 *client = struct wlr_tablet_tool_client_v2 *client =
@ -257,7 +304,7 @@ static void add_tablet_tool_client(struct wlr_tablet_seat_client_v2 *seat,
return; return;
} }
wl_resource_set_implementation(client->resource, &tablet_tool_impl, wl_resource_set_implementation(client->resource, &tablet_tool_impl,
client, NULL); client, destroy_tablet_tool);
zwp_tablet_seat_v2_send_tool_added(seat->resource, client->resource); zwp_tablet_seat_v2_send_tool_added(seat->resource, client->resource);
// Send the expected events // Send the expected events
@ -412,8 +459,33 @@ static void destroy_tablet_pad_v2(struct wl_resource *resource) {
wl_list_remove(&pad->seat_link); wl_list_remove(&pad->seat_link);
wl_list_remove(&pad->pad_link); wl_list_remove(&pad->pad_link);
//wl_list_remove(tablet->device_destroy.link); /* This isn't optimal, if the client destroys the resources in another
//wl_list_remove(tablet->client_destroy.link); * order, it will be disconnected.
* But this makes things *way* easier for us, and (untested) I doubt
* clients will destroy it in another order.
*/
for (size_t i = 0; i < pad->group_count; ++i) {
if (pad->groups[i]) {
wl_resource_destroy(pad->groups[i]);
}
}
free(pad->groups);
for (size_t i = 0; i < pad->ring_count; ++i) {
if (pad->rings[i]) {
wl_resource_destroy(pad->rings[i]);
}
}
free(pad->rings);
for (size_t i = 0; i < pad->strip_count; ++i) {
if (pad->strips[i]) {
wl_resource_destroy(pad->strips[i]);
}
}
free(pad->strips);
free(pad);
} }
static void handle_tablet_pad_v2_destroy(struct wl_client *client, static void handle_tablet_pad_v2_destroy(struct wl_client *client,
@ -508,6 +580,7 @@ static void add_tablet_pad_group(struct wlr_tablet_v2_tablet_pad *pad,
wl_array_add(&button_array, group->button_count * sizeof(int)); wl_array_add(&button_array, group->button_count * sizeof(int));
memcpy(button_array.data, group->buttons, 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); zwp_tablet_pad_group_v2_send_buttons(client->groups[index], &button_array);
wl_array_release(&button_array);
client->strip_count = group->strip_count; client->strip_count = group->strip_count;
for (size_t i = 0; i < group->strip_count; ++i) { for (size_t i = 0; i < group->strip_count; ++i) {
@ -647,12 +720,6 @@ struct wlr_tablet_v2_tablet_pad *wlr_make_tablet_pad(
add_tablet_pad_client(pos, pad); 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; return pad;
} }
@ -678,23 +745,21 @@ static struct wlr_tablet_seat_client_v2 *tablet_seat_from_resource (
static void wlr_tablet_seat_client_v2_destroy(struct wl_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); struct wlr_tablet_seat_client_v2 *seat = tablet_seat_from_resource(resource);
seat->resource = NULL; /* XXX: Evaluate whether we should have a way to access structs */
/* We can't just destroy the struct, because we may need to iterate it wl_list_remove(&seat->tools);
* on display->destroy/manager_destroy wl_list_remove(&seat->tablets);
*/ wl_list_remove(&seat->pads);
// TODO: Implement the free() check
wl_list_remove(&seat->seat_link);
wl_list_remove(&seat->client_link);
free(seat);
} }
static void handle_seat_destroy(struct wl_listener *listener, void *data) { static void handle_seat_client_destroy(struct wl_listener *listener, void *data) {
struct wlr_tablet_seat_client_v2 *seat = struct wlr_tablet_seat_client_v2 *seat =
wl_container_of(listener, seat, seat_client_destroy); wl_container_of(listener, seat, seat_client_destroy);
destroy_tablet_seat_client(seat);
seat->seat = NULL;
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_client_destroy.link);
} }
static void tablet_manager_destroy(struct wl_client *client, static void tablet_manager_destroy(struct wl_client *client,
@ -740,7 +805,7 @@ static void get_tablet_seat(struct wl_client *wl_client, struct wl_resource *res
wl_list_init(&seat_client->tablets); wl_list_init(&seat_client->tablets);
wl_list_init(&seat_client->pads); wl_list_init(&seat_client->pads);
seat_client->seat_client_destroy.notify = handle_seat_destroy; seat_client->seat_client_destroy.notify = handle_seat_client_destroy;
wl_signal_add(&seat->events.destroy, &seat_client->seat_client_destroy); wl_signal_add(&seat->events.destroy, &seat_client->seat_client_destroy);
wl_list_insert(&manager->tablet_seats, &seat_client->client_link); wl_list_insert(&manager->tablet_seats, &seat_client->client_link);
@ -778,11 +843,12 @@ static struct wlr_tablet_manager_client_v2 *tablet_manager_client_from_resource
static void wlr_tablet_manager_v2_destroy(struct wl_resource *resource) { static void wlr_tablet_manager_v2_destroy(struct wl_resource *resource) {
struct wlr_tablet_manager_client_v2 *client = tablet_manager_client_from_resource(resource); struct wlr_tablet_manager_client_v2 *client = tablet_manager_client_from_resource(resource);
client->resource = NULL; // TODO: Evaluate whether we may need to iterate structs
/* We can't just destroy the struct, because we may need to iterate it wl_list_remove(&client->link);
* on display->destroy/manager_destroy wl_list_remove(&client->tablet_seats);
*/ //wl_list_remove(&client->client_destroy.link);
// TODO: Implement the free() check
free(client);
} }
static void tablet_v2_bind(struct wl_client *wl_client, void *data, static void tablet_v2_bind(struct wl_client *wl_client, void *data,