From e76d4581ce0d52ac3c32c43336af48d4d5760f8d Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Fri, 15 Feb 2019 23:39:20 +1300 Subject: [PATCH] types/wlr_compositor: Change to new design - wlr_surface and wlr_region are bundled into the same file - Allows extensions to add state to wl_surface commits Old surface code has not been removed yet. --- include/wlr/types/meson.build | 1 - include/wlr/types/wlr_compositor.h | 89 +++- include/wlr/types/wlr_region.h | 24 -- include/wlr/types/wlr_surface.h | 6 +- include/xwayland/xwm.h | 1 - rootston/cursor.c | 2 +- types/meson.build | 1 - types/wlr_compositor.c | 638 ++++++++++++++++++++++++----- types/wlr_pointer_constraints_v1.c | 2 +- types/wlr_region.c | 78 ---- types/wlr_surface.c | 24 +- xwayland/xwm.c | 14 - 12 files changed, 619 insertions(+), 261 deletions(-) delete mode 100644 include/wlr/types/wlr_region.h delete mode 100644 types/wlr_region.c diff --git a/include/wlr/types/meson.build b/include/wlr/types/meson.build index c7e7bdbfc..cf672c808 100644 --- a/include/wlr/types/meson.build +++ b/include/wlr/types/meson.build @@ -31,7 +31,6 @@ install_headers( 'wlr_presentation_time.h', 'wlr_primary_selection_v1.h', 'wlr_primary_selection.h', - 'wlr_region.h', 'wlr_relative_pointer_v1.h', 'wlr_screencopy_v1.h', 'wlr_screenshooter.h', diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index 36b9e83f6..0cff2ba04 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -12,34 +12,105 @@ #include #include +struct wlr_commit; +struct wlr_output; struct wlr_surface; struct wlr_subcompositor { struct wl_global *global; - struct wl_list resources; - struct wl_list subsurface_resources; }; struct wlr_compositor { struct wl_global *global; - struct wl_list resources; struct wlr_renderer *renderer; - struct wl_list surface_resources; - struct wl_list region_resources; + + uint32_t ids; struct wlr_subcompositor subcompositor; - struct wl_listener display_destroy; - struct { struct wl_signal new_surface; + struct wl_signal new_surface_2; + struct wl_signal new_state; + } events; + + struct wl_listener display_destroy; +}; + +struct wlr_surface_2 { + struct wl_resource *resource; + struct wlr_compositor *compositor; + + struct { + struct wl_signal commit; + struct wl_signal destroy; + } events; + + struct wlr_commit *pending; + struct wl_list committed; + + struct wl_list frame_callbacks; +}; + +struct wlr_commit { + struct wl_list link; + struct wlr_surface_2 *surface; + + // If the user has called wl_surface.commit + bool committed; + // See wlr_commit_inhibit + size_t inhibit; + size_t ref_cnt; + + // wl_surface.attach + struct wl_resource *buffer_resource; + int32_t sx, sy; + // wl_surface.damage + pixman_region32_t surface_damage; + // wl_surface.frame + struct wl_list frame_callbacks; + // wl_surface.set_opaque_region + pixman_region32_t opaque_region; + // wl_surface.set_input_region + pixman_region32_t input_region; + // wl_surface.set_buffer_transform + enum wl_output_transform transform; + // wl_surface.set_buffer_scale + int32_t scale; + // wl_surface.damage_buffer + pixman_region32_t buffer_damage; + + size_t state_len; + void **state; + + struct { + struct wl_signal commit; + struct wl_signal complete; struct wl_signal destroy; } events; }; -void wlr_compositor_destroy(struct wlr_compositor *wlr_compositor); +struct wlr_compositor_new_state_args { + struct wlr_commit *old; + struct wlr_commit *new; +}; + struct wlr_compositor *wlr_compositor_create(struct wl_display *display, struct wlr_renderer *renderer); +uint32_t wlr_compositor_register(struct wlr_compositor *compositor); + +struct wlr_surface_2 *wlr_surface_from_resource_2(struct wl_resource *resource); + +struct wlr_commit *wlr_surface_get_commit(struct wlr_surface_2 *surface); +struct wlr_commit *wlr_surface_get_pending(struct wlr_surface_2 *surface); + +void wlr_surface_send_enter_2(struct wlr_surface_2 *surf, struct wlr_output *output); +void wlr_surface_send_leave_2(struct wlr_surface_2 *surf, struct wlr_output *output); + +void wlr_commit_unref(struct wlr_commit *commit); + +void wlr_commit_inhibit(struct wlr_commit *commit); +void wlr_commit_uninhibit(struct wlr_commit *commit); bool wlr_surface_is_subsurface(struct wlr_surface *surface); @@ -50,4 +121,6 @@ bool wlr_surface_is_subsurface(struct wlr_surface *surface); struct wlr_subsurface *wlr_subsurface_from_wlr_surface( struct wlr_surface *surface); +pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource); + #endif diff --git a/include/wlr/types/wlr_region.h b/include/wlr/types/wlr_region.h deleted file mode 100644 index ec7f73aa7..000000000 --- a/include/wlr/types/wlr_region.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This an unstable interface of wlroots. No guarantees are made regarding the - * future consistency of this API. - */ -#ifndef WLR_USE_UNSTABLE -#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" -#endif - -#ifndef WLR_TYPES_WLR_REGION_H -#define WLR_TYPES_WLR_REGION_H - -#include -#include - -/* - * 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 version, uint32_t id, struct wl_list *resource_list); - -pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource); - -#endif diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 0c3899877..21c52fdc4 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -157,8 +157,7 @@ struct wlr_renderer; * 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); + uint32_t version, uint32_t id, struct wlr_renderer *renderer); /** * Set the lifetime role for this surface. Returns 0 on success or -1 if the @@ -188,8 +187,7 @@ struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface); * is non-NULL, adds the subsurface's resource to the list. */ struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface, - struct wlr_surface *parent, uint32_t version, uint32_t id, - struct wl_list *resource_list); + struct wlr_surface *parent, uint32_t version, uint32_t id); /** * Get the root of the subsurface tree for this surface. diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 00f2f3d59..7313f4f7a 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -128,7 +128,6 @@ struct wlr_xwm { #endif struct wl_listener compositor_new_surface; - struct wl_listener compositor_destroy; struct wl_listener seat_set_selection; struct wl_listener seat_set_primary_selection; struct wl_listener seat_start_drag; diff --git a/rootston/cursor.c b/rootston/cursor.c index 6e09c06e0..c3623c305 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/types/meson.build b/types/meson.build index 72d3f84a0..a78fdf19d 100644 --- a/types/meson.build +++ b/types/meson.build @@ -54,7 +54,6 @@ lib_wlr_types = static_library( 'wlr_presentation_time.c', 'wlr_primary_selection_v1.c', 'wlr_primary_selection.c', - 'wlr_region.c', 'wlr_relative_pointer_v1.c', 'wlr_screencopy_v1.c', 'wlr_screenshooter.c', diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 7702a7788..0c121f8e8 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -1,8 +1,9 @@ #include #include +#include +#include #include #include -#include #include #include #include "util/signal.h" @@ -22,15 +23,6 @@ struct wlr_subsurface *wlr_subsurface_from_wlr_surface( return (struct wlr_subsurface *)surface->role_data; } -static const struct wl_subcompositor_interface subcompositor_impl; - -static struct wlr_subcompositor *subcompositor_from_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &wl_subcompositor_interface, - &subcompositor_impl)); - return wl_resource_get_user_data(resource); -} - static void subcompositor_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -40,8 +32,6 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource, struct wl_resource *parent_resource) { - struct wlr_subcompositor *subcompositor = - subcompositor_from_resource(resource); struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); struct wlr_surface *parent = wlr_surface_from_resource(parent_resource); @@ -77,8 +67,8 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client, return; } - wlr_subsurface_create(surface, parent, wl_resource_get_version(resource), - id, &subcompositor->subsurface_resources); + wlr_subsurface_create(surface, parent, + wl_resource_get_version(resource), id); } static const struct wl_subcompositor_interface subcompositor_impl = { @@ -86,54 +76,405 @@ static const struct wl_subcompositor_interface subcompositor_impl = { .get_subsurface = subcompositor_handle_get_subsurface, }; -static void subcompositor_resource_destroy(struct wl_resource *resource) { - wl_list_remove(wl_resource_get_link(resource)); -} - static void subcompositor_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { - struct wlr_subcompositor *subcompositor = data; struct wl_resource *resource = wl_resource_create(client, &wl_subcompositor_interface, 1, id); if (resource == NULL) { wl_client_post_no_memory(client); return; } - wl_resource_set_implementation(resource, &subcompositor_impl, - subcompositor, subcompositor_resource_destroy); - wl_list_insert(&subcompositor->resources, wl_resource_get_link(resource)); + wl_resource_set_implementation(resource, &subcompositor_impl, NULL, NULL); } -static void subcompositor_init(struct wlr_subcompositor *subcompositor, +static void subcompositor_init(struct wlr_subcompositor *sc, struct wl_display *display) { - subcompositor->global = wl_global_create(display, - &wl_subcompositor_interface, SUBCOMPOSITOR_VERSION, subcompositor, - subcompositor_bind); - if (subcompositor->global == NULL) { - wlr_log_errno(WLR_ERROR, "Could not allocate subcompositor global"); + sc->global = wl_global_create(display, &wl_subcompositor_interface, + SUBCOMPOSITOR_VERSION, NULL, subcompositor_bind); + if (sc->global == NULL) { + wlr_log_errno(WLR_ERROR, "Failed to create subcompositor global"); return; } - wl_list_init(&subcompositor->resources); - wl_list_init(&subcompositor->subsurface_resources); } -static void subcompositor_finish(struct wlr_subcompositor *subcompositor) { - wl_global_destroy(subcompositor->global); - struct wl_resource *resource, *tmp; - wl_resource_for_each_safe(resource, tmp, - &subcompositor->subsurface_resources) { - wl_resource_destroy(resource); +static void subcompositor_finish(struct wlr_subcompositor *sc) { + wl_global_destroy(sc->global); +} + +static const struct wl_region_interface region_impl; + +pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_region_interface, + ®ion_impl)); + return wl_resource_get_user_data(resource); +} + +static void region_destroy(struct wl_client *client, struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void region_add(struct wl_client *client, struct wl_resource *resource, + int32_t x, int32_t y, int32_t width, int32_t height) { + pixman_region32_t *region = wlr_region_from_resource(resource); + pixman_region32_union_rect(region, region, x, y, width, height); +} + +static void region_subtract(struct wl_client *client, struct wl_resource *resource, + int32_t x, int32_t y, int32_t width, int32_t height) { + pixman_region32_t *region = wlr_region_from_resource(resource); + pixman_region32_union_rect(region, region, x, y, width, height); + + pixman_region32_t rect; + pixman_region32_init_rect(&rect, x, y, width, height); + pixman_region32_subtract(region, region, &rect); + pixman_region32_fini(&rect); +} + +static const struct wl_region_interface region_impl = { + .destroy = region_destroy, + .add = region_add, + .subtract = region_subtract, +}; + +static void region_resource_destroy(struct wl_resource *resource) { + pixman_region32_t *region = wlr_region_from_resource(resource); + + pixman_region32_fini(region); + free(region); +} + +static struct wlr_commit *commit_create(struct wlr_surface_2 *surf) { + struct wlr_compositor *comp = surf->compositor; + + struct wlr_commit *c = calloc(1, sizeof(*c)); + if (!c) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return NULL; } - wl_resource_for_each_safe(resource, tmp, &subcompositor->resources) { - wl_resource_destroy(resource); + + // Prevent a zero allocation + size_t len = comp->ids ? comp->ids : 1; + + c->state = calloc(len, sizeof(*c->state)); + if (!c->state) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + free(c); + return NULL; + } + c->state_len = len; + + c->surface = surf; + + pixman_region32_init(&c->surface_damage); + wl_list_init(&c->frame_callbacks); + pixman_region32_init(&c->opaque_region); + pixman_region32_init_rect(&c->input_region, + INT_MIN, INT_MIN, UINT_MAX, UINT_MAX); + c->scale = 1; + pixman_region32_init(&c->buffer_damage); + + return c; +} + +static void commit_destroy(struct wlr_commit *c) { + pixman_region32_fini(&c->surface_damage); + pixman_region32_fini(&c->opaque_region); + pixman_region32_fini(&c->input_region); + pixman_region32_fini(&c->buffer_damage); + + wlr_signal_emit_safe(&c->events.destroy, c); + + free(c->state); + free(c); +} + +static bool commit_is_complete(struct wlr_commit *c) { + return c->committed && c->inhibit == 0; +} + +static bool commit_is_latest(struct wlr_commit *c) { + assert(c->committed); + + struct wlr_surface_2 *surf = c->surface; + struct wlr_commit *iter; + wl_list_for_each(iter, &surf->committed, link) { + if (iter == c) { + return true; + } + + if (commit_is_complete(iter)) { + return false; + } + } + + // You shouldn't be able to get here. + assert(0); + return false; +} + +static void surface_prune_commits(struct wlr_surface_2 *surf) { + bool complete = false; + struct wlr_commit *iter, *tmp; + wl_list_for_each_safe(iter, tmp, &surf->committed, link) { + if (!complete) { + complete = commit_is_complete(iter); + } else if (iter->ref_cnt == 0) { + commit_destroy(iter); + } } } +void wlr_commit_inhibit(struct wlr_commit *commit) { + assert(commit && !commit_is_complete(commit)); + ++commit->inhibit; +} + +void wlr_commit_uninhibit(struct wlr_commit *commit) { + assert(commit && commit->inhibit > 0); + --commit->inhibit; + + if (commit_is_complete(commit)) { + wlr_signal_emit_safe(&commit->events.complete, commit); + + if (commit_is_latest(commit)) { + struct wlr_surface_2 *surf = commit->surface; + surface_prune_commits(surf); + wlr_signal_emit_safe(&surf->events.commit, surf); + } + } +} + +void wlr_commit_set(struct wlr_commit *commit, uint32_t id, void *data) { + struct wlr_compositor *comp = commit->surface->compositor; + + // They didn't get their ID from wlr_compositor_register + assert(id < comp->ids); + + // This can happen if wlr_compositor_register is called after + // the commit was created. + if (commit->state_len < comp->ids) { + void **tmp = realloc(commit->state, + sizeof(*commit->state) * comp->ids); + if (!tmp) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return; + } + + commit->state = tmp; + for (size_t i = commit->state_len; i < comp->ids; ++i) { + commit->state[i] = NULL; + } + commit->state_len = comp->ids; + } + + commit->state[id] = data; +} + +void *wlr_commit_get(struct wlr_commit *commit, uint32_t id) { + if (id >= commit->state_len) { + return NULL; + } + return commit->state[id]; +}; + +static void surface_destroy(struct wl_client *client, struct wl_resource *res) { + wl_resource_destroy(res); +} + +static void surface_attach(struct wl_client *client, struct wl_resource *res, + struct wl_resource *buffer, int32_t dx, int32_t dy) { + struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res); + struct wlr_commit *commit = wlr_surface_get_pending(surf); + + commit->buffer_resource = buffer; + commit->sx = dx; + commit->sy = dy; +} + +static void surface_damage(struct wl_client *client, struct wl_resource *res, + int32_t x, int32_t y, int32_t width, int32_t height) { + struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res); + struct wlr_commit *commit = wlr_surface_get_pending(surf); + + pixman_region32_union_rect(&commit->surface_damage, + &commit->surface_damage, x, y, width, height); +} + +static void callback_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +static void surface_frame(struct wl_client *client, struct wl_resource *res, + uint32_t id) { + struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res); + struct wlr_commit *commit = wlr_surface_get_pending(surf); + + struct wl_resource *callback = + wl_resource_create(client, &wl_callback_interface, 1, id); + if (!callback) { + wlr_log_errno(WLR_ERROR, "Failed to create callback resource"); + wl_resource_post_no_memory(surf->resource); + return; + } + + wl_resource_set_implementation(callback, NULL, NULL, + callback_resource_destroy); + + wl_list_insert(&commit->frame_callbacks, wl_resource_get_link(callback)); +} + +static void surface_set_opaque_region(struct wl_client *client, + struct wl_resource *res, struct wl_resource *region_res) { + struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res); + struct wlr_commit *commit = wlr_surface_get_pending(surf); + + if (region_res) { + pixman_region32_t *region = wlr_region_from_resource(region_res); + pixman_region32_copy(&commit->opaque_region, region); + } else { + pixman_region32_clear(&commit->opaque_region); + } +} + +static void surface_set_input_region(struct wl_client *client, + struct wl_resource *res, struct wl_resource *input_res) { + struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res); + struct wlr_commit *commit = wlr_surface_get_pending(surf); + + if (input_res) { + pixman_region32_t *region = wlr_region_from_resource(input_res); + pixman_region32_copy(&commit->input_region, region); + } else { + pixman_region32_union_rect(&commit->input_region, + &commit->input_region, INT_MIN, INT_MIN, UINT_MAX, UINT_MAX); + } +} + +static void surface_set_buffer_transform(struct wl_client *client, + struct wl_resource *res, int32_t transform) { + struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res); + struct wlr_commit *commit = wlr_surface_get_pending(surf); + + if (transform < 0 || transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) { + wl_resource_post_error(surf->resource, + WL_SURFACE_ERROR_INVALID_TRANSFORM, + "transform value (%"PRId32") is not valid wl_output.transform enum", + transform); + return; + } + + commit->transform = transform; +} + +static void surface_set_buffer_scale(struct wl_client *client, + struct wl_resource *res, int32_t scale) { + struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res); + struct wlr_commit *commit = wlr_surface_get_pending(surf); + + if (scale <= 0) { + wl_resource_post_error(surf->resource, + WL_SURFACE_ERROR_INVALID_SCALE, + "scale value (%"PRId32") is not positive", + scale); + return; + } + + commit->scale = scale; +} + +static void surface_damage_buffer(struct wl_client *client, struct wl_resource *res, + int32_t x, int32_t y, int32_t width, int32_t height) { + struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res); + struct wlr_commit *commit = wlr_surface_get_pending(surf); + + /* + * The client is being extremely stupid, but there is nothing in the + * standard mentioning that this is an error, so we just ignore it. + */ + if (width < 0 || height < 0) { + return; + } + + pixman_region32_union_rect(&commit->buffer_damage, + &commit->buffer_damage, x, y, width, height); +} + +static void surface_commit(struct wl_client *client, struct wl_resource *res) { + struct wlr_surface_2 *surf = wlr_surface_from_resource_2(res); + struct wlr_commit *commit = wlr_surface_get_pending(surf); + + commit->committed = true; + wl_list_insert(&surf->committed, &commit->link); + + surf->pending = commit_create(surf); + if (!surf->pending) { + wl_resource_post_no_memory(surf->resource); + return; + } + + surf->pending->buffer_resource = commit->buffer_resource; + pixman_region32_copy(&surf->pending->opaque_region, &commit->opaque_region); + pixman_region32_copy(&surf->pending->input_region, &commit->input_region); + surf->pending->transform = commit->transform; + surf->pending->scale = commit->scale; + + /* + * The wayland protocol says we'll signal these in the order they're + * committed, so we make sure to add them to the end of the list. + */ + wl_list_insert_list(surf->frame_callbacks.prev, &commit->frame_callbacks); + wl_list_init(&commit->frame_callbacks); + + struct wlr_compositor_new_state_args args = { + .old = commit, + .new = surf->pending, + }; + + wlr_signal_emit_safe(&commit->events.commit, commit); + wlr_signal_emit_safe(&surf->compositor->events.new_state, &args); + + surface_prune_commits(surf); + + if (commit_is_complete(commit)) { + wlr_signal_emit_safe(&commit->events.complete, commit); + wlr_signal_emit_safe(&surf->events.commit, surf); + } +} + +static struct wl_surface_interface surface_impl = { + .destroy = surface_destroy, + .attach = surface_attach, + .damage = surface_damage, + .frame = surface_frame, + .set_opaque_region = surface_set_opaque_region, + .set_input_region = surface_set_input_region, + .set_buffer_transform = surface_set_buffer_transform, + .set_buffer_scale = surface_set_buffer_scale, + .damage_buffer = surface_damage_buffer, + .commit = surface_commit, +}; + +struct wlr_surface_2 *wlr_surface_from_resource_2(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_compositor_interface, + &surface_impl)); + return wl_resource_get_user_data(resource); +} + +static void surface_resource_destroy(struct wl_resource *resource) { + struct wlr_surface_2 *surf = wlr_surface_from_resource_2(resource); + + wlr_signal_emit_safe(&surf->events.destroy, surf); + + struct wlr_commit *iter, *tmp; + wl_list_for_each_reverse_safe(iter, tmp, &surf->committed, link) { + commit_destroy(iter); + } + + free(surf); +} static const struct wl_compositor_interface compositor_impl; - -static struct wlr_compositor *compositor_from_resource( - struct wl_resource *resource) { +static struct wlr_compositor *compositor_from_resource(struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &wl_compositor_interface, &compositor_impl)); return wl_resource_get_user_data(resource); @@ -143,21 +484,68 @@ static void compositor_create_surface(struct wl_client *client, struct wl_resource *resource, uint32_t id) { struct wlr_compositor *compositor = compositor_from_resource(resource); - struct wlr_surface *surface = wlr_surface_create(client, - wl_resource_get_version(resource), id, compositor->renderer, - &compositor->surface_resources); - if (surface == NULL) { - return; + struct wlr_surface_2 *surf = calloc(1, sizeof(*surf)); + if (!surf) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + goto error_post; } - wlr_signal_emit_safe(&compositor->events.new_surface, surface); + surf->resource = wl_resource_create(client, &wl_surface_interface, + wl_resource_get_version(resource), id); + if (!surf->resource) { + wlr_log_errno(WLR_ERROR, "Failed to create surface resource"); + goto error_surf; + } + + wl_resource_set_implementation(surf->resource, &surface_impl, + surf, surface_resource_destroy); + + wl_signal_init(&surf->events.destroy); + wl_list_init(&surf->committed); + + surf->pending = commit_create(surf); + if (!surf->pending) { + goto error_resource; + } + + struct wlr_compositor_new_state_args args = { + .old = NULL, + .new = surf->pending, + }; + + wlr_signal_emit_safe(&compositor->events.new_surface_2, surf); + wlr_signal_emit_safe(&compositor->events.new_state, &args); + + return; + +error_resource: + wl_resource_destroy(surf->resource); +error_surf: + free(surf); +error_post: + wl_client_post_no_memory(client); } static void compositor_create_region(struct wl_client *client, struct wl_resource *resource, uint32_t id) { - struct wlr_compositor *compositor = compositor_from_resource(resource); + pixman_region32_t *region = calloc(1, sizeof(*region)); + if (!region) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + wl_client_post_no_memory(client); + return; + } - wlr_region_create(client, 1, id, &compositor->region_resources); + pixman_region32_init(region); + + struct wl_resource *res = + wl_resource_create(client, &wl_region_interface, 1, id); + if (!res) { + free(region); + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(res, ®ion_impl, region, + region_resource_destroy); } static const struct wl_compositor_interface compositor_impl = { @@ -165,81 +553,119 @@ static const struct wl_compositor_interface compositor_impl = { .create_region = compositor_create_region, }; -static void compositor_resource_destroy(struct wl_resource *resource) { - wl_list_remove(wl_resource_get_link(resource)); -} - -static void compositor_bind(struct wl_client *wl_client, void *data, +static void compositor_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { - struct wlr_compositor *compositor = data; - assert(wl_client && compositor); + struct wlr_compositor *comp = data; - struct wl_resource *resource = - wl_resource_create(wl_client, &wl_compositor_interface, version, id); - if (resource == NULL) { - wl_client_post_no_memory(wl_client); + struct wl_resource *res = + wl_resource_create(client, &wl_compositor_interface, version, id); + if (!res) { + wlr_log_errno(WLR_ERROR, "Failed to create compositor resource"); + wl_client_post_no_memory(client); return; } - wl_resource_set_implementation(resource, &compositor_impl, - compositor, compositor_resource_destroy); - wl_list_insert(&compositor->resources, wl_resource_get_link(resource)); + + wl_resource_set_implementation(res, &compositor_impl, comp, NULL); } -void wlr_compositor_destroy(struct wlr_compositor *compositor) { - if (compositor == NULL) { - return; - } - wlr_signal_emit_safe(&compositor->events.destroy, compositor); - subcompositor_finish(&compositor->subcompositor); - wl_list_remove(&compositor->display_destroy.link); - wl_global_destroy(compositor->global); - struct wl_resource *resource, *tmp; - wl_resource_for_each_safe(resource, tmp, &compositor->surface_resources) { - wl_resource_destroy(resource); - } - wl_resource_for_each_safe(resource, tmp, &compositor->region_resources) { - wl_resource_destroy(resource); - } - wl_resource_for_each_safe(resource, tmp, &compositor->resources) { - wl_resource_destroy(resource); - } - free(compositor); -} +static void compositor_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_compositor *comp = wl_container_of(listener, comp, display_destroy); -static void handle_display_destroy(struct wl_listener *listener, void *data) { - struct wlr_compositor *compositor = - wl_container_of(listener, compositor, display_destroy); - wlr_compositor_destroy(compositor); + subcompositor_finish(&comp->subcompositor); + wl_list_remove(&comp->display_destroy.link); + wl_global_destroy(comp->global); + + free(comp); } struct wlr_compositor *wlr_compositor_create(struct wl_display *display, struct wlr_renderer *renderer) { - struct wlr_compositor *compositor = - calloc(1, sizeof(struct wlr_compositor)); - if (!compositor) { - wlr_log_errno(WLR_ERROR, "Could not allocate wlr compositor"); + struct wlr_compositor *comp = calloc(1, sizeof(*comp)); + if (!comp) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); return NULL; } - compositor->global = wl_global_create(display, &wl_compositor_interface, - COMPOSITOR_VERSION, compositor, compositor_bind); - if (!compositor->global) { - free(compositor); - wlr_log_errno(WLR_ERROR, "Could not allocate compositor global"); + comp->global = wl_global_create(display, &wl_compositor_interface, + COMPOSITOR_VERSION, comp, compositor_bind); + if (!comp->global) { + wlr_log_errno(WLR_ERROR, "Failed to create wayland global"); + free(comp); return NULL; } - compositor->renderer = renderer; + comp->renderer = renderer; - wl_list_init(&compositor->resources); - wl_list_init(&compositor->surface_resources); - wl_list_init(&compositor->region_resources); - wl_signal_init(&compositor->events.new_surface); - wl_signal_init(&compositor->events.destroy); + wl_signal_init(&comp->events.new_surface); + wl_signal_init(&comp->events.new_surface_2); + wl_signal_init(&comp->events.new_state); - subcompositor_init(&compositor->subcompositor, display); + subcompositor_init(&comp->subcompositor, display); - compositor->display_destroy.notify = handle_display_destroy; - wl_display_add_destroy_listener(display, &compositor->display_destroy); + comp->display_destroy.notify = compositor_display_destroy; + wl_display_add_destroy_listener(display, &comp->display_destroy); - return compositor; + return comp; +} + +uint32_t wlr_compositor_register(struct wlr_compositor *compositor) { + assert(compositor); + return compositor->ids++; +} + +struct wlr_commit *wlr_surface_get_commit(struct wlr_surface_2 *surf) { + surface_prune_commits(surf); + + struct wlr_commit *iter; + wl_list_for_each(iter, &surf->committed, link) { + if (commit_is_complete(iter)) { + ++iter->ref_cnt; + return iter; + } + } + + return NULL; +} + +struct wlr_commit *wlr_surface_get_pending(struct wlr_surface_2 *surf) { + return surf->pending; +} + +void wlr_surface_send_enter_2(struct wlr_surface_2 *surf, struct wlr_output *output) { + struct wl_client *client = wl_resource_get_client(surf->resource); + struct wl_resource *iter; + wl_resource_for_each(iter, &output->resources) { + if (wl_resource_get_client(iter) == client) { + wl_surface_send_enter(surf->resource, iter); + } + } +} + +void wlr_surface_send_leave_2(struct wlr_surface_2 *surf, struct wlr_output *output) { + struct wl_client *client = wl_resource_get_client(surf->resource); + struct wl_resource *iter; + wl_resource_for_each(iter, &output->resources) { + if (wl_resource_get_client(iter) == client) { + wl_surface_send_leave(surf->resource, iter); + } + } +} + +static inline int64_t timespec_to_msec(const struct timespec *a) { + return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; +} + +void wlr_surface_send_frame_done_2(struct wlr_surface_2 *surf, + const struct timespec *ts) { + struct wl_resource *iter, *tmp; + wl_resource_for_each_safe(iter, tmp, &surf->frame_callbacks) { + wl_callback_send_done(iter, timespec_to_msec(ts)); + wl_resource_destroy(iter); + } +} + +void wlr_commit_unref(struct wlr_commit *commit) { + assert(commit && commit->ref_cnt > 0); + --commit->ref_cnt; + + surface_prune_commits(commit->surface); } diff --git a/types/wlr_pointer_constraints_v1.c b/types/wlr_pointer_constraints_v1.c index 196af92ec..9ab2b20c0 100644 --- a/types/wlr_pointer_constraints_v1.c +++ b/types/wlr_pointer_constraints_v1.c @@ -5,8 +5,8 @@ #include #include #include +#include #include -#include #include #include "util/signal.h" diff --git a/types/wlr_region.c b/types/wlr_region.c deleted file mode 100644 index 6996ab148..000000000 --- a/types/wlr_region.c +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static void region_add(struct wl_client *client, struct wl_resource *resource, - int32_t x, int32_t y, int32_t width, int32_t height) { - pixman_region32_t *region = wlr_region_from_resource(resource); - pixman_region32_union_rect(region, region, x, y, width, height); -} - -static void region_subtract(struct wl_client *client, struct wl_resource *resource, - int32_t x, int32_t y, int32_t width, int32_t height) { - pixman_region32_t *region = wlr_region_from_resource(resource); - pixman_region32_union_rect(region, region, x, y, width, height); - - pixman_region32_t rect; - pixman_region32_init_rect(&rect, x, y, width, height); - pixman_region32_subtract(region, region, &rect); - pixman_region32_fini(&rect); -} - -static void region_destroy(struct wl_client *client, struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static const struct wl_region_interface region_impl = { - .destroy = region_destroy, - .add = region_add, - .subtract = region_subtract, -}; - -static void region_handle_resource_destroy(struct wl_resource *resource) { - pixman_region32_t *reg = wlr_region_from_resource(resource); - - wl_list_remove(wl_resource_get_link(resource)); - - pixman_region32_fini(reg); - free(reg); -} - -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)); - if (region == NULL) { - wl_client_post_no_memory(client); - return NULL; - } - - pixman_region32_init(region); - - struct wl_resource *region_resource = wl_resource_create(client, - &wl_region_interface, version, id); - if (region_resource == NULL) { - free(region); - wl_client_post_no_memory(client); - return NULL; - } - wl_resource_set_implementation(region_resource, ®ion_impl, region, - 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; -} - -pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &wl_region_interface, - ®ion_impl)); - return wl_resource_get_user_data(resource); -} diff --git a/types/wlr_surface.c b/types/wlr_surface.c index febfcd438..2d34aac8b 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -566,8 +565,6 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) { wlr_signal_emit_safe(&surface->events.destroy, surface); - wl_list_remove(wl_resource_get_link(surface->resource)); - wl_list_remove(&surface->renderer_destroy.link); surface_state_finish(&surface->pending); surface_state_finish(&surface->current); @@ -587,8 +584,7 @@ static void surface_handle_renderer_destroy(struct wl_listener *listener, } 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) { + uint32_t version, uint32_t id, struct wlr_renderer *renderer) { assert(version <= SURFACE_VERSION); struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface)); @@ -626,13 +622,6 @@ struct wlr_surface *wlr_surface_create(struct wl_client *client, wl_signal_add(&renderer->events.destroy, &surface->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; } @@ -679,7 +668,6 @@ static struct wlr_subsurface *subsurface_from_resource( static void subsurface_resource_destroy(struct wl_resource *resource) { struct wlr_subsurface *subsurface = subsurface_from_resource(resource); - wl_list_remove(wl_resource_get_link(resource)); subsurface_destroy(subsurface); } @@ -930,8 +918,7 @@ static void subsurface_handle_surface_destroy(struct wl_listener *listener, } struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface, - struct wlr_surface *parent, uint32_t version, uint32_t id, - struct wl_list *resource_list) { + struct wlr_surface *parent, uint32_t version, uint32_t id) { assert(version <= SUBSURFACE_VERSION); struct wl_client *client = wl_resource_get_client(surface->resource); @@ -974,13 +961,6 @@ struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface, 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); return subsurface; diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 34bbd02fc..f4d9f9545 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -1387,16 +1387,6 @@ static void handle_compositor_new_surface(struct wl_listener *listener, } } -static void handle_compositor_destroy(struct wl_listener *listener, - void *data) { - struct wlr_xwm *xwm = - wl_container_of(listener, xwm, compositor_destroy); - wl_list_remove(&xwm->compositor_new_surface.link); - wl_list_remove(&xwm->compositor_destroy.link); - wl_list_init(&xwm->compositor_new_surface.link); - wl_list_init(&xwm->compositor_destroy.link); -} - void wlr_xwayland_surface_activate(struct wlr_xwayland_surface *xsurface, bool activated) { struct wlr_xwayland_surface *focused = xsurface->xwm->focus_surface; @@ -1475,7 +1465,6 @@ void xwm_destroy(struct wlr_xwm *xwm) { xwayland_surface_destroy(xsurface); } wl_list_remove(&xwm->compositor_new_surface.link); - wl_list_remove(&xwm->compositor_destroy.link); xcb_disconnect(xwm->xcb_conn); free(xwm); @@ -1770,9 +1759,6 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) { xwm->compositor_new_surface.notify = handle_compositor_new_surface; wl_signal_add(&wlr_xwayland->compositor->events.new_surface, &xwm->compositor_new_surface); - xwm->compositor_destroy.notify = handle_compositor_destroy; - wl_signal_add(&wlr_xwayland->compositor->events.destroy, - &xwm->compositor_destroy); xwm_create_wm_window(xwm);