commit 9c6a405461cd4dc0d5620a0711283c18facf08c2
parent d0a9e34c63062fc8426ff450b417310dffbe6e56
Author: Michael Forney <mforney@mforney.org>
Date: Wed, 11 Sep 2013 00:34:53 -0700
Introduce surface classes
Diffstat:
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);