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.
This commit is contained in:
Scott Anderson 2019-02-15 23:39:20 +13:00
parent cf3b083c32
commit e76d4581ce
12 changed files with 619 additions and 261 deletions

View file

@ -31,7 +31,6 @@ install_headers(
'wlr_presentation_time.h', 'wlr_presentation_time.h',
'wlr_primary_selection_v1.h', 'wlr_primary_selection_v1.h',
'wlr_primary_selection.h', 'wlr_primary_selection.h',
'wlr_region.h',
'wlr_relative_pointer_v1.h', 'wlr_relative_pointer_v1.h',
'wlr_screencopy_v1.h', 'wlr_screencopy_v1.h',
'wlr_screenshooter.h', 'wlr_screenshooter.h',

View file

@ -12,34 +12,105 @@
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
struct wlr_commit;
struct wlr_output;
struct wlr_surface; struct wlr_surface;
struct wlr_subcompositor { struct wlr_subcompositor {
struct wl_global *global; struct wl_global *global;
struct wl_list resources;
struct wl_list subsurface_resources;
}; };
struct wlr_compositor { struct wlr_compositor {
struct wl_global *global; struct wl_global *global;
struct wl_list resources;
struct wlr_renderer *renderer; struct wlr_renderer *renderer;
struct wl_list surface_resources;
struct wl_list region_resources; uint32_t ids;
struct wlr_subcompositor subcompositor; struct wlr_subcompositor subcompositor;
struct wl_listener display_destroy;
struct { struct {
struct wl_signal new_surface; 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; struct wl_signal destroy;
} events; } 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_compositor *wlr_compositor_create(struct wl_display *display,
struct wlr_renderer *renderer); 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); 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_subsurface *wlr_subsurface_from_wlr_surface(
struct wlr_surface *surface); struct wlr_surface *surface);
pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource);
#endif #endif

View file

