compositor: redesign how resources are managed
All public resource creators now take a new ID for the resource and an optional list where the resource link is added. When the resource is destroyed it is its own responsibility to remove itself from the list. This removes the need for the caller to add a destroy listener. This commit fixes a few segfaults with resources not removed from the list when destroyed.
This commit is contained in:
parent
979b1b22d5
commit
43012f3740
|
@ -6,9 +6,11 @@
|
||||||
struct wl_resource;
|
struct wl_resource;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implements the given resource as region.
|
* Creates a new region resource with the provided new ID. If `resource_list` is
|
||||||
|
* non-NULL, adds the region's resource to the list.
|
||||||
*/
|
*/
|
||||||
struct wl_resource *wlr_region_create(struct wl_client *client, uint32_t id);
|
struct wl_resource *wlr_region_create(struct wl_client *client,
|
||||||
|
uint32_t version, uint32_t id, struct wl_list *resource_list);
|
||||||
|
|
||||||
pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource);
|
pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource);
|
||||||
|
|
||||||
|
|
|
@ -80,10 +80,6 @@ struct wlr_surface {
|
||||||
struct wl_signal destroy;
|
struct wl_signal destroy;
|
||||||
} events;
|
} events;
|
||||||
|
|
||||||
// destroy listener used by compositor
|
|
||||||
struct wl_listener compositor_listener;
|
|
||||||
void *compositor_data;
|
|
||||||
|
|
||||||
// surface commit callback for the role that runs before all others
|
// surface commit callback for the role that runs before all others
|
||||||
void (*role_committed)(struct wlr_surface *surface, void *role_data);
|
void (*role_committed)(struct wlr_surface *surface, void *role_data);
|
||||||
void *role_data;
|
void *role_data;
|
||||||
|
@ -102,8 +98,14 @@ typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface,
|
||||||
int sx, int sy, void *data);
|
int sx, int sy, void *data);
|
||||||
|
|
||||||
struct wlr_renderer;
|
struct wlr_renderer;
|
||||||
struct wlr_surface *wlr_surface_create(struct wl_resource *res,
|
|
||||||
struct wlr_renderer *renderer);
|
/**
|
||||||
|
* Create a new surface resource with the provided new ID. If `resource_list`
|
||||||
|
* is non-NULL, adds the surface's resource to the list.
|
||||||
|
*/
|
||||||
|
struct wlr_surface *wlr_surface_create(struct wl_client *client,
|
||||||
|
uint32_t version, uint32_t id, struct wlr_renderer *renderer,
|
||||||
|
struct wl_list *resource_list);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the lifetime role for this surface. Returns 0 on success or -1 if the
|
* Set the lifetime role for this surface. Returns 0 on success or -1 if the
|
||||||
|
@ -121,10 +123,12 @@ int wlr_surface_set_role(struct wlr_surface *surface, const char *role,
|
||||||
bool wlr_surface_has_buffer(struct wlr_surface *surface);
|
bool wlr_surface_has_buffer(struct wlr_surface *surface);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the subsurface implementation for this surface.
|
* Create a new subsurface resource with the provided new ID. If `resource_list`
|
||||||
|
* is non-NULL, adds the subsurface's resource to the list.
|
||||||
*/
|
*/
|
||||||
struct wlr_subsurface *wlr_surface_make_subsurface(struct wlr_surface *surface,
|
struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface,
|
||||||
struct wlr_surface *parent, uint32_t id);
|
struct wlr_surface *parent, uint32_t version, uint32_t id,
|
||||||
|
struct wl_list *resource_list);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the root of the subsurface tree for this surface.
|
* Get the root of the subsurface tree for this surface.
|
||||||
|
|
|
@ -75,14 +75,8 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_subsurface *subsurface =
|
wlr_subsurface_create(surface, parent, wl_resource_get_version(resource),
|
||||||
wlr_surface_make_subsurface(surface, parent, id);
|
id, &subcompositor->subsurface_resources);
|
||||||
if (subsurface == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_list_insert(&subcompositor->subsurface_resources,
|
|
||||||
wl_resource_get_link(subsurface->resource));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_subcompositor_interface subcompositor_impl = {
|
static const struct wl_subcompositor_interface subcompositor_impl = {
|
||||||
|
@ -142,36 +136,17 @@ static struct wlr_compositor *compositor_from_resource(
|
||||||
return wl_resource_get_user_data(resource);
|
return wl_resource_get_user_data(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compositor_handle_surface_destroy(struct wl_listener *listener,
|
|
||||||
void *data) {
|
|
||||||
wl_list_remove(wl_resource_get_link(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wl_compositor_create_surface(struct wl_client *client,
|
static void wl_compositor_create_surface(struct wl_client *client,
|
||||||
struct wl_resource *resource, uint32_t id) {
|
struct wl_resource *resource, uint32_t id) {
|
||||||
struct wlr_compositor *compositor = compositor_from_resource(resource);
|
struct wlr_compositor *compositor = compositor_from_resource(resource);
|
||||||
|
|
||||||
struct wl_resource *surface_resource = wl_resource_create(client,
|
struct wlr_surface *surface = wlr_surface_create(client,
|
||||||
&wl_surface_interface, wl_resource_get_version(resource), id);
|
wl_resource_get_version(resource), id, compositor->renderer,
|
||||||
if (surface_resource == NULL) {
|
&compositor->surface_resources);
|
||||||
wl_resource_post_no_memory(resource);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct wlr_surface *surface = wlr_surface_create(surface_resource,
|
|
||||||
compositor->renderer);
|
|
||||||
if (surface == NULL) {
|
if (surface == NULL) {
|
||||||
wl_resource_destroy(surface_resource);
|
|
||||||
wl_resource_post_no_memory(resource);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
surface->compositor_data = compositor;
|
|
||||||
surface->compositor_listener.notify = compositor_handle_surface_destroy;
|
|
||||||
wl_resource_add_destroy_listener(surface_resource,
|
|
||||||
&surface->compositor_listener);
|
|
||||||
|
|
||||||
wl_list_insert(&compositor->surface_resources,
|
|
||||||
wl_resource_get_link(surface_resource));
|
|
||||||
wlr_signal_emit_safe(&compositor->events.new_surface, surface);
|
wlr_signal_emit_safe(&compositor->events.new_surface, surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,14 +154,7 @@ static void wl_compositor_create_region(struct wl_client *client,
|
||||||
struct wl_resource *resource, uint32_t id) {
|
struct wl_resource *resource, uint32_t id) {
|
||||||
struct wlr_compositor *compositor = compositor_from_resource(resource);
|
struct wlr_compositor *compositor = compositor_from_resource(resource);
|
||||||
|
|
||||||
struct wl_resource *region_resource = wlr_region_create(client, id);
|
wlr_region_create(client, 1, id, &compositor->region_resources);
|
||||||
if (region_resource == NULL) {
|
|
||||||
wl_resource_post_no_memory(resource);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_list_insert(&compositor->region_resources,
|
|
||||||
wl_resource_get_link(region_resource));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_compositor_interface compositor_impl = {
|
static const struct wl_compositor_interface compositor_impl = {
|
||||||
|
|
|
@ -34,29 +34,40 @@ static const struct wl_region_interface region_impl = {
|
||||||
|
|
||||||
static void region_handle_resource_destroy(struct wl_resource *resource) {
|
static void region_handle_resource_destroy(struct wl_resource *resource) {
|
||||||
pixman_region32_t *reg = wlr_region_from_resource(resource);
|
pixman_region32_t *reg = wlr_region_from_resource(resource);
|
||||||
|
|
||||||
|
wl_list_remove(wl_resource_get_link(resource));
|
||||||
|
|
||||||
pixman_region32_fini(reg);
|
pixman_region32_fini(reg);
|
||||||
free(reg);
|
free(reg);
|
||||||
|
|
||||||
// Set by wlr_compositor
|
|
||||||
wl_list_remove(wl_resource_get_link(resource));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wl_resource *wlr_region_create(struct wl_client *client, uint32_t id) {
|
struct wl_resource *wlr_region_create(struct wl_client *client,
|
||||||
|
uint32_t version, uint32_t id, struct wl_list *resource_list) {
|
||||||
pixman_region32_t *region = calloc(1, sizeof(pixman_region32_t));
|
pixman_region32_t *region = calloc(1, sizeof(pixman_region32_t));
|
||||||
if (region == NULL) {
|
if (region == NULL) {
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_init(region);
|
pixman_region32_init(region);
|
||||||
|
|
||||||
struct wl_resource *region_resource = wl_resource_create(client,
|
struct wl_resource *region_resource = wl_resource_create(client,
|
||||||
&wl_region_interface, 1, id);
|
&wl_region_interface, version, id);
|
||||||
if (region_resource == NULL) {
|
if (region_resource == NULL) {
|
||||||
free(region);
|
free(region);
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
wl_resource_set_implementation(region_resource, ®ion_impl, region,
|
wl_resource_set_implementation(region_resource, ®ion_impl, region,
|
||||||
region_handle_resource_destroy);
|
region_handle_resource_destroy);
|
||||||
|
|
||||||
|
struct wl_list *resource_link = wl_resource_get_link(region_resource);
|
||||||
|
if (resource_list != NULL) {
|
||||||
|
wl_list_insert(resource_list, resource_link);
|
||||||
|
} else {
|
||||||
|
wl_list_init(resource_link);
|
||||||
|
}
|
||||||
|
|
||||||
return region_resource;
|
return region_resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -615,6 +615,8 @@ static void subsurface_destroy(struct wlr_subsurface *subsurface) {
|
||||||
wl_list_remove(&subsurface->parent_destroy.link);
|
wl_list_remove(&subsurface->parent_destroy.link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wl_list_remove(wl_resource_get_link(subsurface->resource));
|
||||||
|
|
||||||
wl_resource_set_user_data(subsurface->resource, NULL);
|
wl_resource_set_user_data(subsurface->resource, NULL);
|
||||||
if (subsurface->surface) {
|
if (subsurface->surface) {
|
||||||
subsurface->surface->role_data = NULL;
|
subsurface->surface->role_data = NULL;
|
||||||
|
@ -627,6 +629,9 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) {
|
||||||
|
|
||||||
wlr_signal_emit_safe(&surface->events.destroy, surface);
|
wlr_signal_emit_safe(&surface->events.destroy, surface);
|
||||||
|
|
||||||
|
wl_list_remove(wl_resource_get_link(surface->resource));
|
||||||
|
|
||||||
|
wl_list_remove(&surface->renderer_destroy.link);
|
||||||
wlr_texture_destroy(surface->texture);
|
wlr_texture_destroy(surface->texture);
|
||||||
surface_state_destroy(surface->pending);
|
surface_state_destroy(surface->pending);
|
||||||
surface_state_destroy(surface->current);
|
surface_state_destroy(surface->current);
|
||||||
|
@ -641,16 +646,27 @@ static void surface_handle_renderer_destroy(struct wl_listener *listener,
|
||||||
wl_resource_destroy(surface->resource);
|
wl_resource_destroy(surface->resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_surface *wlr_surface_create(struct wl_resource *res,
|
struct wlr_surface *wlr_surface_create(struct wl_client *client,
|
||||||
struct wlr_renderer *renderer) {
|
uint32_t version, uint32_t id, struct wlr_renderer *renderer,
|
||||||
|
struct wl_list *resource_list) {
|
||||||
struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface));
|
struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface));
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
wl_resource_post_no_memory(res);
|
wl_client_post_no_memory(client);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
wlr_log(L_DEBUG, "New wlr_surface %p (res %p)", surface, res);
|
surface->resource = wl_resource_create(client, &wl_surface_interface,
|
||||||
|
version, id);
|
||||||
|
if (surface->resource == NULL) {
|
||||||
|
free(surface);
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
wl_resource_set_implementation(surface->resource, &surface_interface,
|
||||||
|
surface, surface_handle_resource_destroy);
|
||||||
|
|
||||||
|
wlr_log(L_DEBUG, "New wlr_surface %p (res %p)", surface, surface->resource);
|
||||||
|
|
||||||
surface->renderer = renderer;
|
surface->renderer = renderer;
|
||||||
surface->resource = res;
|
|
||||||
|
|
||||||
surface->current = surface_state_create();
|
surface->current = surface_state_create();
|
||||||
surface->pending = surface_state_create();
|
surface->pending = surface_state_create();
|
||||||
|
@ -660,12 +676,17 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res,
|
||||||
wl_signal_init(&surface->events.new_subsurface);
|
wl_signal_init(&surface->events.new_subsurface);
|
||||||
wl_list_init(&surface->subsurfaces);
|
wl_list_init(&surface->subsurfaces);
|
||||||
wl_list_init(&surface->subsurface_pending_list);
|
wl_list_init(&surface->subsurface_pending_list);
|
||||||
wl_resource_set_implementation(res, &surface_interface,
|
|
||||||
surface, surface_handle_resource_destroy);
|
|
||||||
|
|
||||||
wl_signal_add(&renderer->events.destroy, &surface->renderer_destroy);
|
wl_signal_add(&renderer->events.destroy, &surface->renderer_destroy);
|
||||||
surface->renderer_destroy.notify = surface_handle_renderer_destroy;
|
surface->renderer_destroy.notify = surface_handle_renderer_destroy;
|
||||||
|
|
||||||
|
struct wl_list *resource_link = wl_resource_get_link(surface->resource);
|
||||||
|
if (resource_list != NULL) {
|
||||||
|
wl_list_insert(resource_list, resource_link);
|
||||||
|
} else {
|
||||||
|
wl_list_init(resource_link);
|
||||||
|
}
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,8 +859,9 @@ static void subsurface_handle_surface_destroy(struct wl_listener *listener,
|
||||||
subsurface_destroy(subsurface);
|
subsurface_destroy(subsurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_subsurface *wlr_surface_make_subsurface(struct wlr_surface *surface,
|
struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface,
|
||||||
struct wlr_surface *parent, uint32_t id) {
|
struct wlr_surface *parent, uint32_t version, uint32_t id,
|
||||||
|
struct wl_list *resource_list) {
|
||||||
struct wl_client *client = wl_resource_get_client(surface->resource);
|
struct wl_client *client = wl_resource_get_client(surface->resource);
|
||||||
|
|
||||||
struct wlr_subsurface *subsurface =
|
struct wlr_subsurface *subsurface =
|
||||||
|
@ -856,7 +878,20 @@ struct wlr_subsurface *wlr_surface_make_subsurface(struct wlr_surface *surface,
|
||||||
}
|
}
|
||||||
subsurface->synchronized = true;
|
subsurface->synchronized = true;
|
||||||
subsurface->surface = surface;
|
subsurface->surface = surface;
|
||||||
|
subsurface->resource =
|
||||||
|
wl_resource_create(client, &wl_subsurface_interface, version, id);
|
||||||
|
if (subsurface->resource == NULL) {
|
||||||
|
surface_state_destroy(subsurface->cached);
|
||||||
|
free(subsurface);
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
wl_resource_set_implementation(subsurface->resource,
|
||||||
|
&subsurface_implementation, subsurface,
|
||||||
|
subsurface_resource_destroy);
|
||||||
|
|
||||||
wl_signal_init(&subsurface->events.destroy);
|
wl_signal_init(&subsurface->events.destroy);
|
||||||
|
|
||||||
wl_signal_add(&surface->events.destroy, &subsurface->surface_destroy);
|
wl_signal_add(&surface->events.destroy, &subsurface->surface_destroy);
|
||||||
subsurface->surface_destroy.notify = subsurface_handle_surface_destroy;
|
subsurface->surface_destroy.notify = subsurface_handle_surface_destroy;
|
||||||
|
|
||||||
|
@ -868,21 +903,15 @@ struct wlr_subsurface *wlr_surface_make_subsurface(struct wlr_surface *surface,
|
||||||
wl_list_insert(&parent->subsurface_pending_list,
|
wl_list_insert(&parent->subsurface_pending_list,
|
||||||
&subsurface->parent_pending_link);
|
&subsurface->parent_pending_link);
|
||||||
|
|
||||||
subsurface->resource =
|
|
||||||
wl_resource_create(client, &wl_subsurface_interface, 1, id);
|
|
||||||
if (subsurface->resource == NULL) {
|
|
||||||
surface_state_destroy(subsurface->cached);
|
|
||||||
free(subsurface);
|
|
||||||
wl_client_post_no_memory(client);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_resource_set_implementation(subsurface->resource,
|
|
||||||
&subsurface_implementation, subsurface,
|
|
||||||
subsurface_resource_destroy);
|
|
||||||
|
|
||||||
surface->role_data = subsurface;
|
surface->role_data = subsurface;
|
||||||
|
|
||||||
|
struct wl_list *resource_link = wl_resource_get_link(subsurface->resource);
|
||||||
|
if (resource_list != NULL) {
|
||||||
|
wl_list_insert(resource_list, resource_link);
|
||||||
|
} else {
|
||||||
|
wl_list_init(resource_link);
|
||||||
|
}
|
||||||
|
|
||||||
wlr_signal_emit_safe(&parent->events.new_subsurface, subsurface);
|
wlr_signal_emit_safe(&parent->events.new_subsurface, subsurface);
|
||||||
|
|
||||||
return subsurface;
|
return subsurface;
|
||||||
|
|
Loading…
Reference in New Issue