swc

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

commit 9c6a405461cd4dc0d5620a0711283c18facf08c2
parent d0a9e34c63062fc8426ff450b417310dffbe6e56
Author: Michael Forney <mforney@mforney.org>
Date:   Wed, 11 Sep 2013 00:34:53 -0700

Introduce surface classes

Diffstat:
Mlibswc/Makefile.am | 1+
Mlibswc/compositor.c | 57+++++++--------------------------------------------------
Mlibswc/compositor.h | 20++++++++++++++++++++
Alibswc/compositor_surface.c | 321+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alibswc/compositor_surface.h | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlibswc/output.h | 2++
Mlibswc/renderer.c | 109++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mlibswc/surface.c | 77++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mlibswc/surface.h | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Dlibswc/surface_state.h | 30------------------------------
Mlibswc/util.h | 11+++++++++++
11 files changed, 642 insertions(+), 136 deletions(-)

diff --git a/libswc/Makefile.am b/libswc/Makefile.am @@ -11,6 +11,7 @@ libswc_la_SOURCES = \ output.c output.h \ buffer.c buffer.h \ surface.c surface.h \ + compositor_surface.c compositor_surface.h \ region.c region.h \ renderer.c renderer.h \ input_focus.c input_focus.h \ diff --git a/libswc/compositor.c b/libswc/compositor.c @@ -170,33 +170,6 @@ static void handle_tty_event(struct wl_listener * listener, void * data) } } -static void handle_surface_event(struct wl_listener * listener, void * data) -{ - struct swc_event * event = data; - struct swc_surface * surface = event->data; - struct swc_compositor * compositor = surface->compositor_state.compositor; - - switch (event->type) - { - case SWC_SURFACE_ATTACH: - swc_renderer_attach(&compositor->renderer, &compositor->outputs, - surface, surface->state.buffer); - break; - case SWC_SURFACE_REPAINT: - { - struct swc_output * output; - - wl_list_for_each(output, &compositor->outputs, link) - { - if (surface->output_mask & (1 << output->id)) - schedule_repaint_for_output(compositor, output); - } - - break; - } - } -} - static void handle_drm_event(struct wl_listener * listener, void * data) { struct swc_event * event = data; @@ -266,6 +239,11 @@ static void create_surface(struct wl_client * client, struct swc_surface * surface; struct swc_output * output; + printf("compositor.create_surface\n"); + + output = swc_container_of(compositor->outputs.next, typeof(*output), link); + + /* Initialize surface. */ surface = swc_surface_new(client, id); if (!surface) @@ -273,29 +251,6 @@ static void create_surface(struct wl_client * client, wl_resource_post_no_memory(resource); return; } - - printf("compositor_create_surface: %p\n", surface); - - output = swc_container_of(compositor->outputs.next, typeof(*output), link); - - /* Initialize compositor state */ - surface->compositor_state = (struct swc_compositor_surface_state) { - .compositor = compositor, - .event_listener = { - .notify = &handle_surface_event - }, - .destroy_listener = { - .notify = &handle_surface_destroy - } - }; - - wl_signal_add(&surface->event_signal, - &surface->compositor_state.event_listener); - wl_resource_add_destroy_listener(surface->resource, - &surface->compositor_state.destroy_listener); - - wl_list_insert(compositor->surfaces.prev, &surface->link); - surface->output_mask |= 1 << output->id; } static void create_region(struct wl_client * client, @@ -340,6 +295,8 @@ bool swc_compositor_initialize(struct swc_compositor * compositor, compositor->display = display; compositor->tty_listener.notify = &handle_tty_event; compositor->drm_listener.notify = &handle_drm_event; + compositor->compositor_class.interface + = &swc_compositor_class_implementation; compositor->udev = udev_new(); diff --git a/libswc/compositor.h b/libswc/compositor.h @@ -27,6 +27,23 @@ struct swc_compositor struct wl_list surfaces; struct wl_array key_bindings; + /* Internal state related to repainting the screen. */ + struct + { + pixman_region32_t damage; + pixman_region32_t opaque; + + /* A mask of outputs that have been repainted but are waiting on a page + * flip. */ + uint32_t pending_flips; + + /* A mask of outputs that are scheduled to be repainted on the next + * idle. */ + uint32_t scheduled_updates; + }; + + struct swc_surface_class compositor_class; + struct wl_listener tty_listener; struct wl_listener drm_listener; @@ -45,5 +62,8 @@ void swc_compositor_add_key_binding(struct swc_compositor * compositor, uint32_t modifiers, xkb_keysym_t key, swc_binding_handler_t handler, void * data); +void swc_compositor_schedule_update(struct swc_compositor * compositor, + struct swc_output * output); + #endif diff --git a/libswc/compositor_surface.c b/libswc/compositor_surface.c @@ -0,0 +1,321 @@ +/* swc: compositor_surface.c + * + * Copyright (c) 2013 Michael Forney + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "compositor_surface.h" +#include "compositor.h" +#include "util.h" + +#include <stdio.h> +#include <stdlib.h> + +static bool add(struct swc_surface * surface); +static void remove_(struct swc_surface * surface); +static void attach(struct swc_surface * surface, struct wl_resource * resource); +static void update(struct swc_surface * surface); +static void move(struct swc_surface * surface, int32_t x, int32_t y); + +const struct swc_surface_class_interface swc_compositor_class_implementation = { + .add = &add, + .remove = &remove_, + .attach = &attach, + .update = &update, + .move = &move +}; + +/** + * Adds damage from the region below a surface, taking into account it's clip + * region, to the region specified by `damage'. + */ +static void damage_below_surface(struct swc_surface * surface) +{ + struct swc_compositor * compositor = swc_container_of + (surface->class, typeof(*compositor), compositor_class); + struct swc_compositor_surface_state * state = surface->class_state; + pixman_region32_t damage_below; + + pixman_region32_init_with_extents(&damage_below, &state->extents); + pixman_region32_subtract(&damage_below, &damage_below, &state->clip); + pixman_region32_union(&compositor->damage, &compositor->damage, + &damage_below); + pixman_region32_fini(&damage_below); +} + +/** + * Completely damages the surface and its border. + */ +static void damage_surface(struct swc_surface * surface) +{ + struct swc_compositor_surface_state * state = surface->class_state; + printf("damaging surface\n"); + + pixman_region32_fini(&surface->state.damage); + pixman_region32_init_rect(&surface->state.damage, 0, 0, + surface->geometry.width, + surface->geometry.height); + state->border.damaged = true; +} + +static void update_extents(struct swc_surface * surface) +{ + struct swc_compositor_surface_state * state = surface->class_state; + + state->extents.x1 = surface->geometry.x - state->border.width; + state->extents.y1 = surface->geometry.y - state->border.width; + state->extents.x2 = surface->geometry.x + surface->geometry.width + + state->border.width; + state->extents.y2 = surface->geometry.y + surface->geometry.height + + state->border.width; + + /* Damage border. */ + state->border.damaged = true; +} + +static void update_outputs(struct swc_surface * surface) +{ + struct swc_compositor * compositor = swc_container_of + (surface->class, typeof(*compositor), compositor_class); + struct swc_compositor_surface_state * state = surface->class_state; + uint32_t old_outputs = surface->outputs, new_outputs = 0, + entered_outputs, left_outputs, changed_outputs; + struct swc_output * output; + struct wl_client * client; + struct wl_resource * resource; + + if (state->mapped) + { + wl_list_for_each(output, &compositor->outputs, link) + { + if (swc_rectangle_overlap(&output->geometry, &surface->geometry)) + new_outputs |= SWC_OUTPUT_MASK(output); + } + } + + if (new_outputs == old_outputs) + return; + + entered_outputs = new_outputs & ~old_outputs; + left_outputs = old_outputs & ~new_outputs; + changed_outputs = old_outputs ^ new_outputs; + + wl_list_for_each(output, &compositor->outputs, link) + { + if (!(changed_outputs & SWC_OUTPUT_MASK(output))) + continue; + + client = wl_resource_get_client(surface->resource); + resource = wl_resource_find_for_client(&output->resources, client); + + if (resource) + { + if (entered_outputs & SWC_OUTPUT_MASK(output)) + wl_surface_send_enter(surface->resource, resource); + else if (left_outputs & SWC_OUTPUT_MASK(output)) + wl_surface_send_leave(surface->resource, resource); + } + } + + surface->outputs = new_outputs; +} + +/* Compositor class */ +bool add(struct swc_surface * surface) +{ + struct swc_compositor * compositor = swc_container_of + (surface->class, typeof(*compositor), compositor_class); + struct swc_compositor_surface_state * state; + + state = malloc(sizeof *state); + + if (!state) + return false; + + state->compositor = compositor; + state->extents.x1 = surface->geometry.x; + state->extents.y1 = surface->geometry.y; + state->extents.x2 = surface->geometry.x + surface->geometry.width; + state->extents.y2 = surface->geometry.y + surface->geometry.height; + state->border.width = 0; + state->border.color = 0x000000; + state->border.damaged = false; + state->mapped = false; + + wl_signal_add(&surface->event_signal, &state->event_listener); + + pixman_region32_init(&state->clip); + + surface->class_state = state; + + return true; +} + +void remove_(struct swc_surface * surface) +{ + struct swc_compositor * compositor = swc_container_of + (surface->class, typeof(*compositor), compositor_class); + struct swc_compositor_surface_state * state = surface->class_state; + + swc_compositor_surface_hide(surface); + + wl_list_remove(&state->event_listener.link); + pixman_region32_fini(&state->clip); + + free(state); +} + +void attach(struct swc_surface * surface, struct wl_resource * resource) +{ + struct swc_compositor * compositor = swc_container_of + (surface->class, typeof(*compositor), compositor_class); + + swc_renderer_attach(&compositor->renderer, surface, + wl_resource_get_user_data(resource)); +} + +void update(struct swc_surface * surface) +{ + struct swc_compositor * compositor = swc_container_of + (surface->class, typeof(*compositor), compositor_class); + struct swc_compositor_surface_state * state = surface->class_state; + struct swc_output * output; + + if (!state->mapped) + return; + + wl_list_for_each(output, &compositor->outputs, link) + { + if (surface->outputs & SWC_OUTPUT_MASK(output)) + swc_compositor_schedule_update(compositor, output); + } +} + +void move(struct swc_surface * surface, int32_t x, int32_t y) +{ + struct swc_compositor * compositor = swc_container_of + (surface->class, typeof(*compositor), compositor_class); + struct swc_compositor_surface_state * state = surface->class_state; + + if (x == surface->geometry.x && y == surface->geometry.y) + return; + + if (state->mapped) + damage_below_surface(surface); + + surface->geometry.x = x; + surface->geometry.y = y; + + update_extents(surface); + + if (state->mapped) + { + /* Assume worst-case no clipping until we draw the next frame (in case + * the surface gets moved again before that). */ + pixman_region32_init(&state->clip); + + damage_below_surface(surface); + update(surface); + update_outputs(surface); + update(surface); + } +} + +void swc_compositor_surface_show(struct swc_surface * surface) +{ + struct swc_compositor * compositor = swc_container_of + (surface->class, typeof(*compositor), compositor_class); + struct swc_compositor_surface_state * state = surface->class_state; + + if (surface->class->interface != &swc_compositor_class_implementation) + return; + + if (state->mapped) + return; + + printf("showing surface %u\n", wl_resource_get_id(surface->resource)); + + state->mapped = true; + + /* Assume worst-case no clipping until we draw the next frame (in case the + * surface gets moved before that. */ + pixman_region32_clear(&state->clip); + + damage_surface(surface); + update_outputs(surface); + update(surface); + wl_list_insert(&compositor->surfaces, &surface->link); +} + +void swc_compositor_surface_hide(struct swc_surface * surface) +{ + struct swc_compositor * compositor = swc_container_of + (surface->class, typeof(*compositor), compositor_class); + struct swc_compositor_surface_state * state = surface->class_state; + + if (surface->class->interface != &swc_compositor_class_implementation) + return; + + if (!state->mapped) + return; + + /* Update all the outputs the surface was on. */ + update(surface); + + state->mapped = false; + + damage_below_surface(surface); + update_outputs(surface); + wl_list_remove(&surface->link); +} + +void swc_compositor_surface_set_border_width(struct swc_surface * surface, + uint32_t width) +{ + struct swc_compositor_surface_state * state = surface->class_state; + + if (state->border.width == width) + return; + + state->border.width = width; + state->border.damaged = true; + + /* XXX: Damage above surface for transparent surfaces? */ + + update_extents(surface); + update(surface); +} + +void swc_compositor_surface_set_border_color(struct swc_surface * surface, + uint32_t color) +{ + struct swc_compositor_surface_state * state = surface->class_state; + + if (state->border.color == color) + return; + + state->border.color = color; + state->border.damaged = true; + + /* XXX: Damage above surface for transparent surfaces? */ + + update(surface); +} + diff --git a/libswc/compositor_surface.h b/libswc/compositor_surface.h @@ -0,0 +1,69 @@ +/* swc: compositor_surface.h + * + * Copyright (c) 2013 Michael Forney + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef SWC_COMPOSITOR_SURFACE_H +#define SWC_COMPOSITOR_SURFACE_H 1 + +#include "surface.h" + +#include <wayland-server.h> +#include <pixman.h> + +struct swc_compositor_surface_state +{ + struct swc_compositor * compositor; + + /* The box that the surface covers (including it's border). */ + pixman_box32_t extents; + + /* The region that is covered by opaque regions of surfaces above this + * surface. */ + pixman_region32_t clip; + + struct + { + uint32_t width; + uint32_t color; + bool damaged; + } border; + + bool mapped; + + struct wl_listener event_listener; +}; + +extern const struct swc_surface_class_interface + swc_compositor_class_implementation; + +void swc_compositor_surface_show(struct swc_surface * surface); + +void swc_compositor_surface_hide(struct swc_surface * surface); + +void swc_compositor_surface_set_border_width(struct swc_surface * surface, + uint32_t width); + +void swc_compositor_surface_set_border_color(struct swc_surface * surface, + uint32_t color); + +#endif + diff --git a/libswc/output.h b/libswc/output.h @@ -9,6 +9,8 @@ #include <wayland-server.h> #include <xf86drmMode.h> +#define SWC_OUTPUT_MASK(output) (1 << (output)->id) + struct swc_output { /* Outputs need IDs so surfaces can keep track of which output they are diff --git a/libswc/renderer.c b/libswc/renderer.c @@ -1,4 +1,6 @@ #include "renderer.h" +#include "compositor_surface.h" +#include "util.h" #include <stdio.h> #include <GLES2/gl2.h> @@ -8,6 +10,23 @@ #include <intelbatch/mi.h> #include <xf86drm.h> +struct buffer_state +{ + union + { + struct + { + pixman_image_t * image; + } shm; + struct + { + drm_intel_bo * bo; + uint32_t width, height, pitch; + } drm; + }; + struct wl_listener destroy_listener; +}; + static inline uint32_t format_wayland_to_pixman(uint32_t wayland_format) { switch (wayland_format) @@ -55,15 +74,37 @@ static inline void switch_context(struct swc_renderer * renderer, } } +static void handle_buffer_destroy(struct wl_listener * listener, void * data) +{ + struct buffer_state * state + = swc_container_of(listener, typeof(*state), destroy_listener); + + free(state); +} + +static inline struct buffer_state * buffer_state(struct wl_resource * resource) +{ + struct wl_listener * listener + = wl_resource_get_destroy_listener(resource, &handle_buffer_destroy); + + return listener ? swc_container_of(listener, struct buffer_state, + destroy_listener) + : NULL; +} + static void repaint_surface_for_output(struct swc_renderer * renderer, struct swc_surface * surface, struct swc_output * output) { struct swc_buffer * back_buffer = swc_output_get_back_buffer(output); + struct buffer_state * state; + struct swc_compositor_surface_state * surface_state = surface->class_state; if (!surface->state.buffer) return; + state = buffer_state(&surface->state.buffer->resource); + if (wl_buffer_is_shm(surface->state.buffer)) { pixman_image_t * buffer_image; @@ -77,7 +118,7 @@ static void repaint_surface_for_output(struct swc_renderer * renderer, back_buffer->bo->virtual, back_buffer->pitch); pixman_image_composite32(PIXMAN_OP_SRC, - surface->renderer_state.shm.image, NULL, + state->shm.image, NULL, buffer_image, 0, 0, 0, 0, 0, 0, surface->geometry.width, surface->geometry.height); @@ -88,13 +129,13 @@ static void repaint_surface_for_output(struct swc_renderer * renderer, printf("repainting drm surface\n"); - drm_intel_bo * src = surface->renderer_state.drm.bo; - uint32_t src_pitch = surface->renderer_state.drm.pitch; + drm_intel_bo * src = state->drm.bo; + uint32_t src_pitch = state->drm.pitch; xy_src_copy_blt(&renderer->batch, src, src_pitch, 0, 0, back_buffer->bo, back_buffer->pitch, - surface->geometry.x + surface->border.width, - surface->geometry.y + surface->border.width, + surface->geometry.x + surface_state->border.width, + surface->geometry.y + surface_state->border.width, surface->geometry.width, surface->geometry.height); } @@ -105,29 +146,29 @@ static void repaint_surface_for_output(struct swc_renderer * renderer, /* Top */ xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch, surface->geometry.x, surface->geometry.y, - surface->geometry.x + surface->geometry.width + 2 * surface->border.width, - surface->geometry.y + surface->border.width, - surface->border.color); + surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width, + surface->geometry.y + surface_state->border.width, + surface_state->border.color); /* Bottom */ xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch, surface->geometry.x, - surface->geometry.y + surface->border.width + surface->geometry.height, - surface->geometry.x + surface->geometry.width + 2 * surface->border.width, - surface->geometry.y + surface->geometry.height + 2 * surface->border.width, - surface->border.color); + surface->geometry.y + surface_state->border.width + surface->geometry.height, + surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width, + surface->geometry.y + surface->geometry.height + 2 * surface_state->border.width, + surface_state->border.color); /* Left */ xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch, - surface->geometry.x, surface->geometry.y + surface->border.width, - surface->geometry.x + surface->border.width, - surface->geometry.y + + surface->border.width + surface->geometry.height, - surface->border.color); + surface->geometry.x, surface->geometry.y + surface_state->border.width, + surface->geometry.x + surface_state->border.width, + surface->geometry.y + + surface_state->border.width + surface->geometry.height, + surface_state->border.color); /* Right */ xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch, - surface->geometry.x + surface->border.width + surface->geometry.width, - surface->geometry.y + surface->border.width, - surface->geometry.x + surface->geometry.width + 2 * surface->border.width, - surface->geometry.y + surface->border.width + surface->geometry.height, - surface->border.color); + surface->geometry.x + surface_state->border.width + surface->geometry.width, + surface->geometry.y + surface_state->border.width, + surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width, + surface->geometry.y + surface_state->border.width + surface->geometry.height, + surface_state->border.color); } } @@ -162,10 +203,8 @@ void swc_renderer_repaint_output(struct swc_renderer * renderer, wl_list_for_each(surface, surfaces, link) { - if (surface->output_mask & (1 << output->id)) - { + if (surface->outputs & (1 << output->id)) repaint_surface_for_output(renderer, surface, output); - } } switch_context(renderer, SWC_RENDERER_CONTEXT_NONE, back_buffer); @@ -175,18 +214,26 @@ void swc_renderer_attach(struct swc_renderer * renderer, struct swc_surface * surface, struct wl_buffer * buffer) { + struct buffer_state * state; struct gbm_bo * bo; if (!buffer) return; + /* Check if we have already seen this buffer. */ + if ((state = buffer_state(&buffer->resource))) + return; + + if (!(state = malloc(sizeof *state))) + return; + /* SHM buffer */ if (wl_buffer_is_shm(buffer)) { struct swc_output * output; uint32_t wayland_format = wl_shm_buffer_get_format(buffer); - surface->renderer_state.shm.image + state->shm.image = pixman_image_create_bits(format_wayland_to_pixman(wayland_format), wl_shm_buffer_get_width(buffer), wl_shm_buffer_get_height(buffer), @@ -206,15 +253,15 @@ void swc_renderer_attach(struct swc_renderer * renderer, return; } - surface->renderer_state.drm.bo + state->drm.bo = drm_intel_bo_gem_create_from_name(renderer->drm->bufmgr, "surface", flink.name); - surface->renderer_state.drm.pitch = gbm_bo_get_stride(bo); - surface->renderer_state.drm.width = gbm_bo_get_width(bo); - surface->renderer_state.drm.height = gbm_bo_get_height(bo); + state->drm.pitch = gbm_bo_get_stride(bo); + state->drm.width = gbm_bo_get_width(bo); + state->drm.height = gbm_bo_get_height(bo); - printf("pitch: %u, width: %u, height: %u\n", surface->renderer_state.drm.pitch, - surface->renderer_state.drm.width, surface->renderer_state.drm.height); + printf("pitch: %u, width: %u, height: %u\n", state->drm.pitch, + state->drm.width, state->drm.height); } } diff --git a/libswc/surface.c b/libswc/surface.c @@ -1,3 +1,26 @@ +/* swc: surface.c + * + * Copyright (c) 2013 Michael Forney + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #include "surface.h" #include "event.h" #include "region.h" @@ -184,8 +207,8 @@ static void commit(struct wl_client * client, struct wl_resource * resource) state_set_buffer(&surface->state, surface->pending.state.buffer); - event.type = SWC_SURFACE_ATTACH; - wl_signal_emit(&surface->event_signal, &event); + surface->class->interface->attach(surface, + &surface->state.buffer->resource); } /* Damage */ @@ -221,8 +244,7 @@ static void commit(struct wl_client * client, struct wl_resource * resource) surface->pending.state.buffer = surface->state.buffer; wl_list_init(&surface->pending.state.frame_callbacks); - event.type = SWC_SURFACE_REPAINT; - wl_signal_emit(&surface->event_signal, &event); + surface->class->interface->update(surface); } void set_buffer_transform(struct wl_client * client, @@ -256,6 +278,9 @@ static void surface_destroy(struct wl_resource * resource) if (surface->shell_destructor) surface->shell_destructor(surface); + if (surface->class && surface->class->interface->remove) + surface->class->interface->remove(surface); + /* Finish the surface. */ state_finish(&surface->state); state_finish(&surface->pending.state); @@ -281,15 +306,15 @@ struct swc_surface * swc_surface_new(struct wl_client * client, uint32_t id) return NULL; /* Initialize the surface. */ - surface->output_mask = 0; + surface->outputs = 0; surface->geometry.x = 0; surface->geometry.y = 0; surface->geometry.width = 0; surface->geometry.height = 0; - surface->border.width = 0; - surface->border.color = 0x000000; surface->shell_data = NULL; surface->shell_destructor = NULL; + surface->class = NULL; + surface->class_state = NULL; state_initialize(&surface->state); state_initialize(&surface->pending.state); @@ -323,3 +348,41 @@ void swc_surface_send_frame_callbacks(struct swc_surface * surface, wl_list_init(&surface->state.frame_callbacks); } +void swc_surface_set_class(struct swc_surface * surface, + const struct swc_surface_class * class) +{ + if (surface->class == class) + return; + + if (surface->class && surface->class->interface->remove) + surface->class->interface->remove(surface); + + surface->class = class; + + if (surface->class) + { + if (surface->class->interface->add + && !surface->class->interface->add(surface)) + { + surface->class = NULL; + return; + } + + + surface->class->interface->attach(surface, &surface->state.buffer->resource); + surface->class->interface->update(surface); + } +} + +void swc_surface_update(struct swc_surface * surface) +{ + if (surface->class) + surface->class->interface->update(surface); +} + +void swc_surface_move(struct swc_surface * surface, int32_t x, int32_t y) +{ + if (surface->class) + surface->class->interface->move(surface, x, y); +} + diff --git a/libswc/surface.h b/libswc/surface.h @@ -1,17 +1,34 @@ +/* swc: surface.h + * + * Copyright (c) 2013 Michael Forney + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #ifndef SWC_SURFACE_H #define SWC_SURFACE_H 1 -#include "surface_state.h" - #include <stdbool.h> #include <wayland-server.h> #include <pixman.h> -enum swc_surface_event -{ - SWC_SURFACE_ATTACH, - SWC_SURFACE_REPAINT -}; +struct swc_surface; struct swc_surface_state { @@ -30,15 +47,41 @@ struct swc_surface_state struct wl_listener buffer_destroy_listener; }; +/** + * A surface class is a set of operations that can be performed on a surface. + * This gives the compositor the ability to classify surfaces, treating some + * specially (for example, a cursor surface). + */ +struct swc_surface_class_interface +{ + /* Called when a surface is added to the class. */ + bool (* add)(struct swc_surface * surface); + + /* Called when a surface is removed from the class. */ + void (* remove)(struct swc_surface * surface); + + /* Called when a new buffer is attached to a surface. */ + void (* attach)(struct swc_surface * surface, + struct wl_resource * resource); + + /* Called after a surface requests a commit. */ + void (* update)(struct swc_surface * surface); + + /* Moves the surface to the specified coordinates. */ + void (* move)(struct swc_surface * surface, int32_t x, int32_t y); +}; + +struct swc_surface_class +{ + const struct swc_surface_class_interface * interface; +}; + struct swc_surface { struct wl_resource * resource; struct swc_surface_state state; - union swc_renderer_surface_state renderer_state; - struct swc_compositor_surface_state compositor_state; - /* For usage by a shell implementation. */ void * shell_data; @@ -54,15 +97,11 @@ struct swc_surface int32_t x, y; } pending; - pixman_rectangle32_t geometry; + const struct swc_surface_class * class; + void * class_state; - struct - { - uint32_t width; - uint32_t color; - } border; - - uint32_t output_mask; + uint32_t outputs; + pixman_rectangle32_t geometry; struct wl_signal event_signal; struct wl_list link; @@ -72,6 +111,12 @@ struct swc_surface * swc_surface_new(struct wl_client * client, uint32_t id); void swc_surface_send_frame_callbacks(struct swc_surface * surface, uint32_t time); +void swc_surface_set_class(struct swc_surface * surface, + const struct swc_surface_class * class); + +void swc_surface_update(struct swc_surface * surface); + +void swc_surface_move(struct swc_surface * surface, int32_t x, int32_t y); #endif diff --git a/libswc/surface_state.h b/libswc/surface_state.h @@ -1,30 +0,0 @@ -#ifndef SWC_SURFACE_STATE_H -#define SWC_SURFACE_STATE_H 1 - -#include <libdrm/intel_bufmgr.h> - -#include <wayland-server.h> -#include <pixman.h> - -union swc_renderer_surface_state -{ - struct - { - pixman_image_t * image; - } shm; - struct - { - drm_intel_bo * bo; - uint32_t width, height, pitch; - } drm; -}; - -struct swc_compositor_surface_state -{ - struct swc_compositor * compositor; - struct wl_listener destroy_listener; - struct wl_listener event_listener; -}; - -#endif - diff --git a/libswc/util.h b/libswc/util.h @@ -2,7 +2,9 @@ #define SWC_UTIL_H 1 #include <stdbool.h> +#include <sys/param.h> #include <wayland-server.h> +#include <pixman.h> #ifndef offsetof # define offsetof __builtin_offsetof @@ -15,6 +17,15 @@ void swc_remove_resource(struct wl_resource * resource); +static inline bool swc_rectangle_overlap + (pixman_rectangle32_t * r1, pixman_rectangle32_t * r2) +{ + return (MAX(r1->x + r1->width, r2->x + r2->width) - MIN(r1->x, r2->x) + < r1->width + r2->width) + && (MAX(r1->y + r1->height, r2->y + r2->height) - MIN(r1->y, r2->y) + < r1->height + r2->height); +} + int swc_launch_open_input_device(int socket, const char * path, int flags); bool swc_launch_drm_master(int socket, int fd, bool set);