@ -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 <pixman.h>
#include <wayland-server-protocol.h>
/*
* 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

View file

@ -157,8 +157,7 @@ struct wlr_renderer;
* is non-NULL, adds the surface's resource to the list. * is non-NULL, adds the surface's resource to the list.
*/ */
struct wlr_surface *wlr_surface_create(struct wl_client *client, struct wlr_surface *wlr_surface_create(struct wl_client *client,
uint32_t version, uint32_t id, struct wlr_renderer *renderer, 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
@ -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. * is non-NULL, adds the subsurface's resource to the list.
*/ */
struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface, struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface,
struct wlr_surface *parent, uint32_t version, 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.

View file

@ -128,7 +128,6 @@ struct wlr_xwm {
#endif #endif
struct wl_listener compositor_new_surface; struct wl_listener compositor_new_surface;
struct wl_listener compositor_destroy;
struct wl_listener seat_set_selection; struct wl_listener seat_set_selection;
struct wl_listener seat_set_primary_selection; struct wl_listener seat_set_primary_selection;
struct wl_listener seat_start_drag; struct wl_listener seat_start_drag;

View file

@ -2,7 +2,7 @@
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <wlr/types/wlr_region.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_xcursor_manager.h> #include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/util/edges.h> #include <wlr/util/edges.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>

View file

@ -54,7 +54,6 @@ lib_wlr_types = static_library(
'wlr_presentation_time.c', 'wlr_presentation_time.c',
'wlr_primary_selection_v1.c', 'wlr_primary_selection_v1.c',
'wlr_primary_selection.c', 'wlr_primary_selection.c',
'wlr_region.c',
'wlr_relative_pointer_v1.c', 'wlr_relative_pointer_v1.c',
'wlr_screencopy_v1.c', 'wlr_screencopy_v1.c',
'wlr_screenshooter.c', 'wlr_screenshooter.c',

View file

@ -1,8 +1,9 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <limits.h>
#include <inttypes.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_region.h>
#include <wlr/types/wlr_surface.h> #include <wlr/types/wlr_surface.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "util/signal.h" #include "util/signal.h"
@ -22,15 +23,6 @@ struct wlr_subsurface *wlr_subsurface_from_wlr_surface(
return (struct wlr_subsurface *)surface->role_data; 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, static void subcompositor_handle_destroy(struct wl_client *client,
struct wl_resource *resource) { struct wl_resource *resource) {
wl_resource_destroy(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 *resource, uint32_t id,
struct wl_resource *surface_resource, struct wl_resource *surface_resource,
struct wl_resource *parent_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 *surface = wlr_surface_from_resource(surface_resource);
struct wlr_surface *parent = wlr_surface_from_resource(parent_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; return;
} }
wlr_subsurface_create(surface, parent, wl_resource_get_version(resource), wlr_subsurface_create(surface, parent,
id, &subcompositor->subsurface_resources); wl_resource_get_version(resource), id);
} }
static const struct wl_subcompositor_interface subcompositor_impl = { 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, .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, static void subcompositor_bind(struct wl_client *client, void *data,
uint32_t version, uint32_t id) { uint32_t version, uint32_t id) {
struct wlr_subcompositor *subcompositor = data;
struct wl_resource *resource = struct wl_resource *resource =
wl_resource_create(client, &wl_subcompositor_interface, 1, id); wl_resource_create(client, &wl_subcompositor_interface, 1, id);
if (resource == NULL) { if (resource == NULL) {
wl_client_post_no_memory(client); wl_client_post_no_memory(client);
return; return;
} }
wl_resource_set_implementation(resource, &subcompositor_impl, wl_resource_set_implementation(resource, &subcompositor_impl, NULL, NULL);
subcompositor, subcompositor_resource_destroy);
wl_list_insert(&subcompositor->resources, wl_resource_get_link(resource));
} }
static void subcompositor_init(struct wlr_subcompositor *subcompositor, static void subcompositor_init(struct wlr_subcompositor *sc,
struct wl_display *display) { struct wl_display *display) {
subcompositor->global = wl_global_create(display, sc->global = wl_global_create(display, &wl_subcompositor_interface,
&wl_subcompositor_interface, SUBCOMPOSITOR_VERSION, subcompositor, SUBCOMPOSITOR_VERSION, NULL, subcompositor_bind);
subcompositor_bind); if (sc->global == NULL) {
if (subcompositor->global == NULL) { wlr_log_errno(WLR_ERROR, "Failed to create subcompositor global");
wlr_log_errno(WLR_ERROR, "Could not allocate subcompositor global");
return; return;
} }
wl_list_init(&subcompositor->resources);
wl_list_init(&subcompositor->subsurface_resources);
} }
static void subcompositor_finish(struct wlr_subcompositor *subcompositor) { static void subcompositor_finish(struct wlr_subcompositor *sc) {
wl_global_destroy(subcompositor->global); wl_global_destroy(sc->global);
struct wl_resource *resource, *tmp; }
wl_resource_for_each_safe(resource, tmp,
&subcompositor->subsurface_resources) { static const struct wl_region_interface region_impl;
wl_resource_destroy(resource);
pixman_region32_t *wlr_region_from_resource(struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &wl_region_interface,
&region_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 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, assert(wl_resource_instance_of(resource, &wl_compositor_interface,
&compositor_impl)); &compositor_impl));
return wl_resource_get_user_data(resource); 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 wl_resource *resource, uint32_t id) {
struct wlr_compositor *compositor = compositor_from_resource(resource); struct wlr_compositor *compositor = compositor_from_resource(resource);
struct wlr_surface *surface = wlr_surface_create(client, struct wlr_surface_2 *surf = calloc(1, sizeof(*surf));
wl_resource_get_version(resource), id, compositor->renderer, if (!surf) {
&compositor->surface_resources); wlr_log_errno(WLR_ERROR, "Allocation failed");
if (surface == NULL) { goto error_post;
return;
} }
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, static void 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); 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, &region_impl, region,
region_resource_destroy);
} }
static const struct wl_compositor_interface compositor_impl = { 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, .create_region = compositor_create_region,
}; };
static void compositor_resource_destroy(struct wl_resource *resource) { static void compositor_bind(struct wl_client *client, void *data,
wl_list_remove(wl_resource_get_link(resource));
}
static void compositor_bind(struct wl_client *wl_client, void *data,
uint32_t version, uint32_t id) { uint32_t version, uint32_t id) {
struct wlr_compositor *compositor = data; struct wlr_compositor *comp = data;
assert(wl_client && compositor);
struct wl_resource *resource = struct wl_resource *res =
wl_resource_create(wl_client, &wl_compositor_interface, version, id); wl_resource_create(client, &wl_compositor_interface, version, id);
if (resource == NULL) { if (!res) {
wl_client_post_no_memory(wl_client); wlr_log_errno(WLR_ERROR, "Failed to create compositor resource");
wl_client_post_no_memory(client);
return; return;
} }
wl_resource_set_implementation(resource, &compositor_impl,
compositor, compositor_resource_destroy); wl_resource_set_implementation(res, &compositor_impl, comp, NULL);
wl_list_insert(&compositor->resources, wl_resource_get_link(resource));
} }
void wlr_compositor_destroy(struct wlr_compositor *compositor) { static void compositor_display_destroy(struct wl_listener *listener, void *data) {
if (compositor == NULL) { struct wlr_compositor *comp = wl_container_of(listener, comp, display_destroy);
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 handle_display_destroy(struct wl_listener *listener, void *data) { subcompositor_finish(&comp->subcompositor);
struct wlr_compositor *compositor = wl_list_remove(&comp->display_destroy.link);
wl_container_of(listener, compositor, display_destroy); wl_global_destroy(comp->global);
wlr_compositor_destroy(compositor);
free(comp);
} }
struct wlr_compositor *wlr_compositor_create(struct wl_display *display, struct wlr_compositor *wlr_compositor_create(struct wl_display *display,
struct wlr_renderer *renderer) { struct wlr_renderer *renderer) {
struct wlr_compositor *compositor = struct wlr_compositor *comp = calloc(1, sizeof(*comp));
calloc(1, sizeof(struct wlr_compositor)); if (!comp) {
if (!compositor) { wlr_log_errno(WLR_ERROR, "Allocation failed");
wlr_log_errno(WLR_ERROR, "Could not allocate wlr compositor");
return NULL; return NULL;
} }
compositor->global = wl_global_create(display, &wl_compositor_interface, comp->global = wl_global_create(display, &wl_compositor_interface,
COMPOSITOR_VERSION, compositor, compositor_bind); COMPOSITOR_VERSION, comp, compositor_bind);
if (!compositor->global) { if (!comp->global) {
free(compositor); wlr_log_errno(WLR_ERROR, "Failed to create wayland global");
wlr_log_errno(WLR_ERROR, "Could not allocate compositor global"); free(comp);
return NULL; return NULL;
} }
compositor->renderer = renderer; comp->renderer = renderer;
wl_list_init(&compositor->resources); wl_signal_init(&comp->events.new_surface);
wl_list_init(&compositor->surface_resources); wl_signal_init(&comp->events.new_surface_2);
wl_list_init(&compositor->region_resources); wl_signal_init(&comp->events.new_state);
wl_signal_init(&compositor->events.new_surface);
wl_signal_init(&compositor->events.destroy);
subcompositor_init(&compositor->subcompositor, display); subcompositor_init(&comp->subcompositor, display);
compositor->display_destroy.notify = handle_display_destroy; comp->display_destroy.notify = compositor_display_destroy;
wl_display_add_destroy_listener(display, &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);
} }

View file

@ -5,8 +5,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/types/wlr_box.h> #include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_pointer_constraints_v1.h> #include <wlr/types/wlr_pointer_constraints_v1.h>
#include <wlr/types/wlr_region.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "util/signal.h" #include "util/signal.h"

View file

@ -1,78 +0,0 @@
#include <assert.h>
#include <pixman.h>
#include <stdio.h>
#include <stdlib.h>
#include <wayland-server.h>
#include <wlr/types/wlr_region.h>
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, &region_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,
&region_impl));
return wl_resource_get_user_data(resource);
}

