commit 9c6a405

Michael Forney  ·  2013-09-11 07:34:53 +0000 UTC
parent d0a9e34
Introduce surface classes
11 files changed,  +642, -136
+1, -0
1@@ -11,6 +11,7 @@ libswc_la_SOURCES = \
2     output.c output.h \
3     buffer.c buffer.h \
4     surface.c surface.h \
5+    compositor_surface.c compositor_surface.h \
6     region.c region.h \
7     renderer.c renderer.h \
8     input_focus.c input_focus.h \
+7, -50
 1@@ -170,33 +170,6 @@ static void handle_tty_event(struct wl_listener * listener, void * data)
 2     }
 3 }
 4 
 5-static void handle_surface_event(struct wl_listener * listener, void * data)
 6-{
 7-    struct swc_event * event = data;
 8-    struct swc_surface * surface = event->data;
 9-    struct swc_compositor * compositor = surface->compositor_state.compositor;
10-
11-    switch (event->type)
12-    {
13-        case SWC_SURFACE_ATTACH:
14-            swc_renderer_attach(&compositor->renderer, &compositor->outputs,
15-                                surface, surface->state.buffer);
16-            break;
17-        case SWC_SURFACE_REPAINT:
18-        {
19-            struct swc_output * output;
20-
21-            wl_list_for_each(output, &compositor->outputs, link)
22-            {
23-                if (surface->output_mask & (1 << output->id))
24-                    schedule_repaint_for_output(compositor, output);
25-            }
26-
27-            break;
28-        }
29-    }
30-}
31-
32 static void handle_drm_event(struct wl_listener * listener, void * data)
33 {
34     struct swc_event * event = data;
35@@ -266,6 +239,11 @@ static void create_surface(struct wl_client * client,
36     struct swc_surface * surface;
37     struct swc_output * output;
38 
39+    printf("compositor.create_surface\n");
40+
41+    output = swc_container_of(compositor->outputs.next, typeof(*output), link);
42+
43+    /* Initialize surface. */
44     surface = swc_surface_new(client, id);
45 
46     if (!surface)
47@@ -273,29 +251,6 @@ static void create_surface(struct wl_client * client,
48         wl_resource_post_no_memory(resource);
49         return;
50     }
51-
52-    printf("compositor_create_surface: %p\n", surface);
53-
54-    output = swc_container_of(compositor->outputs.next, typeof(*output), link);
55-
56-    /* Initialize compositor state */
57-    surface->compositor_state = (struct swc_compositor_surface_state) {
58-        .compositor = compositor,
59-        .event_listener = {
60-            .notify = &handle_surface_event
61-        },
62-        .destroy_listener = {
63-            .notify = &handle_surface_destroy
64-        }
65-    };
66-
67-    wl_signal_add(&surface->event_signal,
68-                  &surface->compositor_state.event_listener);
69-    wl_resource_add_destroy_listener(surface->resource,
70-                  &surface->compositor_state.destroy_listener);
71-
72-    wl_list_insert(compositor->surfaces.prev, &surface->link);
73-    surface->output_mask |= 1 << output->id;
74 }
75 
76 static void create_region(struct wl_client * client,
77@@ -340,6 +295,8 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
78     compositor->display = display;
79     compositor->tty_listener.notify = &handle_tty_event;
80     compositor->drm_listener.notify = &handle_drm_event;
81+    compositor->compositor_class.interface
82+        = &swc_compositor_class_implementation;
83 
84     compositor->udev = udev_new();
85 
+20, -0
 1@@ -27,6 +27,23 @@ struct swc_compositor
 2     struct wl_list surfaces;
 3     struct wl_array key_bindings;
 4 
 5+    /* Internal state related to repainting the screen. */
 6+    struct
 7+    {
 8+        pixman_region32_t damage;
 9+        pixman_region32_t opaque;
10+
11+        /* A mask of outputs that have been repainted but are waiting on a page
12+         * flip. */
13+        uint32_t pending_flips;
14+
15+        /* A mask of outputs that are scheduled to be repainted on the next
16+         * idle. */
17+        uint32_t scheduled_updates;
18+    };
19+
20+    struct swc_surface_class compositor_class;
21+
22     struct wl_listener tty_listener;
23     struct wl_listener drm_listener;
24 
25@@ -45,5 +62,8 @@ void swc_compositor_add_key_binding(struct swc_compositor * compositor,
26                                     uint32_t modifiers, xkb_keysym_t key,
27                                     swc_binding_handler_t handler, void * data);
28 
29+void swc_compositor_schedule_update(struct swc_compositor * compositor,
30+                                    struct swc_output * output);
31+
32 #endif
33 
+321, -0
  1@@ -0,0 +1,321 @@
  2+/* swc: compositor_surface.c
  3+ *
  4+ * Copyright (c) 2013 Michael Forney
  5+ *
  6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
  7+ * of this software and associated documentation files (the "Software"), to deal
  8+ * in the Software without restriction, including without limitation the rights
  9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10+ * copies of the Software, and to permit persons to whom the Software is
 11+ * furnished to do so, subject to the following conditions:
 12+ *
 13+ * The above copyright notice and this permission notice shall be included in
 14+ * all copies or substantial portions of the Software.
 15+ *
 16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 22+ * SOFTWARE.
 23+ */
 24+
 25+#include "compositor_surface.h"
 26+#include "compositor.h"
 27+#include "util.h"
 28+
 29+#include <stdio.h>
 30+#include <stdlib.h>
 31+
 32+static bool add(struct swc_surface * surface);
 33+static void remove_(struct swc_surface * surface);
 34+static void attach(struct swc_surface * surface, struct wl_resource * resource);
 35+static void update(struct swc_surface * surface);
 36+static void move(struct swc_surface * surface, int32_t x, int32_t y);
 37+
 38+const struct swc_surface_class_interface swc_compositor_class_implementation = {
 39+    .add = &add,
 40+    .remove = &remove_,
 41+    .attach = &attach,
 42+    .update = &update,
 43+    .move = &move
 44+};
 45+
 46+/**
 47+ * Adds damage from the region below a surface, taking into account it's clip
 48+ * region, to the region specified by `damage'.
 49+ */
 50+static void damage_below_surface(struct swc_surface * surface)
 51+{
 52+    struct swc_compositor * compositor = swc_container_of
 53+        (surface->class, typeof(*compositor), compositor_class);
 54+    struct swc_compositor_surface_state * state = surface->class_state;
 55+    pixman_region32_t damage_below;
 56+
 57+    pixman_region32_init_with_extents(&damage_below, &state->extents);
 58+    pixman_region32_subtract(&damage_below, &damage_below, &state->clip);
 59+    pixman_region32_union(&compositor->damage, &compositor->damage,
 60+                          &damage_below);
 61+    pixman_region32_fini(&damage_below);
 62+}
 63+
 64+/**
 65+ * Completely damages the surface and its border.
 66+ */
 67+static void damage_surface(struct swc_surface * surface)
 68+{
 69+    struct swc_compositor_surface_state * state = surface->class_state;
 70+    printf("damaging surface\n");
 71+
 72+    pixman_region32_fini(&surface->state.damage);
 73+    pixman_region32_init_rect(&surface->state.damage, 0, 0,
 74+                              surface->geometry.width,
 75+                              surface->geometry.height);
 76+    state->border.damaged = true;
 77+}
 78+
 79+static void update_extents(struct swc_surface * surface)
 80+{
 81+    struct swc_compositor_surface_state * state = surface->class_state;
 82+
 83+    state->extents.x1 = surface->geometry.x - state->border.width;
 84+    state->extents.y1 = surface->geometry.y - state->border.width;
 85+    state->extents.x2 = surface->geometry.x + surface->geometry.width
 86+        + state->border.width;
 87+    state->extents.y2 = surface->geometry.y + surface->geometry.height
 88+        + state->border.width;
 89+
 90+    /* Damage border. */
 91+    state->border.damaged = true;
 92+}
 93+
 94+static void update_outputs(struct swc_surface * surface)
 95+{
 96+    struct swc_compositor * compositor = swc_container_of
 97+        (surface->class, typeof(*compositor), compositor_class);
 98+    struct swc_compositor_surface_state * state = surface->class_state;
 99+    uint32_t old_outputs = surface->outputs, new_outputs = 0,
100+             entered_outputs, left_outputs, changed_outputs;
101+    struct swc_output * output;
102+    struct wl_client * client;
103+    struct wl_resource * resource;
104+
105+    if (state->mapped)
106+    {
107+        wl_list_for_each(output, &compositor->outputs, link)
108+        {
109+            if (swc_rectangle_overlap(&output->geometry, &surface->geometry))
110+                new_outputs |= SWC_OUTPUT_MASK(output);
111+        }
112+    }
113+
114+    if (new_outputs == old_outputs)
115+        return;
116+
117+    entered_outputs = new_outputs & ~old_outputs;
118+    left_outputs = old_outputs & ~new_outputs;
119+    changed_outputs = old_outputs ^ new_outputs;
120+
121+    wl_list_for_each(output, &compositor->outputs, link)
122+    {
123+        if (!(changed_outputs & SWC_OUTPUT_MASK(output)))
124+            continue;
125+
126+        client = wl_resource_get_client(surface->resource);
127+        resource = wl_resource_find_for_client(&output->resources, client);
128+
129+        if (resource)
130+        {
131+            if (entered_outputs & SWC_OUTPUT_MASK(output))
132+                wl_surface_send_enter(surface->resource, resource);
133+            else if (left_outputs & SWC_OUTPUT_MASK(output))
134+                wl_surface_send_leave(surface->resource, resource);
135+        }
136+    }
137+
138+    surface->outputs = new_outputs;
139+}
140+
141+/* Compositor class */
142+bool add(struct swc_surface * surface)
143+{
144+    struct swc_compositor * compositor = swc_container_of
145+        (surface->class, typeof(*compositor), compositor_class);
146+    struct swc_compositor_surface_state * state;
147+
148+    state = malloc(sizeof *state);
149+
150+    if (!state)
151+        return false;
152+
153+    state->compositor = compositor;
154+    state->extents.x1 = surface->geometry.x;
155+    state->extents.y1 = surface->geometry.y;
156+    state->extents.x2 = surface->geometry.x + surface->geometry.width;
157+    state->extents.y2 = surface->geometry.y + surface->geometry.height;
158+    state->border.width = 0;
159+    state->border.color = 0x000000;
160+    state->border.damaged = false;
161+    state->mapped = false;
162+
163+    wl_signal_add(&surface->event_signal, &state->event_listener);
164+
165+    pixman_region32_init(&state->clip);
166+
167+    surface->class_state = state;
168+
169+    return true;
170+}
171+
172+void remove_(struct swc_surface * surface)
173+{
174+    struct swc_compositor * compositor = swc_container_of
175+        (surface->class, typeof(*compositor), compositor_class);
176+    struct swc_compositor_surface_state * state = surface->class_state;
177+
178+    swc_compositor_surface_hide(surface);
179+
180+    wl_list_remove(&state->event_listener.link);
181+    pixman_region32_fini(&state->clip);
182+
183+    free(state);
184+}
185+
186+void attach(struct swc_surface * surface, struct wl_resource * resource)
187+{
188+    struct swc_compositor * compositor = swc_container_of
189+        (surface->class, typeof(*compositor), compositor_class);
190+
191+    swc_renderer_attach(&compositor->renderer, surface,
192+                        wl_resource_get_user_data(resource));
193+}
194+
195+void update(struct swc_surface * surface)
196+{
197+    struct swc_compositor * compositor = swc_container_of
198+        (surface->class, typeof(*compositor), compositor_class);
199+    struct swc_compositor_surface_state * state = surface->class_state;
200+    struct swc_output * output;
201+
202+    if (!state->mapped)
203+        return;
204+
205+    wl_list_for_each(output, &compositor->outputs, link)
206+    {
207+        if (surface->outputs & SWC_OUTPUT_MASK(output))
208+            swc_compositor_schedule_update(compositor, output);
209+    }
210+}
211+
212+void move(struct swc_surface * surface, int32_t x, int32_t y)
213+{
214+    struct swc_compositor * compositor = swc_container_of
215+        (surface->class, typeof(*compositor), compositor_class);
216+    struct swc_compositor_surface_state * state = surface->class_state;
217+
218+    if (x == surface->geometry.x && y == surface->geometry.y)
219+        return;
220+
221+    if (state->mapped)
222+        damage_below_surface(surface);
223+
224+    surface->geometry.x = x;
225+    surface->geometry.y = y;
226+
227+    update_extents(surface);
228+
229+    if (state->mapped)
230+    {
231+        /* Assume worst-case no clipping until we draw the next frame (in case
232+         * the surface gets moved again before that). */
233+        pixman_region32_init(&state->clip);
234+
235+        damage_below_surface(surface);
236+        update(surface);
237+        update_outputs(surface);
238+        update(surface);
239+    }
240+}
241+
242+void swc_compositor_surface_show(struct swc_surface * surface)
243+{
244+    struct swc_compositor * compositor = swc_container_of
245+        (surface->class, typeof(*compositor), compositor_class);
246+    struct swc_compositor_surface_state * state = surface->class_state;
247+
248+    if (surface->class->interface != &swc_compositor_class_implementation)
249+        return;
250+
251+    if (state->mapped)
252+        return;
253+
254+    printf("showing surface %u\n", wl_resource_get_id(surface->resource));
255+
256+    state->mapped = true;
257+
258+    /* Assume worst-case no clipping until we draw the next frame (in case the
259+     * surface gets moved before that. */
260+    pixman_region32_clear(&state->clip);
261+
262+    damage_surface(surface);
263+    update_outputs(surface);
264+    update(surface);
265+    wl_list_insert(&compositor->surfaces, &surface->link);
266+}
267+
268+void swc_compositor_surface_hide(struct swc_surface * surface)
269+{
270+    struct swc_compositor * compositor = swc_container_of
271+        (surface->class, typeof(*compositor), compositor_class);
272+    struct swc_compositor_surface_state * state = surface->class_state;
273+
274+    if (surface->class->interface != &swc_compositor_class_implementation)
275+        return;
276+
277+    if (!state->mapped)
278+        return;
279+
280+    /* Update all the outputs the surface was on. */
281+    update(surface);
282+
283+    state->mapped = false;
284+
285+    damage_below_surface(surface);
286+    update_outputs(surface);
287+    wl_list_remove(&surface->link);
288+}
289+
290+void swc_compositor_surface_set_border_width(struct swc_surface * surface,
291+                                             uint32_t width)
292+{
293+    struct swc_compositor_surface_state * state = surface->class_state;
294+
295+    if (state->border.width == width)
296+        return;
297+
298+    state->border.width = width;
299+    state->border.damaged = true;
300+
301+    /* XXX: Damage above surface for transparent surfaces? */
302+
303+    update_extents(surface);
304+    update(surface);
305+}
306+
307+void swc_compositor_surface_set_border_color(struct swc_surface * surface,
308+                                             uint32_t color)
309+{
310+    struct swc_compositor_surface_state * state = surface->class_state;
311+
312+    if (state->border.color == color)
313+        return;
314+
315+    state->border.color = color;
316+    state->border.damaged = true;
317+
318+    /* XXX: Damage above surface for transparent surfaces? */
319+
320+    update(surface);
321+}
322+
+69, -0
 1@@ -0,0 +1,69 @@
 2+/* swc: compositor_surface.h
 3+ *
 4+ * Copyright (c) 2013 Michael Forney
 5+ *
 6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
 7+ * of this software and associated documentation files (the "Software"), to deal
 8+ * in the Software without restriction, including without limitation the rights
 9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25+#ifndef SWC_COMPOSITOR_SURFACE_H
26+#define SWC_COMPOSITOR_SURFACE_H 1
27+
28+#include "surface.h"
29+
30+#include <wayland-server.h>
31+#include <pixman.h>
32+
33+struct swc_compositor_surface_state
34+{
35+    struct swc_compositor * compositor;
36+
37+    /* The box that the surface covers (including it's border). */
38+    pixman_box32_t extents;
39+
40+    /* The region that is covered by opaque regions of surfaces above this
41+     * surface. */
42+    pixman_region32_t clip;
43+
44+    struct
45+    {
46+        uint32_t width;
47+        uint32_t color;
48+        bool damaged;
49+    } border;
50+
51+    bool mapped;
52+
53+    struct wl_listener event_listener;
54+};
55+
56+extern const struct swc_surface_class_interface
57+    swc_compositor_class_implementation;
58+
59+void swc_compositor_surface_show(struct swc_surface * surface);
60+
61+void swc_compositor_surface_hide(struct swc_surface * surface);
62+
63+void swc_compositor_surface_set_border_width(struct swc_surface * surface,
64+                                             uint32_t width);
65+
66+void swc_compositor_surface_set_border_color(struct swc_surface * surface,
67+                                             uint32_t color);
68+
69+#endif
70+
+2, -0
1@@ -9,6 +9,8 @@
2 #include <wayland-server.h>
3 #include <xf86drmMode.h>
4 
5+#define SWC_OUTPUT_MASK(output) (1 << (output)->id)
6+
7 struct swc_output
8 {
9     /* Outputs need IDs so surfaces can keep track of which output they are
+78, -31
  1@@ -1,4 +1,6 @@
  2 #include "renderer.h"
  3+#include "compositor_surface.h"
  4+#include "util.h"
  5 
  6 #include <stdio.h>
  7 #include <GLES2/gl2.h>
  8@@ -8,6 +10,23 @@
  9 #include <intelbatch/mi.h>
 10 #include <xf86drm.h>
 11 
 12+struct buffer_state
 13+{
 14+    union
 15+    {
 16+        struct
 17+        {
 18+            pixman_image_t * image;
 19+        } shm;
 20+        struct
 21+        {
 22+            drm_intel_bo * bo;
 23+            uint32_t width, height, pitch;
 24+        } drm;
 25+    };
 26+    struct wl_listener destroy_listener;
 27+};
 28+
 29 static inline uint32_t format_wayland_to_pixman(uint32_t wayland_format)
 30 {
 31     switch (wayland_format)
 32@@ -55,15 +74,37 @@ static inline void switch_context(struct swc_renderer * renderer,
 33     }
 34 }
 35 
 36+static void handle_buffer_destroy(struct wl_listener * listener, void * data)
 37+{
 38+    struct buffer_state * state
 39+        = swc_container_of(listener, typeof(*state), destroy_listener);
 40+
 41+    free(state);
 42+}
 43+
 44+static inline struct buffer_state * buffer_state(struct wl_resource * resource)
 45+{
 46+    struct wl_listener * listener
 47+        = wl_resource_get_destroy_listener(resource, &handle_buffer_destroy);
 48+
 49+    return listener ? swc_container_of(listener, struct buffer_state,
 50+                                       destroy_listener)
 51+                    : NULL;
 52+}
 53+
 54 static void repaint_surface_for_output(struct swc_renderer * renderer,
 55                                        struct swc_surface * surface,
 56                                        struct swc_output * output)
 57 {
 58     struct swc_buffer * back_buffer = swc_output_get_back_buffer(output);
 59+    struct buffer_state * state;
 60+    struct swc_compositor_surface_state * surface_state = surface->class_state;
 61 
 62     if (!surface->state.buffer)
 63         return;
 64 
 65+    state = buffer_state(&surface->state.buffer->resource);
 66+
 67     if (wl_buffer_is_shm(surface->state.buffer))
 68     {
 69         pixman_image_t * buffer_image;
 70@@ -77,7 +118,7 @@ static void repaint_surface_for_output(struct swc_renderer * renderer,
 71              back_buffer->bo->virtual, back_buffer->pitch);
 72 
 73         pixman_image_composite32(PIXMAN_OP_SRC,
 74-                                 surface->renderer_state.shm.image, NULL,
 75+                                 state->shm.image, NULL,
 76                                  buffer_image, 0, 0, 0, 0, 0, 0,
 77                                  surface->geometry.width,
 78                                  surface->geometry.height);
 79@@ -88,13 +129,13 @@ static void repaint_surface_for_output(struct swc_renderer * renderer,
 80 
 81         printf("repainting drm surface\n");
 82 
 83-        drm_intel_bo * src = surface->renderer_state.drm.bo;
 84-        uint32_t src_pitch = surface->renderer_state.drm.pitch;
 85+        drm_intel_bo * src = state->drm.bo;
 86+        uint32_t src_pitch = state->drm.pitch;
 87 
 88         xy_src_copy_blt(&renderer->batch, src, src_pitch, 0, 0,
 89                         back_buffer->bo, back_buffer->pitch,
 90-                        surface->geometry.x + surface->border.width,
 91-                        surface->geometry.y + surface->border.width,
 92+                        surface->geometry.x + surface_state->border.width,
 93+                        surface->geometry.y + surface_state->border.width,
 94                         surface->geometry.width, surface->geometry.height);
 95     }
 96 
 97@@ -105,29 +146,29 @@ static void repaint_surface_for_output(struct swc_renderer * renderer,
 98         /* Top */
 99         xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
100                      surface->geometry.x, surface->geometry.y,
101-                     surface->geometry.x + surface->geometry.width + 2 * surface->border.width,
102-                     surface->geometry.y + surface->border.width,
103-                     surface->border.color);
104+                     surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width,
105+                     surface->geometry.y + surface_state->border.width,
106+                     surface_state->border.color);
107         /* Bottom */
108         xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
109                      surface->geometry.x,
110-                     surface->geometry.y + surface->border.width + surface->geometry.height,
111-                     surface->geometry.x + surface->geometry.width + 2 * surface->border.width,
112-                     surface->geometry.y + surface->geometry.height + 2 * surface->border.width,
113-                     surface->border.color);
114+                     surface->geometry.y + surface_state->border.width + surface->geometry.height,
115+                     surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width,
116+                     surface->geometry.y + surface->geometry.height + 2 * surface_state->border.width,
117+                     surface_state->border.color);
118         /* Left */
119         xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
120-                     surface->geometry.x, surface->geometry.y + surface->border.width,
121-                     surface->geometry.x + surface->border.width,
122-                     surface->geometry.y + + surface->border.width + surface->geometry.height,
123-                     surface->border.color);
124+                     surface->geometry.x, surface->geometry.y + surface_state->border.width,
125+                     surface->geometry.x + surface_state->border.width,
126+                     surface->geometry.y + + surface_state->border.width + surface->geometry.height,
127+                     surface_state->border.color);
128         /* Right */
129         xy_color_blt(&renderer->batch, back_buffer->bo, back_buffer->pitch,
130-                     surface->geometry.x + surface->border.width + surface->geometry.width,
131-                     surface->geometry.y + surface->border.width,
132-                     surface->geometry.x + surface->geometry.width + 2 * surface->border.width,
133-                     surface->geometry.y + surface->border.width + surface->geometry.height,
134-                     surface->border.color);
135+                     surface->geometry.x + surface_state->border.width + surface->geometry.width,
136+                     surface->geometry.y + surface_state->border.width,
137+                     surface->geometry.x + surface->geometry.width + 2 * surface_state->border.width,
138+                     surface->geometry.y + surface_state->border.width + surface->geometry.height,
139+                     surface_state->border.color);
140 
141     }
142 }
143@@ -162,10 +203,8 @@ void swc_renderer_repaint_output(struct swc_renderer * renderer,
144 
145     wl_list_for_each(surface, surfaces, link)
146     {
147-        if (surface->output_mask & (1 << output->id))
148-        {
149+        if (surface->outputs & (1 << output->id))
150             repaint_surface_for_output(renderer, surface, output);
151-        }
152     }
153 
154     switch_context(renderer, SWC_RENDERER_CONTEXT_NONE, back_buffer);
155@@ -175,18 +214,26 @@ void swc_renderer_attach(struct swc_renderer * renderer,
156                          struct swc_surface * surface,
157                          struct wl_buffer * buffer)
158 {
159+    struct buffer_state * state;
160     struct gbm_bo * bo;
161 
162     if (!buffer)
163         return;
164 
165+    /* Check if we have already seen this buffer. */
166+    if ((state = buffer_state(&buffer->resource)))
167+        return;
168+
169+    if (!(state = malloc(sizeof *state)))
170+        return;
171+
172     /* SHM buffer */
173     if (wl_buffer_is_shm(buffer))
174     {
175         struct swc_output * output;
176         uint32_t wayland_format = wl_shm_buffer_get_format(buffer);
177 
178-        surface->renderer_state.shm.image
179+        state->shm.image
180             = pixman_image_create_bits(format_wayland_to_pixman(wayland_format),
181                                        wl_shm_buffer_get_width(buffer),
182                                        wl_shm_buffer_get_height(buffer),
183@@ -206,15 +253,15 @@ void swc_renderer_attach(struct swc_renderer * renderer,
184             return;
185         }
186 
187-        surface->renderer_state.drm.bo
188+        state->drm.bo
189             = drm_intel_bo_gem_create_from_name(renderer->drm->bufmgr,
190                                                 "surface", flink.name);
191-        surface->renderer_state.drm.pitch = gbm_bo_get_stride(bo);
192-        surface->renderer_state.drm.width = gbm_bo_get_width(bo);
193-        surface->renderer_state.drm.height = gbm_bo_get_height(bo);
194+        state->drm.pitch = gbm_bo_get_stride(bo);
195+        state->drm.width = gbm_bo_get_width(bo);
196+        state->drm.height = gbm_bo_get_height(bo);
197 
198-        printf("pitch: %u, width: %u, height: %u\n", surface->renderer_state.drm.pitch,
199-            surface->renderer_state.drm.width, surface->renderer_state.drm.height);
200+        printf("pitch: %u, width: %u, height: %u\n", state->drm.pitch,
201+            state->drm.width, state->drm.height);
202     }
203 }
204 
+70, -7
  1@@ -1,3 +1,26 @@
  2+/* swc: surface.c
  3+ *
  4+ * Copyright (c) 2013 Michael Forney
  5+ *
  6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
  7+ * of this software and associated documentation files (the "Software"), to deal
  8+ * in the Software without restriction, including without limitation the rights
  9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10+ * copies of the Software, and to permit persons to whom the Software is
 11+ * furnished to do so, subject to the following conditions:
 12+ *
 13+ * The above copyright notice and this permission notice shall be included in
 14+ * all copies or substantial portions of the Software.
 15+ *
 16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 22+ * SOFTWARE.
 23+ */
 24+
 25 #include "surface.h"
 26 #include "event.h"
 27 #include "region.h"
 28@@ -184,8 +207,8 @@ static void commit(struct wl_client * client, struct wl_resource * resource)
 29 
 30         state_set_buffer(&surface->state, surface->pending.state.buffer);
 31 
 32-        event.type = SWC_SURFACE_ATTACH;
 33-        wl_signal_emit(&surface->event_signal, &event);
 34+        surface->class->interface->attach(surface,
 35+                                          &surface->state.buffer->resource);
 36     }
 37 
 38     /* Damage */
 39@@ -221,8 +244,7 @@ static void commit(struct wl_client * client, struct wl_resource * resource)
 40     surface->pending.state.buffer = surface->state.buffer;
 41     wl_list_init(&surface->pending.state.frame_callbacks);
 42 
 43-    event.type = SWC_SURFACE_REPAINT;
 44-    wl_signal_emit(&surface->event_signal, &event);
 45+    surface->class->interface->update(surface);
 46 }
 47 
 48 void set_buffer_transform(struct wl_client * client,
 49@@ -256,6 +278,9 @@ static void surface_destroy(struct wl_resource * resource)
 50     if (surface->shell_destructor)
 51         surface->shell_destructor(surface);
 52 
 53+    if (surface->class && surface->class->interface->remove)
 54+        surface->class->interface->remove(surface);
 55+
 56     /* Finish the surface. */
 57     state_finish(&surface->state);
 58     state_finish(&surface->pending.state);
 59@@ -281,15 +306,15 @@ struct swc_surface * swc_surface_new(struct wl_client * client, uint32_t id)
 60         return NULL;
 61 
 62     /* Initialize the surface. */
 63-    surface->output_mask = 0;
 64+    surface->outputs = 0;
 65     surface->geometry.x = 0;
 66     surface->geometry.y = 0;
 67     surface->geometry.width = 0;
 68     surface->geometry.height = 0;
 69-    surface->border.width = 0;
 70-    surface->border.color = 0x000000;
 71     surface->shell_data = NULL;
 72     surface->shell_destructor = NULL;
 73+    surface->class = NULL;
 74+    surface->class_state = NULL;
 75 
 76     state_initialize(&surface->state);
 77     state_initialize(&surface->pending.state);
 78@@ -323,3 +348,41 @@ void swc_surface_send_frame_callbacks(struct swc_surface * surface,
 79     wl_list_init(&surface->state.frame_callbacks);
 80 }
 81 
 82+void swc_surface_set_class(struct swc_surface * surface,
 83+                           const struct swc_surface_class * class)
 84+{
 85+    if (surface->class == class)
 86+        return;
 87+
 88+    if (surface->class && surface->class->interface->remove)
 89+        surface->class->interface->remove(surface);
 90+
 91+    surface->class = class;
 92+
 93+    if (surface->class)
 94+    {
 95+        if (surface->class->interface->add
 96+            && !surface->class->interface->add(surface))
 97+        {
 98+            surface->class = NULL;
 99+            return;
100+        }
101+
102+
103+        surface->class->interface->attach(surface, &surface->state.buffer->resource);
104+        surface->class->interface->update(surface);
105+    }
106+}
107+
108+void swc_surface_update(struct swc_surface * surface)
109+{
110+    if (surface->class)
111+        surface->class->interface->update(surface);
112+}
113+
114+void swc_surface_move(struct swc_surface * surface, int32_t x, int32_t y)
115+{
116+    if (surface->class)
117+        surface->class->interface->move(surface, x, y);
118+}
119+
+63, -18
  1@@ -1,17 +1,34 @@
  2+/* swc: surface.h
  3+ *
  4+ * Copyright (c) 2013 Michael Forney
  5+ *
  6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
  7+ * of this software and associated documentation files (the "Software"), to deal
  8+ * in the Software without restriction, including without limitation the rights
  9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10+ * copies of the Software, and to permit persons to whom the Software is
 11+ * furnished to do so, subject to the following conditions:
 12+ *
 13+ * The above copyright notice and this permission notice shall be included in
 14+ * all copies or substantial portions of the Software.
 15+ *
 16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 22+ * SOFTWARE.
 23+ */
 24+
 25 #ifndef SWC_SURFACE_H
 26 #define SWC_SURFACE_H 1
 27 
 28-#include "surface_state.h"
 29-
 30 #include <stdbool.h>
 31 #include <wayland-server.h>
 32 #include <pixman.h>
 33 
 34-enum swc_surface_event
 35-{
 36-    SWC_SURFACE_ATTACH,
 37-    SWC_SURFACE_REPAINT
 38-};
 39+struct swc_surface;
 40 
 41 struct swc_surface_state
 42 {
 43@@ -30,15 +47,41 @@ struct swc_surface_state
 44     struct wl_listener buffer_destroy_listener;
 45 };
 46 
 47+/**
 48+ * A surface class is a set of operations that can be performed on a surface.
 49+ * This gives the compositor the ability to classify surfaces, treating some
 50+ * specially (for example, a cursor surface).
 51+ */
 52+struct swc_surface_class_interface
 53+{
 54+    /* Called when a surface is added to the class. */
 55+    bool (* add)(struct swc_surface * surface);
 56+
 57+    /* Called when a surface is removed from the class. */
 58+    void (* remove)(struct swc_surface * surface);
 59+
 60+    /* Called when a new buffer is attached to a surface. */
 61+    void (* attach)(struct swc_surface * surface,
 62+                    struct wl_resource * resource);
 63+
 64+    /* Called after a surface requests a commit. */
 65+    void (* update)(struct swc_surface * surface);
 66+
 67+    /* Moves the surface to the specified coordinates. */
 68+    void (* move)(struct swc_surface * surface, int32_t x, int32_t y);
 69+};
 70+
 71+struct swc_surface_class
 72+{
 73+    const struct swc_surface_class_interface * interface;
 74+};
 75+
 76 struct swc_surface
 77 {
 78     struct wl_resource * resource;
 79 
 80     struct swc_surface_state state;
 81 
 82-    union swc_renderer_surface_state renderer_state;
 83-    struct swc_compositor_surface_state compositor_state;
 84-
 85     /* For usage by a shell implementation. */
 86     void * shell_data;
 87 
 88@@ -54,15 +97,11 @@ struct swc_surface
 89         int32_t x, y;
 90     } pending;
 91 
 92-    pixman_rectangle32_t geometry;
 93+    const struct swc_surface_class * class;
 94+    void * class_state;
 95 
 96-    struct
 97-    {
 98-        uint32_t width;
 99-        uint32_t color;
100-    } border;
101-
102-    uint32_t output_mask;
103+    uint32_t outputs;
104+    pixman_rectangle32_t geometry;
105 
106     struct wl_signal event_signal;
107     struct wl_list link;
108@@ -72,6 +111,12 @@ struct swc_surface * swc_surface_new(struct wl_client * client, uint32_t id);
109 
110 void swc_surface_send_frame_callbacks(struct swc_surface * surface,
111                                       uint32_t time);
112+void swc_surface_set_class(struct swc_surface * surface,
113+                           const struct swc_surface_class * class);
114+
115+void swc_surface_update(struct swc_surface * surface);
116+
117+void swc_surface_move(struct swc_surface * surface, int32_t x, int32_t y);
118 
119 #endif
120 
+0, -30
 1@@ -1,30 +0,0 @@
 2-#ifndef SWC_SURFACE_STATE_H
 3-#define SWC_SURFACE_STATE_H 1
 4-
 5-#include <libdrm/intel_bufmgr.h>
 6-
 7-#include <wayland-server.h>
 8-#include <pixman.h>
 9-
10-union swc_renderer_surface_state
11-{
12-    struct
13-    {
14-        pixman_image_t * image;
15-    } shm;
16-    struct
17-    {
18-        drm_intel_bo * bo;
19-        uint32_t width, height, pitch;
20-    } drm;
21-};
22-
23-struct swc_compositor_surface_state
24-{
25-    struct swc_compositor * compositor;
26-    struct wl_listener destroy_listener;
27-    struct wl_listener event_listener;
28-};
29-
30-#endif
31-
+11, -0
 1@@ -2,7 +2,9 @@
 2 #define SWC_UTIL_H 1
 3 
 4 #include <stdbool.h>
 5+#include <sys/param.h>
 6 #include <wayland-server.h>
 7+#include <pixman.h>
 8 
 9 #ifndef offsetof
10 #   define offsetof __builtin_offsetof
11@@ -15,6 +17,15 @@
12 
13 void swc_remove_resource(struct wl_resource * resource);
14 
15+static inline bool swc_rectangle_overlap
16+    (pixman_rectangle32_t * r1, pixman_rectangle32_t * r2)
17+{
18+    return (MAX(r1->x + r1->width, r2->x + r2->width) - MIN(r1->x, r2->x)
19+            < r1->width + r2->width)
20+        && (MAX(r1->y + r1->height, r2->y + r2->height) - MIN(r1->y, r2->y)
21+            < r1->height + r2->height);
22+}
23+
24 int swc_launch_open_input_device(int socket, const char * path, int flags);
25 bool swc_launch_drm_master(int socket, int fd, bool set);
26