swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

commit d0272431e80fe1f81869b8df10109cac828fa095
parent 96ab570aa427013949bc6946c5640846d25336fb
Author: Michael Forney <mforney@mforney.org>
Date:   Fri, 21 Jun 2013 01:35:34 -0700

surface: Properly handle buffer attach and destroy

Diffstat:
Msurface.c | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msurface.h | 1+
2 files changed, 68 insertions(+), 18 deletions(-)

diff --git a/surface.c b/surface.c @@ -10,9 +10,21 @@ static pixman_box32_t infinite_extents = { .x2 = INT32_MAX, .y2 = INT32_MAX }; +/** + * Removes a buffer from a surface state. + */ +static void handle_buffer_destroy(struct wl_listener * listener, void * data) +{ + struct swc_surface_state * state; + + state = wl_container_of(listener, state, buffer_destroy_listener); + state->buffer = NULL; +} + static void state_initialize(struct swc_surface_state * state) { state->buffer = NULL; + state->buffer_destroy_listener.notify = &handle_buffer_destroy; pixman_region32_init(&state->damage); pixman_region32_init(&state->opaque); @@ -25,6 +37,12 @@ static void state_finish(struct swc_surface_state * state) { struct wl_resource * resource, * tmp; + if (state->buffer) + { + /* Remove any buffer listeners */ + wl_list_remove(&state->buffer_destroy_listener.link); + } + pixman_region32_fini(&state->damage); pixman_region32_fini(&state->opaque); pixman_region32_fini(&state->input); @@ -34,6 +52,37 @@ static void state_finish(struct swc_surface_state * state) wl_resource_destroy(resource); } +/** + * In order to set the buffer of a surface state (current or pending), we need + * to manage the destroy listeners we have for the new and old buffer. + * + * @return: Whether or not the buffer was changed. + */ +static bool state_set_buffer(struct swc_surface_state * state, + struct wl_buffer * buffer) +{ + if (buffer == state->buffer) + return false; + + if (state->buffer) + { + /* No longer need to worry about the old buffer being destroyed. */ + wl_list_remove(&state->buffer_destroy_listener.link); + } + + if (buffer) + { + /* Need to watch the new buffer for destruction so we can remove it + * from state. */ + wl_resource_add_destroy_listener(&buffer->resource, + &state->buffer_destroy_listener); + } + + state->buffer = buffer; + + return true; +} + static void destroy(struct wl_client * client, struct wl_resource * resource) { wl_resource_destroy(resource); @@ -43,25 +92,17 @@ static void attach(struct wl_client * client, struct wl_resource * resource, struct wl_resource * buffer_resource, int32_t x, int32_t y) { struct swc_surface * surface = wl_resource_get_user_data(resource); + struct wl_buffer * buffer + = buffer_resource ? wl_resource_get_user_data(buffer_resource) : NULL; - surface->pending.x = x; - surface->pending.y = y; - - if (buffer_resource) - { - struct wl_buffer * buffer = wl_resource_get_user_data(buffer_resource); + state_set_buffer(&surface->pending.state, buffer); - surface->pending.state.buffer = buffer; - surface->geometry.width = buffer->width; - surface->geometry.height = buffer->height; - } - else - { - surface->pending.state.buffer = NULL; + /* Adjust geometry of the surface to match the buffer. */ + surface->geometry.width = buffer ? buffer->width : 0; + surface->geometry.height = buffer ? buffer->height : 0; - surface->geometry.width = 0; - surface->geometry.height = 0; - } + surface->pending.x = x; + surface->pending.y = y; } static void damage(struct wl_client * client, struct wl_resource * resource, @@ -129,9 +170,17 @@ static void commit(struct wl_client * client, struct wl_resource * resource) event.data = surface; - if (surface->pending.state.buffer != surface->state.buffer) + /* Attach */ + if (surface->state.buffer != surface->pending.state.buffer) { - surface->state.buffer = surface->pending.state.buffer; + if (surface->state.buffer) + { + /* Release the old buffer, it's no longer needed. */ + wl_buffer_send_release(&surface->state.buffer->resource); + } + + state_set_buffer(&surface->state, surface->pending.state.buffer); + event.type = SWC_SURFACE_ATTACH; wl_signal_emit(&surface->event_signal, &event); } diff --git a/surface.h b/surface.h @@ -27,6 +27,7 @@ struct swc_surface_state pixman_region32_t input; struct wl_list frame_callbacks; + struct wl_listener buffer_destroy_listener; }; struct swc_surface