View file

@ -5,7 +5,6 @@
#include <wlr/types/wlr_buffer.h> #include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_region.h>
#include <wlr/types/wlr_surface.h> #include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
@ -566,8 +565,6 @@ 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); wl_list_remove(&surface->renderer_destroy.link);
surface_state_finish(&surface->pending); surface_state_finish(&surface->pending);
surface_state_finish(&surface->current); 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, struct wlr_surface *wlr_surface_create(struct wl_client *client,
uint32_t version, uint32_t id, struct wlr_renderer *renderer, uint32_t version, uint32_t id, struct wlr_renderer *renderer) {
struct wl_list *resource_list) {
assert(version <= SURFACE_VERSION); assert(version <= SURFACE_VERSION);
struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface)); 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); 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;
} }
@ -679,7 +668,6 @@ static struct wlr_subsurface *subsurface_from_resource(
static void subsurface_resource_destroy(struct wl_resource *resource) { static void subsurface_resource_destroy(struct wl_resource *resource) {
struct wlr_subsurface *subsurface = subsurface_from_resource(resource); struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
wl_list_remove(wl_resource_get_link(resource));
subsurface_destroy(subsurface); 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_subsurface *wlr_subsurface_create(struct wlr_surface *surface,
struct wlr_surface *parent, uint32_t version, uint32_t id, struct wlr_surface *parent, uint32_t version, uint32_t id) {
struct wl_list *resource_list) {
assert(version <= SUBSURFACE_VERSION); assert(version <= SUBSURFACE_VERSION);
struct wl_client *client = wl_resource_get_client(surface->resource); 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; 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;

View file

@ -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, void wlr_xwayland_surface_activate(struct wlr_xwayland_surface *xsurface,
bool activated) { bool activated) {
struct wlr_xwayland_surface *focused = xsurface->xwm->focus_surface; struct wlr_xwayland_surface *focused = xsurface->xwm->focus_surface;
@ -1475,7 +1465,6 @@ void xwm_destroy(struct wlr_xwm *xwm) {
xwayland_surface_destroy(xsurface); xwayland_surface_destroy(xsurface);
} }
wl_list_remove(&xwm->compositor_new_surface.link); wl_list_remove(&xwm->compositor_new_surface.link);
wl_list_remove(&xwm->compositor_destroy.link);
xcb_disconnect(xwm->xcb_conn); xcb_disconnect(xwm->xcb_conn);
free(xwm); 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; xwm->compositor_new_surface.notify = handle_compositor_new_surface;
wl_signal_add(&wlr_xwayland->compositor->events.new_surface, wl_signal_add(&wlr_xwayland->compositor->events.new_surface,
&xwm->compositor_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); xwm_create_wm_window(xwm);