commit 300de28

Michael Forney  ·  2014-01-17 02:06:26 +0000 UTC
parent 0dc0ed3
Move common state to swc_view
10 files changed,  +374, -329
+145, -210
  1@@ -23,6 +23,7 @@
  2 struct view
  3 {
  4     struct swc_view base;
  5+    struct wl_listener event_listener;
  6     struct swc_compositor * compositor;
  7     struct swc_surface * surface;
  8 
  9@@ -40,9 +41,7 @@ struct view
 10         bool damaged;
 11     } border;
 12 
 13-    bool mapped;
 14-
 15-    struct wl_listener surface_event_listener;
 16+    struct wl_list link;
 17 };
 18 
 19 /* Rendering {{{ */
 20@@ -51,50 +50,39 @@ struct render_target
 21 {
 22     struct wld_buffer * buffer;
 23     struct swc_rectangle geometry;
 24+    uint32_t mask;
 25 };
 26 
 27-static void repaint_surface(struct render_target * target,
 28-                            struct swc_surface * surface,
 29-                            pixman_region32_t * damage)
 30+static void repaint_view(struct render_target * target, struct view * view,
 31+                         pixman_region32_t * damage)
 32 {
 33-    pixman_region32_t surface_damage;
 34-    pixman_region32_t border_damage;
 35-    pixman_region32_t surface_region;
 36-    struct view * view = (void *) surface->view;
 37+    pixman_region32_t view_region, view_damage, border_damage;
 38+    const struct swc_rectangle * geometry = &view->base.geometry;
 39 
 40-    if (!surface->state.buffer)
 41+    if (!view->base.buffer)
 42         return;
 43 
 44-    pixman_region32_init_with_extents(&surface_damage, &view->extents);
 45+    pixman_region32_init_rect(&view_region, geometry->x, geometry->y,
 46+                              geometry->width, geometry->height);
 47+    pixman_region32_init_with_extents(&view_damage, &view->extents);
 48     pixman_region32_init(&border_damage);
 49-    pixman_region32_init_rect
 50-        (&surface_region, surface->geometry.x, surface->geometry.y,
 51-         surface->geometry.width, surface->geometry.height);
 52 
 53-    pixman_region32_intersect(&surface_damage, &surface_damage, damage);
 54-    pixman_region32_subtract(&surface_damage, &surface_damage, &view->clip);
 55-    pixman_region32_subtract(&border_damage, &surface_damage, &surface_region);
 56-    pixman_region32_intersect(&surface_damage, &surface_damage,
 57-                              &surface_region);
 58+    pixman_region32_intersect(&view_damage, &view_damage, damage);
 59+    pixman_region32_subtract(&view_damage, &view_damage, &view->clip);
 60+    pixman_region32_subtract(&border_damage, &view_damage, &view_region);
 61+    pixman_region32_intersect(&view_damage, &view_damage, &view_region);
 62 
 63-    pixman_region32_fini(&surface_region);
 64+    pixman_region32_fini(&view_region);
 65 
 66-    if (pixman_region32_not_empty(&surface_damage))
 67+    if (pixman_region32_not_empty(&view_damage))
 68     {
 69-        DEBUG("\tDRM surface %u { x: %d, y: %d, w: %u, h: %u }\n",
 70-              wl_resource_get_id(surface->resource),
 71-              surface->geometry.x, surface->geometry.y,
 72-              surface->geometry.width, surface->geometry.height);
 73-
 74-        pixman_region32_translate(&surface_damage,
 75-                                  -surface->geometry.x, -surface->geometry.y);
 76-        wld_copy_region(swc.drm->renderer, surface->state.buffer->wld,
 77-                        surface->geometry.x - target->geometry.x,
 78-                        surface->geometry.y - target->geometry.y,
 79-                        &surface_damage);
 80+        pixman_region32_translate(&view_damage, -geometry->x, -geometry->y);
 81+        wld_copy_region(swc.drm->renderer, view->base.buffer->wld,
 82+                        geometry->x - target->geometry.x,
 83+                        geometry->y - target->geometry.y, &view_damage);
 84     }
 85 
 86-    pixman_region32_fini(&surface_damage);
 87+    pixman_region32_fini(&view_damage);
 88 
 89     /* Draw border */
 90     if (pixman_region32_not_empty(&border_damage))
 91@@ -112,9 +100,9 @@ static void repaint_surface(struct render_target * target,
 92 static void renderer_repaint(struct render_target * target,
 93                              pixman_region32_t * damage,
 94                              pixman_region32_t * base_damage,
 95-                             struct wl_list * surfaces)
 96+                             struct wl_list * views)
 97 {
 98-    struct swc_surface * surface;
 99+    struct view * view;
100 
101     DEBUG("Rendering to target { x: %d, y: %d, w: %u, h: %u }\n",
102           target->geometry.x, target->geometry.y,
103@@ -128,20 +116,21 @@ static void renderer_repaint(struct render_target * target,
104         wld_fill_region(swc.drm->renderer, 0xff000000, base_damage);
105     }
106 
107-    wl_list_for_each_reverse(surface, surfaces, link)
108+    wl_list_for_each_reverse(view, views, link)
109     {
110-        if (swc_rectangle_overlap(&target->geometry, &surface->geometry))
111-            repaint_surface(target, surface, damage);
112+        if (view->base.screens & target->mask)
113+            repaint_view(target, view, damage);
114     }
115 
116     wld_flush(swc.drm->renderer);
117 }
118 
119-static void renderer_attach(struct view * view, struct swc_buffer * buffer)
120+static bool renderer_attach(struct view * view, struct swc_buffer * buffer)
121 {
122+    return true;
123 }
124 
125-static void renderer_flush_surface(struct swc_surface * surface)
126+static void renderer_flush_view(struct view * view)
127 {
128 }
129 
130@@ -150,12 +139,11 @@ static void renderer_flush_surface(struct swc_surface * surface)
131 /* Surface Views {{{ */
132 
133 /**
134- * Adds damage from the region below a surface, taking into account it's clip
135+ * Adds damage from the region below a view, taking into account it's clip
136  * region, to the region specified by `damage'.
137  */
138-static void damage_below_surface(struct swc_surface * surface)
139+static void damage_below_view(struct view * view)
140 {
141-    struct view * view = (void *) surface->view;
142     struct swc_compositor * compositor = view->compositor;
143     pixman_region32_t damage_below;
144 
145@@ -169,101 +157,40 @@ static void damage_below_surface(struct swc_surface * surface)
146 /**
147  * Completely damages the surface and its border.
148  */
149-static void damage_surface(struct swc_surface * surface)
150+static void damage_view(struct view * view)
151 {
152-    struct view * view = (void *) surface->view;
153-    printf("damaging surface\n");
154-
155-    pixman_region32_fini(&surface->state.damage);
156-    pixman_region32_init_rect(&surface->state.damage, 0, 0,
157-                              surface->geometry.width,
158-                              surface->geometry.height);
159+    damage_below_view(view);
160     view->border.damaged = true;
161 }
162 
163-static void update_extents(struct swc_surface * surface)
164+static void update_extents(struct view * view)
165 {
166-    struct view * view = (void *) surface->view;
167-
168-    view->extents.x1 = surface->geometry.x - view->border.width;
169-    view->extents.y1 = surface->geometry.y - view->border.width;
170-    view->extents.x2 = surface->geometry.x + surface->geometry.width
171+    view->extents.x1 = view->base.geometry.x - view->border.width;
172+    view->extents.y1 = view->base.geometry.y - view->border.width;
173+    view->extents.x2 = view->base.geometry.x + view->base.geometry.width
174         + view->border.width;
175-    view->extents.y2 = surface->geometry.y + surface->geometry.height
176+    view->extents.y2 = view->base.geometry.y + view->base.geometry.height
177         + view->border.width;
178 
179     /* Damage border. */
180     view->border.damaged = true;
181 }
182 
183-static void update_screens(struct swc_surface * surface)
184+static bool update(struct swc_view * base)
185 {
186-    struct view * view = (void *) surface->view;
187-    uint32_t old_screens = surface->screens, new_screens = 0,
188-             entered_screens, left_screens, changed_screens;
189+    struct view * view = (void *) base;
190     struct swc_screen_internal * screen;
191-    struct swc_output * output;
192-    struct wl_client * client;
193-    struct wl_resource * resource;
194 
195-    if (view->mapped)
196-    {
197-        wl_list_for_each(screen, &swc.screens, link)
198-        {
199-            if (swc_rectangle_overlap(&screen->base.geometry, &surface->geometry))
200-                new_screens |= swc_screen_mask(screen);
201-        }
202-    }
203-
204-    if (new_screens == old_screens)
205-        return;
206-
207-    entered_screens = new_screens & ~old_screens;
208-    left_screens = old_screens & ~new_screens;
209-    changed_screens = old_screens ^ new_screens;
210+    if (!view->base.visible)
211+        return false;
212 
213     wl_list_for_each(screen, &swc.screens, link)
214     {
215-        if (!(changed_screens & swc_screen_mask(screen)))
216-            continue;
217-
218-        output = CONTAINER_OF(screen->outputs.next, typeof(*output), link);
219-        client = wl_resource_get_client(surface->resource);
220-        resource = wl_resource_find_for_client(&output->resources, client);
221-
222-        if (resource)
223-        {
224-            if (entered_screens & swc_screen_mask(screen))
225-                wl_surface_send_enter(surface->resource, resource);
226-            else if (left_screens & swc_screen_mask(screen))
227-                wl_surface_send_leave(surface->resource, resource);
228-        }
229+        if (view->base.screens & swc_screen_mask(screen))
230+            swc_compositor_schedule_update(view->compositor, screen);
231     }
232 
233-    surface->screens = new_screens;
234-}
235-
236-static void update(struct swc_view * view);
237-
238-static void handle_surface_event(struct wl_listener * listener, void * data)
239-{
240-    struct view * view
241-        = CONTAINER_OF(listener, typeof(*view), surface_event_listener);
242-    struct swc_event * event = data;
243-    struct swc_surface_event_data * event_data = event->data;
244-    struct swc_surface * surface = event_data->surface;
245-
246-    switch (event->type)
247-    {
248-        case SWC_SURFACE_EVENT_TYPE_RESIZE:
249-            damage_below_surface(surface);
250-
251-            update_extents(surface);
252-            update(&view->base);
253-            update_screens(surface);
254-
255-            break;
256-    }
257+    return true;
258 }
259 
260 static void remove_(struct swc_view * base)
261@@ -271,69 +198,84 @@ static void remove_(struct swc_view * base)
262     struct view * view = (void *) base;
263 
264     swc_compositor_surface_hide(view->surface);
265-    wl_list_remove(&view->surface_event_listener.link);
266     pixman_region32_fini(&view->clip);
267     free(view);
268 }
269 
270-static void attach(struct swc_view * base, struct swc_buffer * buffer)
271+static bool attach(struct swc_view * base, struct swc_buffer * buffer)
272 {
273     struct view * view = (void *) base;
274 
275-    renderer_attach(view, buffer);
276+    if (!renderer_attach(view, buffer))
277+        return false;
278+
279+    return true;
280 }
281 
282-static void update(struct swc_view * base)
283+static bool move(struct swc_view * base, int32_t x, int32_t y)
284 {
285     struct view * view = (void *) base;
286-    struct swc_screen_internal * screen;
287-
288-    if (!view->mapped)
289-        return;
290 
291-    wl_list_for_each(screen, &swc.screens, link)
292+    if (view->base.visible)
293     {
294-        if (view->surface->screens & swc_screen_mask(screen))
295-            swc_compositor_schedule_update(view->compositor, screen);
296+        damage_below_view(view);
297+        update(&view->base);
298     }
299+
300+    return true;
301 }
302 
303-static void move(struct swc_view * base, int32_t x, int32_t y)
304+static void resize(struct swc_view * base)
305 {
306     struct view * view = (void *) base;
307-    struct swc_surface * surface = view->surface;
308-
309-    if (x == surface->geometry.x && y == surface->geometry.y)
310-        return;
311-
312-    if (view->mapped)
313-        damage_below_surface(surface);
314 
315-    surface->geometry.x = x;
316-    surface->geometry.y = y;
317-
318-    update_extents(surface);
319-
320-    if (view->mapped)
321+    if (view->base.visible)
322     {
323-        /* Assume worst-case no clipping until we draw the next frame (in case
324-         * the surface gets moved again before that). */
325-        pixman_region32_init(&view->clip);
326-
327-        damage_below_surface(surface);
328-        update(&view->base);
329-        update_screens(surface);
330+        damage_below_view(view);
331         update(&view->base);
332     }
333 }
334 
335-const struct swc_view_impl view_impl = {
336-    .remove = &remove_,
337-    .attach = &attach,
338+const static struct swc_view_impl view_impl = {
339     .update = &update,
340-    .move = &move
341+    .attach = &attach,
342+    .move = &move,
343+    .resize = &resize,
344+    .remove = &remove_,
345 };
346 
347+static void handle_view_event(struct wl_listener * listener, void * data)
348+{
349+    struct view * view = CONTAINER_OF(listener, typeof(*view), event_listener);
350+    struct swc_event * event = data;
351+
352+    switch (event->type)
353+    {
354+        case SWC_VIEW_EVENT_MOVED:
355+            update_extents(view);
356+
357+            if (view->base.visible)
358+            {
359+                /* Assume worst-case no clipping until we draw the next frame (in case
360+                 * the surface gets moved again before that). */
361+                pixman_region32_init(&view->clip);
362+
363+                damage_below_view(view);
364+                update(&view->base);
365+            }
366+            break;
367+        case SWC_VIEW_EVENT_RESIZED:
368+            update_extents(view);
369+
370+            if (view->base.visible)
371+            {
372+                damage_below_view(view);
373+                update(&view->base);
374+            }
375+            break;
376+    }
377+}
378+
379 bool swc_compositor_add_surface(struct swc_compositor * compositor,
380                                 struct swc_surface * surface)
381 {
382@@ -345,18 +287,18 @@ bool swc_compositor_add_surface(struct swc_compositor * compositor,
383         return false;
384 
385     swc_view_initialize(&view->base, &view_impl);
386+    view->base.visible = false;
387+    view->event_listener.notify = &handle_view_event;
388+    wl_signal_add(&view->base.event_signal, &view->event_listener);
389     view->compositor = compositor;
390     view->surface = surface;
391-    view->mapped = false;
392-    view->extents.x1 = surface->geometry.x;
393-    view->extents.y1 = surface->geometry.y;
394-    view->extents.x2 = surface->geometry.x + surface->geometry.width;
395-    view->extents.y2 = surface->geometry.y + surface->geometry.height;
396+    view->extents.x1 = 0;
397+    view->extents.y1 = 0;
398+    view->extents.x2 = 0;
399+    view->extents.y2 = 0;
400     view->border.width = 0;
401     view->border.color = 0x000000;
402     view->border.damaged = false;
403-    view->surface_event_listener.notify = &handle_surface_event;
404-    wl_signal_add(&surface->event_signal, &view->surface_event_listener);
405     pixman_region32_init(&view->clip);
406     swc_surface_set_view(surface, &view->base);
407 
408@@ -366,26 +308,23 @@ bool swc_compositor_add_surface(struct swc_compositor * compositor,
409 void swc_compositor_surface_show(struct swc_surface * surface)
410 {
411     struct view * view = (void *) surface->view;
412-    struct swc_compositor * compositor = view->compositor;
413 
414     if (view->base.impl != &view_impl)
415         return;
416 
417-    if (view->mapped)
418+    if (view->base.visible)
419         return;
420 
421     printf("showing surface %u\n", wl_resource_get_id(surface->resource));
422 
423-    view->mapped = true;
424-
425     /* Assume worst-case no clipping until we draw the next frame (in case the
426      * surface gets moved before that. */
427     pixman_region32_clear(&view->clip);
428 
429-    damage_surface(surface);
430-    update_screens(surface);
431+    damage_view(view);
432+    swc_view_set_visibility(&view->base, true);
433     update(&view->base);
434-    wl_list_insert(&compositor->surfaces, &surface->link);
435+    wl_list_insert(&view->compositor->views, &view->link);
436 }
437 
438 void swc_compositor_surface_hide(struct swc_surface * surface)
439@@ -395,17 +334,15 @@ void swc_compositor_surface_hide(struct swc_surface * surface)
440     if (view->base.impl != &view_impl)
441         return;
442 
443-    if (!view->mapped)
444+    if (!view->base.visible)
445         return;
446 
447     /* Update all the outputs the surface was on. */
448     update(&view->base);
449 
450-    view->mapped = false;
451-
452-    damage_below_surface(surface);
453-    update_screens(surface);
454-    wl_list_remove(&surface->link);
455+    damage_below_view(view);
456+    swc_view_set_visibility(&view->base, false);
457+    wl_list_remove(&view->link);
458 }
459 
460 void swc_compositor_surface_set_border_width(struct swc_surface * surface,
461@@ -421,7 +358,7 @@ void swc_compositor_surface_set_border_width(struct swc_surface * surface,
462 
463     /* XXX: Damage above surface for transparent surfaces? */
464 
465-    update_extents(surface);
466+    update_extents(view);
467     update(&view->base);
468 }
469 
470@@ -445,63 +382,61 @@ void swc_compositor_surface_set_border_color(struct swc_surface * surface,
471 
472 static void calculate_damage(struct swc_compositor * compositor)
473 {
474-    struct swc_surface * surface;
475     struct view * view;
476-    pixman_region32_t surface_opaque;
477+    pixman_region32_t surface_opaque, * surface_damage;
478 
479     pixman_region32_clear(&compositor->opaque);
480     pixman_region32_init(&surface_opaque);
481 
482-    /* Go through surfaces top-down to calculate clipping regions. */
483-    wl_list_for_each(surface, &compositor->surfaces, link)
484+    /* Go through views top-down to calculate clipping regions. */
485+    wl_list_for_each(view, &compositor->views, link)
486     {
487-        view = (void *) surface->view;
488-
489         /* Clip the surface by the opaque region covering it. */
490         pixman_region32_copy(&view->clip, &compositor->opaque);
491 
492         /* Translate the opaque region to global coordinates. */
493-        pixman_region32_copy(&surface_opaque, &surface->state.opaque);
494-        pixman_region32_translate(&surface_opaque, surface->geometry.x,
495-                                  surface->geometry.y);
496+        pixman_region32_copy(&surface_opaque, &view->surface->state.opaque);
497+        pixman_region32_translate(&surface_opaque,
498+                                  view->base.geometry.x, view->base.geometry.y);
499 
500         /* Add the surface's opaque region to the accumulated opaque
501          * region. */
502         pixman_region32_union(&compositor->opaque, &compositor->opaque,
503                               &surface_opaque);
504 
505-        if (pixman_region32_not_empty(&surface->state.damage))
506+        surface_damage = &view->surface->state.damage;
507+
508+        if (pixman_region32_not_empty(surface_damage))
509         {
510-            renderer_flush_surface(surface);
511+            renderer_flush_view(view);
512 
513             /* Translate surface damage to global coordinates. */
514-            pixman_region32_translate(&surface->state.damage,
515-                                      surface->geometry.x,
516-                                      surface->geometry.y);
517+            pixman_region32_translate
518+                (surface_damage, view->base.geometry.x, view->base.geometry.y);
519 
520             /* Add the surface damage to the compositor damage. */
521             pixman_region32_union(&compositor->damage, &compositor->damage,
522-                                  &surface->state.damage);
523-            pixman_region32_clear(&surface->state.damage);
524+                                  surface_damage);
525+            pixman_region32_clear(surface_damage);
526         }
527 
528         if (view->border.damaged)
529         {
530-            pixman_region32_t border_region, surface_region;
531+            pixman_region32_t border_region, view_region;
532 
533             pixman_region32_init_with_extents(&border_region, &view->extents);
534             pixman_region32_init_rect
535-                (&surface_region, surface->geometry.x, surface->geometry.y,
536-                 surface->geometry.width, surface->geometry.height);
537+                (&view_region, view->base.geometry.x, view->base.geometry.y,
538+                 view->base.geometry.width, view->base.geometry.height);
539 
540             pixman_region32_subtract(&border_region, &border_region,
541-                                     &surface_region);
542+                                     &view_region);
543 
544             pixman_region32_union(&compositor->damage, &compositor->damage,
545                                   &border_region);
546 
547             pixman_region32_fini(&border_region);
548-            pixman_region32_fini(&surface_region);
549+            pixman_region32_fini(&view_region);
550 
551             view->border.damaged = false;
552         }
553@@ -527,9 +462,9 @@ static void repaint_screen(struct swc_compositor * compositor,
554     target.geometry.y = screen->base.geometry.y + output->framebuffer_plane.y;
555     target.geometry.width = target.buffer->width;
556     target.geometry.height = target.buffer->height;
557+    target.mask = swc_screen_mask(screen);
558 
559-    renderer_repaint(&target, damage, &base_damage,
560-                     &compositor->surfaces);
561+    renderer_repaint(&target, damage, &base_damage, &compositor->views);
562 
563     pixman_region32_fini(&base_damage);
564 
565@@ -607,20 +542,20 @@ static void handle_focus(struct swc_pointer * pointer)
566 {
567     /* XXX: Temporary hack */
568     struct swc_compositor * compositor = swc.compositor;
569-    struct swc_surface * surface;
570+    struct view * view;
571     int32_t x, y;
572 
573-    wl_list_for_each(surface, &compositor->surfaces, link)
574+    wl_list_for_each(view, &compositor->views, link)
575     {
576         x = wl_fixed_to_int(pointer->x);
577         y = wl_fixed_to_int(pointer->y);
578 
579-        if (swc_rectangle_contains_point(&surface->geometry, x, y)
580-            && pixman_region32_contains_point(&surface->state.input,
581-                                              x - surface->geometry.x,
582-                                              y - surface->geometry.y, NULL))
583+        if (swc_rectangle_contains_point(&view->base.geometry, x, y)
584+            && pixman_region32_contains_point(&view->surface->state.input,
585+                                              x - view->base.geometry.x,
586+                                              y - view->base.geometry.y, NULL))
587         {
588-            swc_pointer_set_focus(pointer, surface);
589+            swc_pointer_set_focus(pointer, view->surface);
590             return;
591         }
592     }
593@@ -645,14 +580,14 @@ static void handle_drm_event(struct wl_listener * listener, void * data)
594         case SWC_DRM_PAGE_FLIP:
595         {
596             struct swc_drm_event_data * event_data = event->data;
597-            struct swc_surface * surface;
598+            struct view * view;
599 
600             compositor->pending_flips &= ~SWC_OUTPUT_MASK(event_data->output);
601 
602             if (compositor->pending_flips == 0)
603             {
604-                wl_list_for_each(surface, &compositor->surfaces, link)
605-                    swc_view_frame(surface->view, event_data->time);
606+                wl_list_for_each(view, &compositor->views, link)
607+                    swc_view_frame(&view->base, event_data->time);
608             }
609 
610             /* If we had scheduled updates that couldn't run because we were
611@@ -744,7 +679,7 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
612 
613     pixman_region32_init(&compositor->damage);
614     pixman_region32_init(&compositor->opaque);
615-    wl_list_init(&compositor->surfaces);
616+    wl_list_init(&compositor->views);
617 
618     swc_add_key_binding(SWC_MOD_CTRL | SWC_MOD_ALT, XKB_KEY_BackSpace,
619                         &handle_terminate, display);
+1, -1
1@@ -10,7 +10,7 @@ struct swc_screen_internal;
2 struct swc_compositor
3 {
4     struct wl_display * display;
5-    struct wl_list surfaces;
6+    struct wl_list views;
7 
8     /* Internal state related to repainting the screen. */
9     struct
+5, -14
 1@@ -1,6 +1,7 @@
 2 #include "pointer.h"
 3 #include "event.h"
 4 #include "util.h"
 5+#include "view.h"
 6 
 7 #include <stdio.h>
 8 #include <assert.h>
 9@@ -19,8 +20,8 @@ static void enter(struct swc_input_focus_handler * handler,
10     display = wl_client_get_display(client);
11     serial = wl_display_next_serial(display);
12 
13-    surface_x = pointer->x - wl_fixed_from_int(surface->geometry.x);
14-    surface_y = pointer->y - wl_fixed_from_int(surface->geometry.y);
15+    surface_x = pointer->x - wl_fixed_from_int(surface->view->geometry.x);
16+    surface_y = pointer->y - wl_fixed_from_int(surface->view->geometry.y);
17 
18     printf("-> pointer.enter: %p (%d, %d)\n", resource, surface_x, surface_y);
19     wl_pointer_send_enter(resource, serial, surface->resource,
20@@ -135,8 +136,6 @@ static void set_cursor(struct wl_client * client,
21 
22     if (surface)
23     {
24-        surface->geometry.x = wl_fixed_to_int(pointer->x) - hotspot_x;
25-        surface->geometry.y = wl_fixed_to_int(pointer->y) - hotspot_y;
26         wl_resource_add_destroy_listener(surface->resource,
27                                          &pointer->cursor.destroy_listener);
28     }
29@@ -218,20 +217,12 @@ void swc_pointer_handle_relative_motion
30     {
31         wl_fixed_t surface_x, surface_y;
32         surface_x = pointer->x
33-            - wl_fixed_from_int(pointer->focus.surface->geometry.x);
34+            - wl_fixed_from_int(pointer->focus.surface->view->geometry.x);
35         surface_y = pointer->y
36-            - wl_fixed_from_int(pointer->focus.surface->geometry.y);
37+            - wl_fixed_from_int(pointer->focus.surface->view->geometry.y);
38 
39         wl_pointer_send_motion(pointer->focus.resource, time,
40                                surface_x, surface_y);
41-
42-        if (pointer->cursor.surface)
43-        {
44-            swc_surface_move
45-                (pointer->cursor.surface,
46-                 wl_fixed_to_int(pointer->x) - pointer->cursor.hotspot_x,
47-                 wl_fixed_to_int(pointer->y) - pointer->cursor.hotspot_y);
48-        }
49     }
50 }
51 
+5, -4
 1@@ -26,6 +26,7 @@
 2 #include "swc.h"
 3 #include "surface.h"
 4 #include "util.h"
 5+#include "view.h"
 6 #include "window.h"
 7 
 8 #include <stdlib.h>
 9@@ -87,8 +88,8 @@ static void set_transient(struct wl_client * client,
10         = wl_resource_get_user_data(resource);
11     struct swc_surface * parent = wl_resource_get_user_data(parent_resource);
12 
13-    swc_surface_move(shell_surface->window.surface,
14-                     parent->geometry.x + x, parent->geometry.y + y);
15+    swc_view_move(shell_surface->window.surface->view,
16+                  parent->view->geometry.x + x, parent->view->geometry.y + y);
17     swc_compositor_surface_show(shell_surface->window.surface);
18 
19     /* XXX: Handle transient */
20@@ -111,8 +112,8 @@ static void set_popup(struct wl_client * client, struct wl_resource * resource,
21         = wl_resource_get_user_data(resource);
22     struct swc_surface * parent = wl_resource_get_user_data(parent_resource);
23 
24-    swc_surface_move(shell_surface->window.surface,
25-                     parent->geometry.x + x, parent->geometry.y + y);
26+    swc_view_move(shell_surface->window.surface->view,
27+                  parent->view->geometry.x + x, parent->view->geometry.y + y);
28     swc_compositor_surface_show(shell_surface->window.surface);
29 
30     /* XXX: Handle popup */
+60, -78
  1@@ -24,7 +24,10 @@
  2 #include "surface.h"
  3 #include "buffer.h"
  4 #include "event.h"
  5+#include "internal.h"
  6+#include "output.h"
  7 #include "region.h"
  8+#include "screen.h"
  9 #include "util.h"
 10 #include "view.h"
 11 #include "wayland_buffer.h"
 12@@ -33,37 +36,6 @@
 13 #include <stdio.h>
 14 #include <wld/wld.h>
 15 
 16-static void set_size(struct swc_surface * surface,
 17-                     uint32_t width, uint32_t height)
 18-{
 19-    /* Check if the surface was resized. */
 20-    if (width != surface->geometry.width || height != surface->geometry.height)
 21-    {
 22-        struct swc_surface_event_data data = {
 23-            .surface = surface,
 24-            .resize = {
 25-                .old_width = surface->geometry.width,
 26-                .old_height = surface->geometry.height,
 27-                .new_width = width,
 28-                .new_height = height
 29-            }
 30-        };
 31-
 32-        surface->geometry.width = width;
 33-        surface->geometry.height = height;
 34-
 35-        pixman_region32_intersect_rect
 36-            (&surface->state.opaque, &surface->state.opaque,
 37-             0, 0, width, height);
 38-        pixman_region32_intersect_rect
 39-            (&surface->state.damage, &surface->state.damage,
 40-             0, 0, width, height);
 41-
 42-        swc_send_event(&surface->event_signal,
 43-                       SWC_SURFACE_EVENT_TYPE_RESIZE, &data);
 44-    }
 45-}
 46-
 47 /**
 48  * Removes a buffer from a surface state.
 49  */
 50@@ -73,21 +45,12 @@ static void handle_buffer_destroy(struct wl_listener * listener, void * data)
 51 
 52     state = CONTAINER_OF(listener, typeof(*state), buffer_destroy_listener);
 53     state->buffer = NULL;
 54-
 55-    if (state->current)
 56-    {
 57-        struct swc_surface * surface;
 58-
 59-        surface = CONTAINER_OF(state, typeof(*surface), state);
 60-        set_size(surface, 0, 0);
 61-    }
 62 }
 63 
 64-static void state_initialize(struct swc_surface_state * state, bool current)
 65+static void state_initialize(struct swc_surface_state * state)
 66 {
 67     state->buffer = NULL;
 68     state->buffer_destroy_listener.notify = &handle_buffer_destroy;
 69-    state->current = current;
 70 
 71     pixman_region32_init(&state->damage);
 72     pixman_region32_init(&state->opaque);
 73@@ -232,6 +195,7 @@ static void set_input_region(struct wl_client * client,
 74 static void commit(struct wl_client * client, struct wl_resource * resource)
 75 {
 76     struct swc_surface * surface = wl_resource_get_user_data(resource);
 77+    struct wld_buffer * buffer;
 78 
 79     /* Attach */
 80     if (surface->pending.commit & SWC_SURFACE_COMMIT_ATTACH)
 81@@ -243,24 +207,17 @@ static void commit(struct wl_client * client, struct wl_resource * resource)
 82             swc_wayland_buffer_release(current_buffer);
 83 
 84         state_set_buffer(&surface->state, surface->pending.state.buffer);
 85-
 86-        /* Determine size of buffer. */
 87-        if (current_buffer)
 88-        {
 89-            set_size(surface,
 90-                     current_buffer->wld->width, current_buffer->wld->height);
 91-        }
 92-        else
 93-            set_size(surface, 0, 0);
 94     }
 95 
 96+    buffer = surface->state.buffer ? surface->state.buffer->wld : NULL;
 97+
 98     /* Damage */
 99     if (surface->pending.commit & SWC_SURFACE_COMMIT_DAMAGE)
100     {
101         pixman_region32_intersect_rect(&surface->pending.state.damage,
102                                        &surface->pending.state.damage, 0, 0,
103-                                       surface->geometry.width,
104-                                       surface->geometry.height);
105+                                       buffer ? buffer->width : 0,
106+                                       buffer ? buffer->height : 0);
107         pixman_region32_union(&surface->state.damage, &surface->state.damage,
108                               &surface->pending.state.damage);
109         pixman_region32_clear(&surface->pending.state.damage);
110@@ -271,8 +228,8 @@ static void commit(struct wl_client * client, struct wl_resource * resource)
111     {
112         pixman_region32_intersect_rect(&surface->state.opaque,
113                                        &surface->pending.state.opaque, 0, 0,
114-                                       surface->geometry.width,
115-                                       surface->geometry.height);
116+                                       buffer ? buffer->width : 0,
117+                                       buffer ? buffer->height : 0);
118     }
119 
120     /* Input */
121@@ -293,8 +250,8 @@ static void commit(struct wl_client * client, struct wl_resource * resource)
122     if (surface->view)
123     {
124         if (surface->pending.commit & SWC_SURFACE_COMMIT_ATTACH)
125-            surface->view->impl->attach(surface->view, surface->state.buffer);
126-        surface->view->impl->update(surface->view);
127+            swc_view_attach(surface->view, surface->state.buffer);
128+        swc_view_update(surface->view);
129     }
130 
131     surface->pending.commit = 0;
132@@ -335,6 +292,9 @@ static void surface_destroy(struct wl_resource * resource)
133     state_finish(&surface->state);
134     state_finish(&surface->pending.state);
135 
136+    if (surface->view)
137+        wl_list_remove(&surface->view_listener.link);
138+
139     printf("freeing surface %p\n", surface);
140     free(surface);
141 }
142@@ -362,6 +322,46 @@ static void handle_view_event(struct wl_listener * listener, void * data)
143             wl_list_init(&surface->state.frame_callbacks);
144             break;
145         }
146+        case SWC_VIEW_EVENT_SCREENS_CHANGED:
147+        {
148+            struct swc_screen_internal * screen;
149+            struct swc_output * output;
150+            struct wl_client * client;
151+            struct wl_resource * resource;
152+            uint32_t entered = event_data->screens_changed.entered,
153+                     left = event_data->screens_changed.left;
154+
155+            client = wl_resource_get_client(surface->resource);
156+
157+            wl_list_for_each(screen, &swc.screens, link)
158+            {
159+                if (!((entered | left) & swc_screen_mask(screen)))
160+                    continue;
161+
162+                wl_list_for_each(output, &screen->outputs, link)
163+                {
164+                    resource = wl_resource_find_for_client
165+                        (&output->resources, client);
166+
167+                    if (resource)
168+                    {
169+                        if (entered & swc_screen_mask(screen))
170+                            wl_surface_send_enter(surface->resource, resource);
171+                        else if (left & swc_screen_mask(screen))
172+                            wl_surface_send_leave(surface->resource, resource);
173+                    }
174+                }
175+            }
176+            break;
177+        }
178+        case SWC_VIEW_EVENT_RESIZED:
179+            pixman_region32_intersect_rect
180+                (&surface->state.opaque, &surface->state.opaque, 0, 0,
181+                 surface->view->geometry.width, surface->view->geometry.height);
182+            pixman_region32_intersect_rect
183+                (&surface->state.damage, &surface->state.damage, 0, 0,
184+                 surface->view->geometry.width, surface->view->geometry.height);
185+            break;
186     }
187 }
188 
189@@ -383,19 +383,13 @@ struct swc_surface * swc_surface_new(struct wl_client * client,
190         return NULL;
191 
192     /* Initialize the surface. */
193-    surface->screens = 0;
194-    surface->geometry.x = 0;
195-    surface->geometry.y = 0;
196-    surface->geometry.width = 0;
197-    surface->geometry.height = 0;
198     surface->pending.commit = 0;
199     surface->window = NULL;
200     surface->view = NULL;
201     surface->view_listener.notify = &handle_view_event;
202-    surface->view_state = NULL;
203 
204-    state_initialize(&surface->state, true);
205-    state_initialize(&surface->pending.state, false);
206+    state_initialize(&surface->state);
207+    state_initialize(&surface->pending.state);
208 
209     wl_signal_init(&surface->event_signal);
210 
211@@ -425,20 +419,8 @@ void swc_surface_set_view(struct swc_surface * surface, struct swc_view * view)
212     if (view)
213     {
214         wl_signal_add(&view->event_signal, &surface->view_listener);
215-        surface->view->impl->attach(surface->view, surface->state.buffer);
216-        surface->view->impl->update(surface->view);
217+        swc_view_attach(view, surface->state.buffer);
218+        swc_view_update(surface->view);
219     }
220 }
221 
222-void swc_surface_update(struct swc_surface * surface)
223-{
224-    if (surface->view)
225-        surface->view->impl->update(surface->view);
226-}
227-
228-void swc_surface_move(struct swc_surface * surface, int32_t x, int32_t y)
229-{
230-    if (surface->view)
231-        surface->view->impl->move(surface->view, x, y);
232-}
233-
+1, -11
 1@@ -24,8 +24,7 @@
 2 #ifndef SWC_SURFACE_H
 3 #define SWC_SURFACE_H
 4 
 5-#include "swc.h"
 6-
 7+#include <stdbool.h>
 8 #include <wayland-server.h>
 9 #include <pixman.h>
10 
11@@ -58,7 +57,6 @@ struct swc_surface_state
12 {
13     struct swc_buffer * buffer;
14     struct wl_listener buffer_destroy_listener;
15-    bool current;
16 
17     /* The region that needs to be repainted. */
18     pixman_region32_t damage;
19@@ -88,10 +86,6 @@ struct swc_surface
20     struct swc_window * window;
21     struct swc_view * view;
22     struct wl_listener view_listener;
23-    void * view_state;
24-
25-    uint32_t screens;
26-    struct swc_rectangle geometry;
27 
28     struct wl_signal event_signal;
29     struct wl_list link;
30@@ -102,9 +96,5 @@ struct swc_surface * swc_surface_new(struct wl_client * client,
31 
32 void swc_surface_set_view(struct swc_surface * surface, struct swc_view * view);
33 
34-void swc_surface_update(struct swc_surface * surface);
35-
36-void swc_surface_move(struct swc_surface * surface, int32_t x, int32_t y);
37-
38 #endif
39 
+120, -0
  1@@ -22,17 +22,137 @@
  2  */
  3 
  4 #include "view.h"
  5+#include "buffer.h"
  6 #include "event.h"
  7+#include "internal.h"
  8+#include "screen.h"
  9+#include "util.h"
 10+
 11+#include <wld/wld.h>
 12+
 13+static void update_screens(struct swc_view * view)
 14+{
 15+    struct swc_view_event_data data = { .view = view };
 16+    uint32_t old = view->screens, new = 0;
 17+    struct swc_screen_internal * screen;
 18+
 19+    if (view->visible)
 20+    {
 21+        wl_list_for_each(screen, &swc.screens, link)
 22+        {
 23+            if (swc_rectangle_overlap(&screen->base.geometry, &view->geometry))
 24+                new |= swc_screen_mask(screen);
 25+        }
 26+    }
 27+
 28+    if (new == old)
 29+        return;
 30+
 31+    view->screens = new;
 32+
 33+    data.screens_changed.entered = new & ~old;
 34+    data.screens_changed.left = old & ~new;
 35+    swc_send_event(&view->event_signal, SWC_VIEW_EVENT_SCREENS_CHANGED, &data);
 36+}
 37+
 38+static void set_size(struct swc_view * view, uint32_t width, uint32_t height)
 39+{
 40+    if (view->geometry.width != width || view->geometry.height != height)
 41+    {
 42+        struct swc_view_event_data data = { .view = view };
 43+
 44+        if (view->impl->resize)
 45+            view->impl->resize(view);
 46+
 47+        view->geometry.width = width;
 48+        view->geometry.height = height;
 49+        update_screens(view);
 50+
 51+        swc_send_event(&view->event_signal, SWC_VIEW_EVENT_RESIZED, &data);
 52+    }
 53+}
 54+
 55+static void handle_buffer_destroy(struct wl_listener * listener, void * data)
 56+{
 57+    struct swc_view * view
 58+        = CONTAINER_OF(listener, typeof(*view), buffer_destroy_listener);
 59+
 60+    view->impl->attach(view, NULL);
 61+    view->buffer = NULL;
 62+    set_size(view, 0, 0);
 63+}
 64 
 65 void swc_view_initialize(struct swc_view * view,
 66                          const struct swc_view_impl * impl)
 67 {
 68     view->impl = impl;
 69+    view->visible = true;
 70+    view->geometry.x = 0;
 71+    view->geometry.y = 0;
 72+    view->geometry.width = 0;
 73+    view->geometry.height = 0;
 74+    view->buffer = NULL;
 75+    view->buffer_destroy_listener.notify = &handle_buffer_destroy;
 76+    view->screens = 0;
 77     wl_signal_init(&view->event_signal);
 78 }
 79 
 80 void swc_view_finalize(struct swc_view * view)
 81 {
 82+    if (view->buffer)
 83+        wl_list_remove(&view->buffer_destroy_listener.link);
 84+}
 85+
 86+bool swc_view_attach(struct swc_view * view, struct swc_buffer * buffer)
 87+{
 88+    if (view->impl->attach(view, buffer))
 89+    {
 90+        if (view->buffer)
 91+            wl_list_remove(&view->buffer_destroy_listener.link);
 92+
 93+        if (buffer)
 94+        {
 95+            wl_signal_add(&buffer->destroy_signal,
 96+                          &view->buffer_destroy_listener);
 97+            set_size(view, buffer->wld->width, buffer->wld->height);
 98+        }
 99+        else
100+            set_size(view, 0, 0);
101+
102+        view->buffer = buffer;
103+        return true;
104+    }
105+    else
106+        return false;
107+}
108+
109+bool swc_view_update(struct swc_view * view)
110+{
111+    return view->impl->update(view);
112+}
113+
114+bool swc_view_move(struct swc_view * view, int32_t x, int32_t y)
115+{
116+    struct swc_view_event_data data = { .view = view };
117+
118+    if (x == view->geometry.x && y == view->geometry.y)
119+        return true;
120+
121+    if (!view->impl->move || !view->impl->move(view, x, y))
122+        return false;
123+
124+    view->geometry.x = x;
125+    view->geometry.y = y;
126+    update_screens(view);
127+    swc_send_event(&view->event_signal, SWC_VIEW_EVENT_MOVED, &data);
128+
129+    return true;
130+}
131+
132+void swc_view_set_visibility(struct swc_view * view, bool visible)
133+{
134+    view->visible = visible;
135+    update_screens(view);
136 }
137 
138 void swc_view_frame(struct swc_view * view, uint32_t time)
+33, -9
 1@@ -26,12 +26,20 @@
 2 
 3 #include "swc.h"
 4 
 5-struct swc_buffer;
 6-
 7 enum swc_view_event
 8 {
 9     /* Sent when the view has displayed the next frame. */
10     SWC_VIEW_EVENT_FRAME,
11+
12+    /* Sent when the origin of the view has moved. */
13+    SWC_VIEW_EVENT_MOVED,
14+
15+    /* Sent when the view's size changes. This occurs when a buffer of
16+     * different dimensions is attached to the view. */
17+    SWC_VIEW_EVENT_RESIZED,
18+
19+    /* Sent when the set of screens the view is visible on changes. */
20+    SWC_VIEW_EVENT_SCREENS_CHANGED
21 };
22 
23 struct swc_view_event_data
24@@ -43,6 +51,11 @@ struct swc_view_event_data
25         {
26             uint32_t time;
27         } frame;
28+
29+        struct
30+        {
31+            uint32_t left, entered;
32+        } screens_changed;
33     };
34 };
35 
36@@ -51,21 +64,28 @@ struct swc_view
37     const struct swc_view_impl * impl;
38 
39     struct wl_signal event_signal;
40+    bool visible;
41+    uint32_t screens;
42+
43+    struct swc_rectangle geometry;
44+    struct swc_buffer * buffer;
45+    struct wl_listener buffer_destroy_listener;
46 };
47 
48 struct swc_view_impl
49 {
50-    /* Called when a source is removed from the view. */
51-    void (* remove)(struct swc_view * view);
52+    /* Called when the view should present a new frame. */
53+    bool (* update)(struct swc_view * view);
54 
55     /* Called when a new buffer is attached to the view. */
56-    void (* attach)(struct swc_view * view, struct swc_buffer * buffer);
57+    bool (* attach)(struct swc_view * view, struct swc_buffer * buffer);
58 
59-    /* Called when the view should present a new frame. */
60-    void (* update)(struct swc_view * view);
61+    bool (* move)(struct swc_view * view, int32_t x, int32_t y);
62 
63-    /* Move the view to the specified coordinates. */
64-    void (* move)(struct swc_view * view, int32_t x, int32_t y);
65+    void (* resize)(struct swc_view * view);
66+
67+    /* Called when a source is removed from the view. */
68+    void (* remove)(struct swc_view * view);
69 };
70 
71 void swc_view_initialize(struct swc_view * view,
72@@ -73,6 +93,10 @@ void swc_view_initialize(struct swc_view * view,
73 
74 void swc_view_finalize(struct swc_view * view);
75 
76+bool swc_view_attach(struct swc_view * view, struct swc_buffer * buffer);
77+bool swc_view_update(struct swc_view * view);
78+bool swc_view_move(struct swc_view * view, int32_t x, int32_t y);
79+void swc_view_set_visibility(struct swc_view * view, bool visible);
80 void swc_view_frame(struct swc_view * view, uint32_t time);
81 
82 #endif
+2, -1
 1@@ -29,6 +29,7 @@
 2 #include "seat.h"
 3 #include "swc.h"
 4 #include "util.h"
 5+#include "view.h"
 6 
 7 #include <stdlib.h>
 8 #include <string.h>
 9@@ -97,7 +98,7 @@ void swc_window_set_geometry(struct swc_window * window,
10     if (INTERNAL(window)->impl->configure)
11         INTERNAL(window)->impl->configure(window, geometry);
12 
13-    swc_surface_move(INTERNAL(window)->surface, geometry->x, geometry->y);
14+    swc_view_move(INTERNAL(window)->surface->view, geometry->x, geometry->y);
15 }
16 
17 EXPORT
+2, -1
 1@@ -27,6 +27,7 @@
 2 #include "surface.h"
 3 #include "swc.h"
 4 #include "util.h"
 5+#include "view.h"
 6 #include "window.h"
 7 
 8 #include <stdio.h>
 9@@ -341,7 +342,7 @@ void swc_xwm_manage_window(xcb_window_t id, struct swc_surface * surface)
10     if ((geometry_reply = xcb_get_geometry_reply(xwm.connection,
11                                                  geometry_cookie, NULL)))
12     {
13-        swc_surface_move(surface, geometry_reply->x, geometry_reply->y);
14+        swc_view_move(surface->view, geometry_reply->x, geometry_reply->y);
15     }
16 
17     if (entry->override_redirect)