diff --git a/src/animation.c b/src/animation.c
index 909e24365f018a862c09e964fe911da08cc1dbb2..5eacb7bfed752efc8d36134f4a783971a9692196 100644
--- a/src/animation.c
+++ b/src/animation.c
@@ -34,7 +34,7 @@
 
 WL_EXPORT void
 weston_spring_init(struct weston_spring *spring,
-		 double k, double current, double target)
+		   double k, double current, double target)
 {
 	spring->k = k;
 	spring->friction = 400.0;
@@ -114,52 +114,52 @@ weston_spring_done(struct weston_spring *spring)
 		fabs(spring->current - spring->target) < 0.002;
 }
 
-typedef	void (*weston_surface_animation_frame_func_t)(struct weston_surface_animation *animation);
+typedef	void (*weston_view_animation_frame_func_t)(struct weston_view_animation *animation);
 
-struct weston_surface_animation {
-	struct weston_surface *surface;
+struct weston_view_animation {
+	struct weston_view *view;
 	struct weston_animation animation;
 	struct weston_spring spring;
 	struct weston_transform transform;
 	struct wl_listener listener;
 	float start, stop;
-	weston_surface_animation_frame_func_t frame;
-	weston_surface_animation_frame_func_t reset;
-	weston_surface_animation_done_func_t done;
+	weston_view_animation_frame_func_t frame;
+	weston_view_animation_frame_func_t reset;
+	weston_view_animation_done_func_t done;
 	void *data;
 };
 
 static void
-weston_surface_animation_destroy(struct weston_surface_animation *animation)
+weston_view_animation_destroy(struct weston_view_animation *animation)
 {
 	wl_list_remove(&animation->animation.link);
 	wl_list_remove(&animation->listener.link);
 	wl_list_remove(&animation->transform.link);
 	if (animation->reset)
 		animation->reset(animation);
-	weston_surface_geometry_dirty(animation->surface);
+	weston_view_geometry_dirty(animation->view);
 	if (animation->done)
 		animation->done(animation, animation->data);
 	free(animation);
 }
 
 static void
-handle_animation_surface_destroy(struct wl_listener *listener, void *data)
+handle_animation_view_destroy(struct wl_listener *listener, void *data)
 {
-	struct weston_surface_animation *animation =
+	struct weston_view_animation *animation =
 		container_of(listener,
-			     struct weston_surface_animation, listener);
+			     struct weston_view_animation, listener);
 
-	weston_surface_animation_destroy(animation);
+	weston_view_animation_destroy(animation);
 }
 
 static void
-weston_surface_animation_frame(struct weston_animation *base,
-			       struct weston_output *output, uint32_t msecs)
+weston_view_animation_frame(struct weston_animation *base,
+			    struct weston_output *output, uint32_t msecs)
 {
-	struct weston_surface_animation *animation =
+	struct weston_view_animation *animation =
 		container_of(base,
-			     struct weston_surface_animation, animation);
+			     struct weston_view_animation, animation);
 
 	if (base->frame_counter <= 1)
 		animation->spring.timestamp = msecs;
@@ -167,32 +167,32 @@ weston_surface_animation_frame(struct weston_animation *base,
 	weston_spring_update(&animation->spring, msecs);
 
 	if (weston_spring_done(&animation->spring)) {
-		weston_surface_animation_destroy(animation);
+		weston_view_animation_destroy(animation);
 		return;
 	}
 
 	if (animation->frame)
 		animation->frame(animation);
 
-	weston_surface_geometry_dirty(animation->surface);
-	weston_compositor_schedule_repaint(animation->surface->compositor);
+	weston_view_geometry_dirty(animation->view);
+	weston_view_schedule_repaint(animation->view);
 }
 
-static struct weston_surface_animation *
-weston_surface_animation_run(struct weston_surface *surface,
-			     float start, float stop,
-			     weston_surface_animation_frame_func_t frame,
-			     weston_surface_animation_frame_func_t reset,
-			     weston_surface_animation_done_func_t done,
-			     void *data)
+static struct weston_view_animation *
+weston_view_animation_run(struct weston_view *view,
+			  float start, float stop,
+			  weston_view_animation_frame_func_t frame,
+			  weston_view_animation_frame_func_t reset,
+			  weston_view_animation_done_func_t done,
+			  void *data)
 {
-	struct weston_surface_animation *animation;
+	struct weston_view_animation *animation;
 
 	animation = malloc(sizeof *animation);
 	if (!animation)
 		return NULL;
 
-	animation->surface = surface;
+	animation->view = view;
 	animation->frame = frame;
 	animation->reset = reset;
 	animation->done = done;
@@ -200,35 +200,35 @@ weston_surface_animation_run(struct weston_surface *surface,
 	animation->start = start;
 	animation->stop = stop;
 	weston_matrix_init(&animation->transform.matrix);
-	wl_list_insert(&surface->geometry.transformation_list,
+	wl_list_insert(&view->geometry.transformation_list,
 		       &animation->transform.link);
 	weston_spring_init(&animation->spring, 200.0, 0.0, 1.0);
 	animation->spring.friction = 700;
 	animation->animation.frame_counter = 0;
-	animation->animation.frame = weston_surface_animation_frame;
-	weston_surface_animation_frame(&animation->animation, NULL, 0);
+	animation->animation.frame = weston_view_animation_frame;
+	weston_view_animation_frame(&animation->animation, NULL, 0);
 
-	animation->listener.notify = handle_animation_surface_destroy;
-	wl_signal_add(&surface->destroy_signal, &animation->listener);
+	animation->listener.notify = handle_animation_view_destroy;
+	wl_signal_add(&view->destroy_signal, &animation->listener);
 
-	wl_list_insert(&surface->output->animation_list,
+	wl_list_insert(&view->output->animation_list,
 		       &animation->animation.link);
 
 	return animation;
 }
 
 static void
-reset_alpha(struct weston_surface_animation *animation)
+reset_alpha(struct weston_view_animation *animation)
 {
-	struct weston_surface *surface = animation->surface;
+	struct weston_view *view = animation->view;
 
-	surface->alpha = animation->stop;
+	view->alpha = animation->stop;
 }
 
 static void
-zoom_frame(struct weston_surface_animation *animation)
+zoom_frame(struct weston_view_animation *animation)
 {
-	struct weston_surface *es = animation->surface;
+	struct weston_view *es = animation->view;
 	float scale;
 
 	scale = animation->start +
@@ -248,15 +248,15 @@ zoom_frame(struct weston_surface_animation *animation)
 		es->alpha = 1.0;
 }
 
-WL_EXPORT struct weston_surface_animation *
-weston_zoom_run(struct weston_surface *surface, float start, float stop,
-		weston_surface_animation_done_func_t done, void *data)
+WL_EXPORT struct weston_view_animation *
+weston_zoom_run(struct weston_view *view, float start, float stop,
+		weston_view_animation_done_func_t done, void *data)
 {
-	struct weston_surface_animation *zoom;
+	struct weston_view_animation *zoom;
 
-	zoom = weston_surface_animation_run(surface, start, stop,
-					    zoom_frame, reset_alpha,
-					    done, data);
+	zoom = weston_view_animation_run(view, start, stop,
+					 zoom_frame, reset_alpha,
+					 done, data);
 
 	weston_spring_init(&zoom->spring, 300.0, start, stop);
 	zoom->spring.friction = 1400;
@@ -266,45 +266,45 @@ weston_zoom_run(struct weston_surface *surface, float start, float stop,
 }
 
 static void
-fade_frame(struct weston_surface_animation *animation)
+fade_frame(struct weston_view_animation *animation)
 {
 	if (animation->spring.current > 0.999)
-		animation->surface->alpha = 1;
+		animation->view->alpha = 1;
 	else if (animation->spring.current < 0.001 )
-		animation->surface->alpha = 0;
+		animation->view->alpha = 0;
 	else
-		animation->surface->alpha = animation->spring.current;
+		animation->view->alpha = animation->spring.current;
 }
 
-WL_EXPORT struct weston_surface_animation *
-weston_fade_run(struct weston_surface *surface,
+WL_EXPORT struct weston_view_animation *
+weston_fade_run(struct weston_view *view,
 		float start, float end, float k,
-		weston_surface_animation_done_func_t done, void *data)
+		weston_view_animation_done_func_t done, void *data)
 {
-	struct weston_surface_animation *fade;
+	struct weston_view_animation *fade;
 
-	fade = weston_surface_animation_run(surface, 0, end,
-					    fade_frame, reset_alpha,
-					    done, data);
+	fade = weston_view_animation_run(view, 0, end,
+					 fade_frame, reset_alpha,
+					 done, data);
 
 	weston_spring_init(&fade->spring, k, start, end);
 
 	fade->spring.friction = 1400;
 	fade->spring.previous = -(end - start) * 0.03;
 
-	surface->alpha = start;
+	view->alpha = start;
 
 	return fade;
 }
 
 WL_EXPORT void
-weston_fade_update(struct weston_surface_animation *fade, float target)
+weston_fade_update(struct weston_view_animation *fade, float target)
 {
 	fade->spring.target = target;
 }
 
 static void
-slide_frame(struct weston_surface_animation *animation)
+slide_frame(struct weston_view_animation *animation)
 {
 	float scale;
 
@@ -315,15 +315,15 @@ slide_frame(struct weston_surface_animation *animation)
 	weston_matrix_translate(&animation->transform.matrix, 0, scale, 0);
 }
 
-WL_EXPORT struct weston_surface_animation *
-weston_slide_run(struct weston_surface *surface, float start, float stop,
-		weston_surface_animation_done_func_t done, void *data)
+WL_EXPORT struct weston_view_animation *
+weston_slide_run(struct weston_view *view, float start, float stop,
+		 weston_view_animation_done_func_t done, void *data)
 {
-	struct weston_surface_animation *animation;
+	struct weston_view_animation *animation;
 
-	animation = weston_surface_animation_run(surface, start, stop,
-						 slide_frame, NULL, done,
-						 data);
+	animation = weston_view_animation_run(view, start, stop,
+					      slide_frame, NULL, done,
+					      data);
 	if (!animation)
 		return NULL;
 
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 60b4cbadea16ef33890e560f95ad51858b6db27a..e32e4a85852ad0454f60ac94e187aea06e8c3f6f 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -156,7 +156,7 @@ struct drm_output {
 	struct gbm_bo *cursor_bo[2];
 	struct weston_plane cursor_plane;
 	struct weston_plane fb_plane;
-	struct weston_surface *cursor_surface;
+	struct weston_view *cursor_view;
 	int current_cursor;
 	struct drm_fb *current, *next;
 	struct backlight *backlight;
@@ -448,23 +448,23 @@ drm_output_check_scanout_format(struct drm_output *output,
 }
 
 static struct weston_plane *
-drm_output_prepare_scanout_surface(struct weston_output *_output,
-				   struct weston_surface *es)
+drm_output_prepare_scanout_view(struct weston_output *_output,
+				struct weston_view *ev)
 {
 	struct drm_output *output = (struct drm_output *) _output;
 	struct drm_compositor *c =
 		(struct drm_compositor *) output->base.compositor;
-	struct weston_buffer *buffer = es->buffer_ref.buffer;
+	struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
 	struct gbm_bo *bo;
 	uint32_t format;
 
-	if (es->geometry.x != output->base.x ||
-	    es->geometry.y != output->base.y ||
+	if (ev->geometry.x != output->base.x ||
+	    ev->geometry.y != output->base.y ||
 	    buffer == NULL || c->gbm == NULL ||
 	    buffer->width != output->base.current_mode->width ||
 	    buffer->height != output->base.current_mode->height ||
-	    output->base.transform != es->buffer_transform ||
-	    es->transform.enabled)
+	    output->base.transform != ev->surface->buffer_transform ||
+	    ev->transform.enabled)
 		return NULL;
 
 	bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
@@ -474,7 +474,7 @@ drm_output_prepare_scanout_surface(struct weston_output *_output,
 	if (!bo)
 		return NULL;
 
-	format = drm_output_check_scanout_format(output, es, bo);
+	format = drm_output_check_scanout_format(output, ev->surface, bo);
 	if (format == 0) {
 		gbm_bo_destroy(bo);
 		return NULL;
@@ -766,7 +766,7 @@ page_flip_handler(int fd, unsigned int frame,
 
 static uint32_t
 drm_output_check_sprite_format(struct drm_sprite *s,
-			       struct weston_surface *es, struct gbm_bo *bo)
+			       struct weston_view *ev, struct gbm_bo *bo)
 {
 	uint32_t i, format;
 
@@ -776,9 +776,9 @@ drm_output_check_sprite_format(struct drm_sprite *s,
 		pixman_region32_t r;
 
 		pixman_region32_init_rect(&r, 0, 0,
-					  es->geometry.width,
-					  es->geometry.height);
-		pixman_region32_subtract(&r, &r, &es->opaque);
+					  ev->geometry.width,
+					  ev->geometry.height);
+		pixman_region32_subtract(&r, &r, &ev->surface->opaque);
 
 		if (!pixman_region32_not_empty(&r))
 			format = GBM_FORMAT_XRGB8888;
@@ -794,15 +794,15 @@ drm_output_check_sprite_format(struct drm_sprite *s,
 }
 
 static int
-drm_surface_transform_supported(struct weston_surface *es)
+drm_view_transform_supported(struct weston_view *ev)
 {
-	return !es->transform.enabled ||
-		(es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
+	return !ev->transform.enabled ||
+		(ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
 }
 
 static struct weston_plane *
-drm_output_prepare_overlay_surface(struct weston_output *output_base,
-				   struct weston_surface *es)
+drm_output_prepare_overlay_view(struct weston_output *output_base,
+				struct weston_view *ev)
 {
 	struct weston_compositor *ec = output_base->compositor;
 	struct drm_compositor *c =(struct drm_compositor *) ec;
@@ -817,28 +817,28 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
 	if (c->gbm == NULL)
 		return NULL;
 
-	if (es->buffer_transform != output_base->transform)
+	if (ev->surface->buffer_transform != output_base->transform)
 		return NULL;
 
-	if (es->buffer_scale != output_base->current_scale)
+	if (ev->surface->buffer_scale != output_base->current_scale)
 		return NULL;
 
 	if (c->sprites_are_broken)
 		return NULL;
 
-	if (es->output_mask != (1u << output_base->id))
+	if (ev->output_mask != (1u << output_base->id))
 		return NULL;
 
-	if (es->buffer_ref.buffer == NULL)
+	if (ev->surface->buffer_ref.buffer == NULL)
 		return NULL;
 
-	if (es->alpha != 1.0f)
+	if (ev->alpha != 1.0f)
 		return NULL;
 
-	if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
+	if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
 		return NULL;
 
-	if (!drm_surface_transform_supported(es))
+	if (!drm_view_transform_supported(ev))
 		return NULL;
 
 	wl_list_for_each(s, &c->sprite_list, link) {
@@ -856,12 +856,12 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
 		return NULL;
 
 	bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
-			   es->buffer_ref.buffer->resource,
+			   ev->surface->buffer_ref.buffer->resource,
 			   GBM_BO_USE_SCANOUT);
 	if (!bo)
 		return NULL;
 
-	format = drm_output_check_sprite_format(s, es, bo);
+	format = drm_output_check_sprite_format(s, ev, bo);
 	if (format == 0) {
 		gbm_bo_destroy(bo);
 		return NULL;
@@ -873,9 +873,9 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
 		return NULL;
 	}
 
-	drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
+	drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
 
-	box = pixman_region32_extents(&es->transform.boundingbox);
+	box = pixman_region32_extents(&ev->transform.boundingbox);
 	s->plane.x = box->x1;
 	s->plane.y = box->y1;
 
@@ -885,7 +885,7 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
 	 * for us already).
 	 */
 	pixman_region32_init(&dest_rect);
-	pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
+	pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
 				  &output_base->region);
 	pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
 	box = pixman_region32_extents(&dest_rect);
@@ -901,36 +901,37 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
 	pixman_region32_fini(&dest_rect);
 
 	pixman_region32_init(&src_rect);
-	pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
+	pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
 				  &output_base->region);
 	box = pixman_region32_extents(&src_rect);
 
-	weston_surface_from_global_fixed(es,
-					 wl_fixed_from_int(box->x1),
-					 wl_fixed_from_int(box->y1),
-					 &sx1, &sy1);
-	weston_surface_from_global_fixed(es,
-					 wl_fixed_from_int(box->x2),
-					 wl_fixed_from_int(box->y2),
-					 &sx2, &sy2);
+	weston_view_from_global_fixed(ev,
+				      wl_fixed_from_int(box->x1),
+				      wl_fixed_from_int(box->y1),
+				      &sx1, &sy1);
+	weston_view_from_global_fixed(ev,
+				      wl_fixed_from_int(box->x2),
+				      wl_fixed_from_int(box->y2),
+				      &sx2, &sy2);
 
 	if (sx1 < 0)
 		sx1 = 0;
 	if (sy1 < 0)
 		sy1 = 0;
-	if (sx2 > wl_fixed_from_int(es->geometry.width))
-		sx2 = wl_fixed_from_int(es->geometry.width);
-	if (sy2 > wl_fixed_from_int(es->geometry.height))
-		sy2 = wl_fixed_from_int(es->geometry.height);
+	if (sx2 > wl_fixed_from_int(ev->geometry.width))
+		sx2 = wl_fixed_from_int(ev->geometry.width);
+	if (sy2 > wl_fixed_from_int(ev->geometry.height))
+		sy2 = wl_fixed_from_int(ev->geometry.height);
 
 	tbox.x1 = sx1;
 	tbox.y1 = sy1;
 	tbox.x2 = sx2;
 	tbox.y2 = sy2;
 
-	tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
-				       wl_fixed_from_int(es->geometry.height),
-				       es->buffer_transform, es->buffer_scale, tbox);
+	tbox = weston_transformed_rect(wl_fixed_from_int(ev->geometry.width),
+				       wl_fixed_from_int(ev->geometry.height),
+				       ev->surface->buffer_transform,
+				       ev->surface->buffer_scale, tbox);
 
 	s->src_x = tbox.x1 << 8;
 	s->src_y = tbox.y1 << 8;
@@ -942,8 +943,8 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base,
 }
 
 static struct weston_plane *
-drm_output_prepare_cursor_surface(struct weston_output *output_base,
-				  struct weston_surface *es)
+drm_output_prepare_cursor_view(struct weston_output *output_base,
+			       struct weston_view *ev)
 {
 	struct drm_compositor *c =
 		(struct drm_compositor *) output_base->compositor;
@@ -953,18 +954,18 @@ drm_output_prepare_cursor_surface(struct weston_output *output_base,
 		return NULL;
 	if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
 		return NULL;
-	if (output->cursor_surface)
+	if (output->cursor_view)
 		return NULL;
-	if (es->output_mask != (1u << output_base->id))
+	if (ev->output_mask != (1u << output_base->id))
 		return NULL;
 	if (c->cursors_are_broken)
 		return NULL;
-	if (es->buffer_ref.buffer == NULL ||
-	    !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
-	    es->geometry.width > 64 || es->geometry.height > 64)
+	if (ev->surface->buffer_ref.buffer == NULL ||
+	    !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
+	    ev->geometry.width > 64 || ev->geometry.height > 64)
 		return NULL;
 
-	output->cursor_surface = es;
+	output->cursor_view = ev;
 
 	return &output->cursor_plane;
 }
@@ -972,7 +973,7 @@ drm_output_prepare_cursor_surface(struct weston_output *output_base,
 static void
 drm_output_set_cursor(struct drm_output *output)
 {
-	struct weston_surface *es = output->cursor_surface;
+	struct weston_view *ev = output->cursor_view;
 	struct drm_compositor *c =
 		(struct drm_compositor *) output->base.compositor;
 	EGLint handle, stride;
@@ -981,24 +982,24 @@ drm_output_set_cursor(struct drm_output *output)
 	unsigned char *s;
 	int i, x, y;
 
-	output->cursor_surface = NULL;
-	if (es == NULL) {
+	output->cursor_view = NULL;
+	if (ev == NULL) {
 		drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
 		return;
 	}
 
-	if (es->buffer_ref.buffer &&
+	if (ev->surface->buffer_ref.buffer &&
 	    pixman_region32_not_empty(&output->cursor_plane.damage)) {
 		pixman_region32_fini(&output->cursor_plane.damage);
 		pixman_region32_init(&output->cursor_plane.damage);
 		output->current_cursor ^= 1;
 		bo = output->cursor_bo[output->current_cursor];
 		memset(buf, 0, sizeof buf);
-		stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
-		s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
-		for (i = 0; i < es->geometry.height; i++)
+		stride = wl_shm_buffer_get_stride(ev->surface->buffer_ref.buffer->shm_buffer);
+		s = wl_shm_buffer_get_data(ev->surface->buffer_ref.buffer->shm_buffer);
+		for (i = 0; i < ev->geometry.height; i++)
 			memcpy(buf + i * 64, s + i * stride,
-			       es->geometry.width * 4);
+			       ev->geometry.width * 4);
 
 		if (gbm_bo_write(bo, buf, sizeof buf) < 0)
 			weston_log("failed update cursor: %m\n");
@@ -1011,8 +1012,8 @@ drm_output_set_cursor(struct drm_output *output)
 		}
 	}
 
-	x = (es->geometry.x - output->base.x) * output->base.current_scale;
-	y = (es->geometry.y - output->base.y) * output->base.current_scale;
+	x = (ev->geometry.x - output->base.x) * output->base.current_scale;
+	y = (ev->geometry.y - output->base.y) * output->base.current_scale;
 	if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
 		if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
 			weston_log("failed to move cursor: %m\n");
@@ -1029,7 +1030,7 @@ drm_assign_planes(struct weston_output *output)
 {
 	struct drm_compositor *c =
 		(struct drm_compositor *) output->compositor;
-	struct weston_surface *es, *next;
+	struct weston_view *ev, *next;
 	pixman_region32_t overlap, surface_overlap;
 	struct weston_plane *primary, *next_plane;
 
@@ -1048,36 +1049,39 @@ drm_assign_planes(struct weston_output *output)
 	 */
 	pixman_region32_init(&overlap);
 	primary = &c->base.primary_plane;
-	wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
+
+	/* Flag all visible surfaces as keep_buffer = 1 */
+	wl_list_for_each(ev, &c->base.view_list, link)
+		ev->surface->keep_buffer = 1;
+
+	wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
 		/* test whether this buffer can ever go into a plane:
 		 * non-shm, or small enough to be a cursor
 		 */
-		if ((es->buffer_ref.buffer &&
-		     !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
-		    (es->geometry.width <= 64 && es->geometry.height <= 64))
-			es->keep_buffer = 1;
-		else
-			es->keep_buffer = 0;
+		if (!ev->surface->buffer_ref.buffer ||
+		    (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) &&
+		    (ev->geometry.width > 64 || ev->geometry.height > 64)))
+			ev->surface->keep_buffer = 0;
 
 		pixman_region32_init(&surface_overlap);
 		pixman_region32_intersect(&surface_overlap, &overlap,
-					  &es->transform.boundingbox);
+					  &ev->transform.boundingbox);
 
 		next_plane = NULL;
 		if (pixman_region32_not_empty(&surface_overlap))
 			next_plane = primary;
 		if (next_plane == NULL)
-			next_plane = drm_output_prepare_cursor_surface(output, es);
+			next_plane = drm_output_prepare_cursor_view(output, ev);
 		if (next_plane == NULL)
-			next_plane = drm_output_prepare_scanout_surface(output, es);
+			next_plane = drm_output_prepare_scanout_view(output, ev);
 		if (next_plane == NULL)
-			next_plane = drm_output_prepare_overlay_surface(output, es);
+			next_plane = drm_output_prepare_overlay_view(output, ev);
 		if (next_plane == NULL)
 			next_plane = primary;
-		weston_surface_move_to_plane(es, next_plane);
+		weston_view_move_to_plane(ev, next_plane);
 		if (next_plane == primary)
 			pixman_region32_union(&overlap, &overlap,
-					      &es->transform.boundingbox);
+					      &ev->transform.boundingbox);
 
 		pixman_region32_fini(&surface_overlap);
 	}
diff --git a/src/compositor.c b/src/compositor.c
index 3a028bc28a33876dc957025acb8e2957ddacfd14..11f582e7113b291f83a073cdd441d27d23249d7c 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -93,7 +93,7 @@ weston_output_transform_scale_init(struct weston_output *output,
 				   uint32_t transform, uint32_t scale);
 
 static void
-weston_compositor_build_surface_list(struct weston_compositor *compositor);
+weston_compositor_build_view_list(struct weston_compositor *compositor);
 
 WL_EXPORT int
 weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode,
@@ -347,6 +347,50 @@ region_init_infinite(pixman_region32_t *region)
 static struct weston_subsurface *
 weston_surface_to_subsurface(struct weston_surface *surface);
 
+WL_EXPORT struct weston_view *
+weston_view_create(struct weston_surface *surface)
+{
+	struct weston_view *view;
+
+	view = calloc(1, sizeof *view);
+	if (view == NULL)
+		return NULL;
+
+	view->surface = surface;
+
+	if (surface->compositor->renderer->create_view &&
+	    surface->compositor->renderer->create_view(view) < 0) {
+		free(view);
+		return NULL;
+	}
+
+	/* Assign to surface */
+	wl_list_insert(&surface->views, &view->surface_link);
+
+	wl_signal_init(&view->destroy_signal);
+	wl_list_init(&view->link);
+	wl_list_init(&view->layer_link);
+
+	view->plane = &surface->compositor->primary_plane;
+
+	pixman_region32_init(&view->clip);
+
+	view->alpha = 1.0;
+	pixman_region32_init(&view->transform.opaque);
+
+	wl_list_init(&view->geometry.transformation_list);
+	wl_list_insert(&view->geometry.transformation_list,
+		       &view->transform.position.link);
+	weston_matrix_init(&view->transform.position.matrix);
+	wl_list_init(&view->geometry.child_list);
+	pixman_region32_init(&view->transform.boundingbox);
+	view->transform.dirty = 1;
+
+	view->output = NULL;
+
+	return view;
+}
+
 WL_EXPORT struct weston_surface *
 weston_surface_create(struct weston_compositor *compositor)
 {
@@ -360,11 +404,7 @@ weston_surface_create(struct weston_compositor *compositor)
 
 	surface->resource = NULL;
 
-	wl_list_init(&surface->link);
-	wl_list_init(&surface->layer_link);
-
 	surface->compositor = compositor;
-	surface->alpha = 1.0;
 	surface->ref_count = 1;
 
 	if (compositor->renderer->create_surface(surface) < 0) {
@@ -377,23 +417,15 @@ weston_surface_create(struct weston_compositor *compositor)
 	surface->pending.buffer_transform = surface->buffer_transform;
 	surface->pending.buffer_scale = surface->buffer_scale;
 	surface->output = NULL;
-	surface->plane = &compositor->primary_plane;
 	surface->pending.newly_attached = 0;
 
 	pixman_region32_init(&surface->damage);
 	pixman_region32_init(&surface->opaque);
-	pixman_region32_init(&surface->clip);
 	region_init_infinite(&surface->input);
-	pixman_region32_init(&surface->transform.opaque);
-	wl_list_init(&surface->frame_callback_list);
 
-	wl_list_init(&surface->geometry.transformation_list);
-	wl_list_insert(&surface->geometry.transformation_list,
-		       &surface->transform.position.link);
-	weston_matrix_init(&surface->transform.position.matrix);
-	wl_list_init(&surface->geometry.child_list);
-	pixman_region32_init(&surface->transform.boundingbox);
-	surface->transform.dirty = 1;
+	wl_list_init(&surface->views);
+
+	wl_list_init(&surface->frame_callback_list);
 
 	surface->pending.buffer_destroy_listener.notify =
 		surface_handle_pending_buffer_destroy;
@@ -416,13 +448,13 @@ weston_surface_set_color(struct weston_surface *surface,
 }
 
 WL_EXPORT void
-weston_surface_to_global_float(struct weston_surface *surface,
-			       float sx, float sy, float *x, float *y)
+weston_view_to_global_float(struct weston_view *view,
+			    float sx, float sy, float *x, float *y)
 {
-	if (surface->transform.enabled) {
+	if (view->transform.enabled) {
 		struct weston_vector v = { { sx, sy, 0.0f, 1.0f } };
 
-		weston_matrix_transform(&surface->transform.matrix, &v);
+		weston_matrix_transform(&view->transform.matrix, &v);
 
 		if (fabsf(v.f[3]) < 1e-6) {
 			weston_log("warning: numerical instability in "
@@ -436,8 +468,8 @@ weston_surface_to_global_float(struct weston_surface *surface,
 		*x = v.f[0] / v.f[3];
 		*y = v.f[1] / v.f[3];
 	} else {
-		*x = sx + surface->geometry.x;
-		*y = sy + surface->geometry.y;
+		*x = sx + view->geometry.x;
+		*y = sy + view->geometry.y;
 	}
 }
 
@@ -525,8 +557,8 @@ WL_EXPORT void
 weston_surface_to_buffer_float(struct weston_surface *surface,
 			       float sx, float sy, float *bx, float *by)
 {
-	weston_transformed_coord(surface->geometry.width,
-				 surface->geometry.height,
+	weston_transformed_coord(surface->width,
+				 surface->height,
 				 surface->buffer_transform,
 				 surface->buffer_scale,
 				 sx, sy, bx, by);
@@ -538,8 +570,8 @@ weston_surface_to_buffer(struct weston_surface *surface,
 {
 	float bxf, byf;
 
-	weston_transformed_coord(surface->geometry.width,
-				 surface->geometry.height,
+	weston_transformed_coord(surface->width,
+				 surface->height,
 				 surface->buffer_transform,
 				 surface->buffer_scale,
 				 sx, sy, &bxf, &byf);
@@ -551,35 +583,35 @@ WL_EXPORT pixman_box32_t
 weston_surface_to_buffer_rect(struct weston_surface *surface,
 			      pixman_box32_t rect)
 {
-	return weston_transformed_rect(surface->geometry.width,
-				       surface->geometry.height,
+	return weston_transformed_rect(surface->width,
+				       surface->height,
 				       surface->buffer_transform,
 				       surface->buffer_scale,
 				       rect);
 }
 
 WL_EXPORT void
-weston_surface_move_to_plane(struct weston_surface *surface,
+weston_view_move_to_plane(struct weston_view *view,
 			     struct weston_plane *plane)
 {
-	if (surface->plane == plane)
+	if (view->plane == plane)
 		return;
 
-	weston_surface_damage_below(surface);
-	surface->plane = plane;
-	weston_surface_damage(surface);
+	weston_view_damage_below(view);
+	view->plane = plane;
+	weston_surface_damage(view->surface);
 }
 
 WL_EXPORT void
-weston_surface_damage_below(struct weston_surface *surface)
+weston_view_damage_below(struct weston_view *view)
 {
 	pixman_region32_t damage;
 
 	pixman_region32_init(&damage);
-	pixman_region32_subtract(&damage, &surface->transform.boundingbox,
-				 &surface->clip);
-	pixman_region32_union(&surface->plane->damage,
-			      &surface->plane->damage, &damage);
+	pixman_region32_subtract(&damage, &view->transform.boundingbox,
+				 &view->clip);
+	pixman_region32_union(&view->plane->damage,
+			      &view->plane->damage, &damage);
 	pixman_region32_fini(&damage);
 }
 
@@ -618,7 +650,43 @@ weston_surface_update_output_mask(struct weston_surface *es, uint32_t mask)
 static void
 weston_surface_assign_output(struct weston_surface *es)
 {
-	struct weston_compositor *ec = es->compositor;
+	struct weston_output *new_output;
+	struct weston_view *view;
+	pixman_region32_t region;
+	uint32_t max, area, mask;
+	pixman_box32_t *e;
+
+	new_output = NULL;
+	max = 0;
+	mask = 0;
+	pixman_region32_init(&region);
+	wl_list_for_each(view, &es->views, surface_link) {
+		if (!view->output)
+			continue;
+
+		pixman_region32_intersect(&region, &view->transform.boundingbox,
+					  &view->output->region);
+
+		e = pixman_region32_extents(&region);
+		area = (e->x2 - e->x1) * (e->y2 - e->y1);
+
+		mask |= view->output_mask;
+
+		if (area >= max) {
+			new_output = view->output;
+			max = area;
+		}
+	}
+	pixman_region32_fini(&region);
+
+	es->output = new_output;
+	weston_surface_update_output_mask(es, mask);
+}
+
+static void
+weston_view_assign_output(struct weston_view *ev)
+{
+	struct weston_compositor *ec = ev->surface->compositor;
 	struct weston_output *output, *new_output;
 	pixman_region32_t region;
 	uint32_t max, area, mask;
@@ -629,7 +697,7 @@ weston_surface_assign_output(struct weston_surface *es)
 	mask = 0;
 	pixman_region32_init(&region);
 	wl_list_for_each(output, &ec->output_list, link) {
-		pixman_region32_intersect(&region, &es->transform.boundingbox,
+		pixman_region32_intersect(&region, &ev->transform.boundingbox,
 					  &output->region);
 
 		e = pixman_region32_extents(&region);
@@ -645,14 +713,16 @@ weston_surface_assign_output(struct weston_surface *es)
 	}
 	pixman_region32_fini(&region);
 
-	es->output = new_output;
-	weston_surface_update_output_mask(es, mask);
+	ev->output = new_output;
+	ev->output_mask = mask;
+
+	weston_surface_assign_output(ev->surface);
 }
 
 static void
-surface_compute_bbox(struct weston_surface *surface, int32_t sx, int32_t sy,
-		     int32_t width, int32_t height,
-		     pixman_region32_t *bbox)
+view_compute_bbox(struct weston_view *view, int32_t sx, int32_t sy,
+		  int32_t width, int32_t height,
+		  pixman_region32_t *bbox)
 {
 	float min_x = HUGE_VALF,  min_y = HUGE_VALF;
 	float max_x = -HUGE_VALF, max_y = -HUGE_VALF;
@@ -673,8 +743,7 @@ surface_compute_bbox(struct weston_surface *surface, int32_t sx, int32_t sy,
 
 	for (i = 0; i < 4; ++i) {
 		float x, y;
-		weston_surface_to_global_float(surface,
-					       s[i][0], s[i][1], &x, &y);
+		weston_view_to_global_float(view, s[i][0], s[i][1], &x, &y);
 		if (x < min_x)
 			min_x = x;
 		if (x > max_x)
@@ -692,57 +761,57 @@ surface_compute_bbox(struct weston_surface *surface, int32_t sx, int32_t sy,
 }
 
 static void
-weston_surface_update_transform_disable(struct weston_surface *surface)
+weston_view_update_transform_disable(struct weston_view *view)
 {
-	surface->transform.enabled = 0;
+	view->transform.enabled = 0;
 
 	/* round off fractions when not transformed */
-	surface->geometry.x = roundf(surface->geometry.x);
-	surface->geometry.y = roundf(surface->geometry.y);
+	view->geometry.x = roundf(view->geometry.x);
+	view->geometry.y = roundf(view->geometry.y);
 
 	/* Otherwise identity matrix, but with x and y translation. */
-	surface->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
-	surface->transform.position.matrix.d[12] = surface->geometry.x;
-	surface->transform.position.matrix.d[13] = surface->geometry.y;
+	view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
+	view->transform.position.matrix.d[12] = view->geometry.x;
+	view->transform.position.matrix.d[13] = view->geometry.y;
 
-	surface->transform.matrix = surface->transform.position.matrix;
+	view->transform.matrix = view->transform.position.matrix;
 
-	surface->transform.inverse = surface->transform.position.matrix;
-	surface->transform.inverse.d[12] = -surface->geometry.x;
-	surface->transform.inverse.d[13] = -surface->geometry.y;
+	view->transform.inverse = view->transform.position.matrix;
+	view->transform.inverse.d[12] = -view->geometry.x;
+	view->transform.inverse.d[13] = -view->geometry.y;
 
-	pixman_region32_init_rect(&surface->transform.boundingbox,
-				  surface->geometry.x,
-				  surface->geometry.y,
-				  surface->geometry.width,
-				  surface->geometry.height);
+	pixman_region32_init_rect(&view->transform.boundingbox,
+				  view->geometry.x,
+				  view->geometry.y,
+				  view->geometry.width,
+				  view->geometry.height);
 
-	if (surface->alpha == 1.0) {
-		pixman_region32_copy(&surface->transform.opaque,
-				     &surface->opaque);
-		pixman_region32_translate(&surface->transform.opaque,
-					  surface->geometry.x,
-					  surface->geometry.y);
+	if (view->alpha == 1.0) {
+		pixman_region32_copy(&view->transform.opaque,
+				     &view->surface->opaque);
+		pixman_region32_translate(&view->transform.opaque,
+					  view->geometry.x,
+					  view->geometry.y);
 	}
 }
 
 static int
-weston_surface_update_transform_enable(struct weston_surface *surface)
+weston_view_update_transform_enable(struct weston_view *view)
 {
-	struct weston_surface *parent = surface->geometry.parent;
-	struct weston_matrix *matrix = &surface->transform.matrix;
-	struct weston_matrix *inverse = &surface->transform.inverse;
+	struct weston_view *parent = view->geometry.parent;
+	struct weston_matrix *matrix = &view->transform.matrix;
+	struct weston_matrix *inverse = &view->transform.inverse;
 	struct weston_transform *tform;
 
-	surface->transform.enabled = 1;
+	view->transform.enabled = 1;
 
 	/* Otherwise identity matrix, but with x and y translation. */
-	surface->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
-	surface->transform.position.matrix.d[12] = surface->geometry.x;
-	surface->transform.position.matrix.d[13] = surface->geometry.y;
+	view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
+	view->transform.position.matrix.d[12] = view->geometry.x;
+	view->transform.position.matrix.d[13] = view->geometry.y;
 
 	weston_matrix_init(matrix);
-	wl_list_for_each(tform, &surface->geometry.transformation_list, link)
+	wl_list_for_each(tform, &view->geometry.transformation_list, link)
 		weston_matrix_multiply(matrix, &tform->matrix);
 
 	if (parent)
@@ -750,143 +819,144 @@ weston_surface_update_transform_enable(struct weston_surface *surface)
 
 	if (weston_matrix_invert(inverse, matrix) < 0) {
 		/* Oops, bad total transformation, not invertible */
-		weston_log("error: weston_surface %p"
-			" transformation not invertible.\n", surface);
+		weston_log("error: weston_view %p"
+			" transformation not invertible.\n", view);
 		return -1;
 	}
 
-	surface_compute_bbox(surface, 0, 0, surface->geometry.width,
-			     surface->geometry.height,
-			     &surface->transform.boundingbox);
+	view_compute_bbox(view, 0, 0, view->geometry.width,
+			  view->geometry.height,
+			  &view->transform.boundingbox);
 
 	return 0;
 }
 
 WL_EXPORT void
-weston_surface_update_transform(struct weston_surface *surface)
+weston_view_update_transform(struct weston_view *view)
 {
-	struct weston_surface *parent = surface->geometry.parent;
+	struct weston_view *parent = view->geometry.parent;
 
-	if (!surface->transform.dirty)
+	if (!view->transform.dirty)
 		return;
 
 	if (parent)
-		weston_surface_update_transform(parent);
+		weston_view_update_transform(parent);
 
-	surface->transform.dirty = 0;
+	view->transform.dirty = 0;
 
-	weston_surface_damage_below(surface);
+	weston_view_damage_below(view);
 
-	pixman_region32_fini(&surface->transform.boundingbox);
-	pixman_region32_fini(&surface->transform.opaque);
-	pixman_region32_init(&surface->transform.opaque);
+	pixman_region32_fini(&view->transform.boundingbox);
+	pixman_region32_fini(&view->transform.opaque);
+	pixman_region32_init(&view->transform.opaque);
 
 	/* transform.position is always in transformation_list */
-	if (surface->geometry.transformation_list.next ==
-	    &surface->transform.position.link &&
-	    surface->geometry.transformation_list.prev ==
-	    &surface->transform.position.link &&
+	if (view->geometry.transformation_list.next ==
+	    &view->transform.position.link &&
+	    view->geometry.transformation_list.prev ==
+	    &view->transform.position.link &&
 	    !parent) {
-		weston_surface_update_transform_disable(surface);
+		weston_view_update_transform_disable(view);
 	} else {
-		if (weston_surface_update_transform_enable(surface) < 0)
-			weston_surface_update_transform_disable(surface);
+		if (weston_view_update_transform_enable(view) < 0)
+			weston_view_update_transform_disable(view);
 	}
 
-	weston_surface_damage_below(surface);
+	weston_view_damage_below(view);
 
-	weston_surface_assign_output(surface);
+	weston_view_assign_output(view);
 
-	wl_signal_emit(&surface->compositor->transform_signal, surface);
+	wl_signal_emit(&view->surface->compositor->transform_signal,
+		       view->surface);
 }
 
 WL_EXPORT void
-weston_surface_geometry_dirty(struct weston_surface *surface)
+weston_view_geometry_dirty(struct weston_view *view)
 {
-	struct weston_surface *child;
+	struct weston_view *child;
 
 	/*
-	 * The invariant: if surface->geometry.dirty, then all surfaces
-	 * in surface->geometry.child_list have geometry.dirty too.
+	 * The invariant: if view->geometry.dirty, then all views
+	 * in view->geometry.child_list have geometry.dirty too.
 	 * Corollary: if not parent->geometry.dirty, then all ancestors
 	 * are not dirty.
 	 */
 
-	if (surface->transform.dirty)
+	if (view->transform.dirty)
 		return;
 
-	surface->transform.dirty = 1;
+	view->transform.dirty = 1;
 
-	wl_list_for_each(child, &surface->geometry.child_list,
+	wl_list_for_each(child, &view->geometry.child_list,
 			 geometry.parent_link)
-		weston_surface_geometry_dirty(child);
+		weston_view_geometry_dirty(child);
 }
 
 WL_EXPORT void
-weston_surface_to_global_fixed(struct weston_surface *surface,
-			       wl_fixed_t sx, wl_fixed_t sy,
-			       wl_fixed_t *x, wl_fixed_t *y)
+weston_view_to_global_fixed(struct weston_view *view,
+			    wl_fixed_t vx, wl_fixed_t vy,
+			    wl_fixed_t *x, wl_fixed_t *y)
 {
 	float xf, yf;
 
-	weston_surface_to_global_float(surface,
-	                               wl_fixed_to_double(sx),
-				       wl_fixed_to_double(sy),
-				       &xf, &yf);
+	weston_view_to_global_float(view,
+				    wl_fixed_to_double(vx),
+				    wl_fixed_to_double(vy),
+				    &xf, &yf);
 	*x = wl_fixed_from_double(xf);
 	*y = wl_fixed_from_double(yf);
 }
 
 WL_EXPORT void
-weston_surface_from_global_float(struct weston_surface *surface,
-				 float x, float y, float *sx, float *sy)
+weston_view_from_global_float(struct weston_view *view,
+			      float x, float y, float *vx, float *vy)
 {
-	if (surface->transform.enabled) {
+	if (view->transform.enabled) {
 		struct weston_vector v = { { x, y, 0.0f, 1.0f } };
 
-		weston_matrix_transform(&surface->transform.inverse, &v);
+		weston_matrix_transform(&view->transform.inverse, &v);
 
 		if (fabsf(v.f[3]) < 1e-6) {
 			weston_log("warning: numerical instability in "
-				"weston_surface_from_global(), divisor = %g\n",
+				"weston_view_from_global(), divisor = %g\n",
 				v.f[3]);
-			*sx = 0;
-			*sy = 0;
+			*vx = 0;
+			*vy = 0;
 			return;
 		}
 
-		*sx = v.f[0] / v.f[3];
-		*sy = v.f[1] / v.f[3];
+		*vx = v.f[0] / v.f[3];
+		*vy = v.f[1] / v.f[3];
 	} else {
-		*sx = x - surface->geometry.x;
-		*sy = y - surface->geometry.y;
+		*vx = x - view->geometry.x;
+		*vy = y - view->geometry.y;
 	}
 }
 
 WL_EXPORT void
-weston_surface_from_global_fixed(struct weston_surface *surface,
-			         wl_fixed_t x, wl_fixed_t y,
-			         wl_fixed_t *sx, wl_fixed_t *sy)
+weston_view_from_global_fixed(struct weston_view *view,
+			      wl_fixed_t x, wl_fixed_t y,
+			      wl_fixed_t *vx, wl_fixed_t *vy)
 {
-	float sxf, syf;
+	float vxf, vyf;
 
-	weston_surface_from_global_float(surface,
-					 wl_fixed_to_double(x),
-					 wl_fixed_to_double(y),
-					 &sxf, &syf);
-	*sx = wl_fixed_from_double(sxf);
-	*sy = wl_fixed_from_double(syf);
+	weston_view_from_global_float(view,
+				      wl_fixed_to_double(x),
+				      wl_fixed_to_double(y),
+				      &vxf, &vyf);
+	*vx = wl_fixed_from_double(vxf);
+	*vy = wl_fixed_from_double(vyf);
 }
 
 WL_EXPORT void
-weston_surface_from_global(struct weston_surface *surface,
-			   int32_t x, int32_t y, int32_t *sx, int32_t *sy)
+weston_view_from_global(struct weston_view *view,
+			int32_t x, int32_t y, int32_t *vx, int32_t *vy)
 {
-	float sxf, syf;
+	float vxf, vyf;
 
-	weston_surface_from_global_float(surface, x, y, &sxf, &syf);
-	*sx = floorf(sxf);
-	*sy = floorf(syf);
+	weston_view_from_global_float(view, x, y, &vxf, &vyf);
+	*vx = floorf(vxf);
+	*vy = floorf(vyf);
 }
 
 WL_EXPORT void
@@ -899,68 +969,86 @@ weston_surface_schedule_repaint(struct weston_surface *surface)
 			weston_output_schedule_repaint(output);
 }
 
+WL_EXPORT void
+weston_view_schedule_repaint(struct weston_view *view)
+{
+	struct weston_output *output;
+
+	wl_list_for_each(output, &view->surface->compositor->output_list, link)
+		if (view->output_mask & (1 << output->id))
+			weston_output_schedule_repaint(output);
+}
+
 WL_EXPORT void
 weston_surface_damage(struct weston_surface *surface)
 {
 	pixman_region32_union_rect(&surface->damage, &surface->damage,
-				   0, 0, surface->geometry.width,
-				   surface->geometry.height);
+				   0, 0, surface->width,
+				   surface->height);
 
 	weston_surface_schedule_repaint(surface);
 }
 
 WL_EXPORT void
-weston_surface_configure(struct weston_surface *surface,
-			 float x, float y, int width, int height)
+weston_view_configure(struct weston_view *view,
+		      float x, float y, int width, int height)
 {
-	surface->geometry.x = x;
-	surface->geometry.y = y;
-	surface->geometry.width = width;
-	surface->geometry.height = height;
-	weston_surface_geometry_dirty(surface);
+	view->geometry.x = x;
+	view->geometry.y = y;
+	view->geometry.width = width;
+	view->geometry.height = height;
+	weston_view_geometry_dirty(view);
 }
 
 WL_EXPORT void
-weston_surface_set_position(struct weston_surface *surface,
-			    float x, float y)
+weston_view_set_position(struct weston_view *view, float x, float y)
 {
-	surface->geometry.x = x;
-	surface->geometry.y = y;
-	weston_surface_geometry_dirty(surface);
+	view->geometry.x = x;
+	view->geometry.y = y;
+	weston_view_geometry_dirty(view);
 }
 
 static void
 transform_parent_handle_parent_destroy(struct wl_listener *listener,
 				       void *data)
 {
-	struct weston_surface *surface =
-		container_of(listener, struct weston_surface,
+	struct weston_view *view =
+		container_of(listener, struct weston_view,
 			     geometry.parent_destroy_listener);
 
-	weston_surface_set_transform_parent(surface, NULL);
+	weston_view_set_transform_parent(view, NULL);
 }
 
 WL_EXPORT void
-weston_surface_set_transform_parent(struct weston_surface *surface,
-				    struct weston_surface *parent)
+weston_view_set_transform_parent(struct weston_view *view,
+				    struct weston_view *parent)
 {
-	if (surface->geometry.parent) {
-		wl_list_remove(&surface->geometry.parent_destroy_listener.link);
-		wl_list_remove(&surface->geometry.parent_link);
+	if (view->geometry.parent) {
+		wl_list_remove(&view->geometry.parent_destroy_listener.link);
+		wl_list_remove(&view->geometry.parent_link);
 	}
 
-	surface->geometry.parent = parent;
+	view->geometry.parent = parent;
 
-	surface->geometry.parent_destroy_listener.notify =
+	view->geometry.parent_destroy_listener.notify =
 		transform_parent_handle_parent_destroy;
 	if (parent) {
 		wl_signal_add(&parent->destroy_signal,
-			      &surface->geometry.parent_destroy_listener);
+			      &view->geometry.parent_destroy_listener);
 		wl_list_insert(&parent->geometry.child_list,
-			       &surface->geometry.parent_link);
+			       &view->geometry.parent_link);
 	}
 
-	weston_surface_geometry_dirty(surface);
+	weston_view_geometry_dirty(view);
+}
+
+WL_EXPORT int
+weston_view_is_mapped(struct weston_view *view)
+{
+	if (view->output)
+		return 1;
+	else
+		return 0;
 }
 
 WL_EXPORT int
@@ -1018,20 +1106,20 @@ weston_compositor_get_time(void)
        return tv.tv_sec * 1000 + tv.tv_usec / 1000;
 }
 
-WL_EXPORT struct weston_surface *
-weston_compositor_pick_surface(struct weston_compositor *compositor,
-			       wl_fixed_t x, wl_fixed_t y,
-			       wl_fixed_t *sx, wl_fixed_t *sy)
+WL_EXPORT struct weston_view *
+weston_compositor_pick_view(struct weston_compositor *compositor,
+			    wl_fixed_t x, wl_fixed_t y,
+			    wl_fixed_t *vx, wl_fixed_t *vy)
 {
-	struct weston_surface *surface;
+	struct weston_view *view;
 
-	wl_list_for_each(surface, &compositor->surface_list, link) {
-		weston_surface_from_global_fixed(surface, x, y, sx, sy);
-		if (pixman_region32_contains_point(&surface->input,
-						   wl_fixed_to_int(*sx),
-						   wl_fixed_to_int(*sy),
+	wl_list_for_each(view, &compositor->view_list, link) {
+		weston_view_from_global_fixed(view, x, y, vx, vy);
+		if (pixman_region32_contains_point(&view->surface->input,
+						   wl_fixed_to_int(*vx),
+						   wl_fixed_to_int(*vy),
 						   NULL))
-			return surface;
+			return view;
 	}
 
 	return NULL;
@@ -1050,29 +1138,48 @@ weston_compositor_repick(struct weston_compositor *compositor)
 }
 
 WL_EXPORT void
-weston_surface_unmap(struct weston_surface *surface)
+weston_view_unmap(struct weston_view *view)
 {
 	struct weston_seat *seat;
 
-	weston_surface_damage_below(surface);
-	surface->output = NULL;
-	wl_list_remove(&surface->layer_link);
-	wl_list_remove(&surface->link);
-	wl_list_init(&surface->link);
+	if (!weston_view_is_mapped(view))
+		return;
+
+	weston_view_damage_below(view);
+	view->output = NULL;
+	wl_list_remove(&view->layer_link);
+	wl_list_init(&view->layer_link);
+	wl_list_remove(&view->link);
+	wl_list_init(&view->link);
+	/* We need to do this before torching the output mask */
+	weston_view_schedule_repaint(view);
+	view->output_mask = 0;
+	weston_surface_assign_output(view->surface);
+
+	if (weston_surface_is_mapped(view->surface))
+		return;
 
-	wl_list_for_each(seat, &surface->compositor->seat_list, link) {
-		if (seat->keyboard && seat->keyboard->focus == surface)
+	wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
+		if (seat->keyboard && seat->keyboard->focus == view->surface)
 			weston_keyboard_set_focus(seat->keyboard, NULL);
-		if (seat->pointer && seat->pointer->focus == surface)
+		if (seat->pointer && seat->pointer->focus == view)
 			weston_pointer_set_focus(seat->pointer,
 						 NULL,
 						 wl_fixed_from_int(0),
 						 wl_fixed_from_int(0));
-		if (seat->touch && seat->touch->focus == surface)
+		if (seat->touch && seat->touch->focus == view)
 			weston_touch_set_focus(seat, NULL);
 	}
+}
 
-	weston_surface_schedule_repaint(surface);
+WL_EXPORT void
+weston_surface_unmap(struct weston_surface *surface)
+{
+	struct weston_view *view;
+
+	wl_list_for_each(view, &surface->views, surface_link)
+		weston_view_unmap(view);
+	surface->output = NULL;
 }
 
 struct weston_frame_callback {
@@ -1080,24 +1187,51 @@ struct weston_frame_callback {
 	struct wl_list link;
 };
 
+WL_EXPORT void
+weston_view_destroy(struct weston_view *view)
+{
+	wl_signal_emit(&view->destroy_signal, view);
+
+	assert(wl_list_empty(&view->geometry.child_list));
+
+	if (weston_view_is_mapped(view)) {
+		weston_view_unmap(view);
+		weston_compositor_build_view_list(view->surface->compositor);
+	}
+
+	wl_list_remove(&view->link);
+	wl_list_remove(&view->layer_link);
+
+	pixman_region32_fini(&view->clip);
+	pixman_region32_fini(&view->transform.boundingbox);
+
+	weston_view_set_transform_parent(view, NULL);
+
+	if (view->surface->compositor->renderer->destroy_view)
+		view->surface->compositor->renderer->destroy_view(view);
+
+	wl_list_remove(&view->surface_link);
+
+	free(view);
+}
 
 WL_EXPORT void
 weston_surface_destroy(struct weston_surface *surface)
 {
 	struct weston_compositor *compositor = surface->compositor;
 	struct weston_frame_callback *cb, *next;
+	struct weston_view *ev, *nv;
 
 	if (--surface->ref_count > 0)
 		return;
 
 	wl_signal_emit(&surface->destroy_signal, &surface->resource);
 
-	assert(wl_list_empty(&surface->geometry.child_list));
 	assert(wl_list_empty(&surface->subsurface_list_pending));
 	assert(wl_list_empty(&surface->subsurface_list));
 
-	if (weston_surface_is_mapped(surface))
-		weston_surface_unmap(surface);
+	wl_list_for_each_safe(ev, nv, &surface->views, surface_link)
+		weston_view_destroy(ev);
 
 	wl_list_for_each_safe(cb, next,
 			      &surface->pending.frame_callback_list, link)
@@ -1114,17 +1248,13 @@ weston_surface_destroy(struct weston_surface *surface)
 
 	compositor->renderer->destroy_surface(surface);
 
-	pixman_region32_fini(&surface->transform.boundingbox);
 	pixman_region32_fini(&surface->damage);
 	pixman_region32_fini(&surface->opaque);
-	pixman_region32_fini(&surface->clip);
 	pixman_region32_fini(&surface->input);
 
 	wl_list_for_each_safe(cb, next, &surface->frame_callback_list, link)
 		wl_resource_destroy(cb->resource);
 
-	weston_surface_set_transform_parent(surface, NULL);
-
 	free(surface);
 }
 
@@ -1223,12 +1353,12 @@ weston_surface_attach(struct weston_surface *surface,
 }
 
 WL_EXPORT void
-weston_surface_restack(struct weston_surface *surface, struct wl_list *below)
+weston_view_restack(struct weston_view *view, struct wl_list *below)
 {
-	wl_list_remove(&surface->layer_link);
-	wl_list_insert(below, &surface->layer_link);
-	weston_surface_damage_below(surface);
-	weston_surface_damage(surface);
+	wl_list_remove(&view->layer_link);
+	wl_list_insert(below, &view->layer_link);
+	weston_view_damage_below(view);
+	weston_surface_damage(view->surface);
 }
 
 WL_EXPORT void
@@ -1252,43 +1382,53 @@ weston_output_damage(struct weston_output *output)
 }
 
 static void
-surface_accumulate_damage(struct weston_surface *surface,
-			  pixman_region32_t *opaque)
+surface_flush_damage(struct weston_surface *surface)
 {
 	if (surface->buffer_ref.buffer &&
 	    wl_shm_buffer_get(surface->buffer_ref.buffer->resource))
 		surface->compositor->renderer->flush_damage(surface);
 
-	if (surface->transform.enabled) {
+	empty_region(&surface->damage);
+}
+
+static void
+view_accumulate_damage(struct weston_view *view,
+		       pixman_region32_t *opaque)
+{
+	pixman_region32_t damage;
+
+	pixman_region32_init(&damage);
+	if (view->transform.enabled) {
 		pixman_box32_t *extents;
 
-		extents = pixman_region32_extents(&surface->damage);
-		surface_compute_bbox(surface, extents->x1, extents->y1,
-				     extents->x2 - extents->x1,
-				     extents->y2 - extents->y1,
-				     &surface->damage);
-		pixman_region32_translate(&surface->damage,
-					  -surface->plane->x,
-					  -surface->plane->y);
+		extents = pixman_region32_extents(&view->surface->damage);
+		view_compute_bbox(view, extents->x1, extents->y1,
+				  extents->x2 - extents->x1,
+				  extents->y2 - extents->y1,
+				  &damage);
+		pixman_region32_translate(&damage,
+					  -view->plane->x,
+					  -view->plane->y);
 	} else {
-		pixman_region32_translate(&surface->damage,
-					  surface->geometry.x - surface->plane->x,
-					  surface->geometry.y - surface->plane->y);
+		pixman_region32_copy(&damage, &view->surface->damage);
+		pixman_region32_translate(&damage,
+					  view->geometry.x - view->plane->x,
+					  view->geometry.y - view->plane->y);
 	}
 
-	pixman_region32_subtract(&surface->damage, &surface->damage, opaque);
-	pixman_region32_union(&surface->plane->damage,
-			      &surface->plane->damage, &surface->damage);
-	empty_region(&surface->damage);
-	pixman_region32_copy(&surface->clip, opaque);
-	pixman_region32_union(opaque, opaque, &surface->transform.opaque);
+	pixman_region32_subtract(&damage, &damage, opaque);
+	pixman_region32_union(&view->plane->damage,
+			      &view->plane->damage, &damage);
+	pixman_region32_fini(&damage);
+	pixman_region32_copy(&view->clip, opaque);
+	pixman_region32_union(opaque, opaque, &view->transform.opaque);
 }
 
 static void
 compositor_accumulate_damage(struct weston_compositor *ec)
 {
 	struct weston_plane *plane;
-	struct weston_surface *es;
+	struct weston_view *ev;
 	pixman_region32_t opaque, clip;
 
 	pixman_region32_init(&clip);
@@ -1298,11 +1438,11 @@ compositor_accumulate_damage(struct weston_compositor *ec)
 
 		pixman_region32_init(&opaque);
 
-		wl_list_for_each(es, &ec->surface_list, link) {
-			if (es->plane != plane)
+		wl_list_for_each(ev, &ec->view_list, link) {
+			if (ev->plane != plane)
 				continue;
 
-			surface_accumulate_damage(es, &opaque);
+			view_accumulate_damage(ev, &opaque);
 		}
 
 		pixman_region32_union(&clip, &clip, &opaque);
@@ -1311,7 +1451,16 @@ compositor_accumulate_damage(struct weston_compositor *ec)
 
 	pixman_region32_fini(&clip);
 
-	wl_list_for_each(es, &ec->surface_list, link) {
+	wl_list_for_each(ev, &ec->view_list, link)
+		ev->surface->touched = 0;
+
+	wl_list_for_each(ev, &ec->view_list, link) {
+		if (ev->surface->touched)
+			continue;
+		ev->surface->touched = 1;
+
+		surface_flush_damage(ev->surface);
+
 		/* Both the renderer and the backend have seen the buffer
 		 * by now. If renderer needs the buffer, it has its own
 		 * reference set. If the backend wants to keep the buffer
@@ -1320,56 +1469,122 @@ compositor_accumulate_damage(struct weston_compositor *ec)
 		 * reference now, and allow early buffer release. This enables
 		 * clients to use single-buffering.
 		 */
-		if (!es->keep_buffer)
-			weston_buffer_reference(&es->buffer_ref, NULL);
+		if (!ev->surface->keep_buffer)
+			weston_buffer_reference(&ev->surface->buffer_ref, NULL);
 	}
 }
 
 static void
-surface_list_add(struct weston_compositor *compositor,
-		 struct weston_surface *surface)
+surface_stash_subsurface_views(struct weston_surface *surface)
 {
 	struct weston_subsurface *sub;
 
-	if (wl_list_empty(&surface->subsurface_list)) {
-		weston_surface_update_transform(surface);
-		wl_list_insert(compositor->surface_list.prev, &surface->link);
-		return;
+	wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
+		if (sub->surface == surface)
+			continue;
+
+		wl_list_insert_list(&sub->unused_views, &sub->surface->views);
+		wl_list_init(&sub->surface->views);
+
+		surface_stash_subsurface_views(sub->surface);
 	}
+}
+
+static void
+surface_free_unused_subsurface_views(struct weston_surface *surface)
+{
+	struct weston_subsurface *sub;
+	struct weston_view *view, *nv;
 
 	wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
-		if (!weston_surface_is_mapped(sub->surface))
+		if (sub->surface == surface)
 			continue;
 
-		if (sub->surface == surface) {
-			weston_surface_update_transform(sub->surface);
-			wl_list_insert(compositor->surface_list.prev,
-				       &sub->surface->link);
-		} else {
-			surface_list_add(compositor, sub->surface);
+		wl_list_for_each_safe(view, nv, &sub->unused_views, surface_link)
+			weston_view_destroy(view);
+
+		surface_free_unused_subsurface_views(sub->surface);
+	}
+}
+
+static void
+view_list_add_subsurface_view(struct weston_compositor *compositor,
+			      struct weston_subsurface *sub,
+			      struct weston_view *parent)
+{
+	struct weston_subsurface *child;
+	struct weston_view *view = NULL, *iv;
+
+	wl_list_for_each(iv, &sub->unused_views, surface_link) {
+		if (iv->geometry.parent == parent) {
+			view = iv;
+			break;
 		}
 	}
+
+	if (view) {
+		/* Put it back in the surface's list of views */
+		wl_list_remove(&view->surface_link);
+		wl_list_insert(&sub->surface->views, &view->surface_link);
+	} else {
+		view = weston_view_create(sub->surface);
+		weston_view_configure(view,
+				      sub->position.x,
+				      sub->position.y,
+				      sub->surface->width,
+				      sub->surface->height);
+		weston_view_set_transform_parent(view, parent);
+	}
+
+	weston_view_update_transform(view);
+	wl_list_insert(compositor->view_list.next, &view->link);
+
+	wl_list_for_each(child, &sub->surface->subsurface_list, parent_link)
+		if (child->surface != sub->surface)
+			view_list_add_subsurface_view(compositor, child, view);
 }
 
 static void
-weston_compositor_build_surface_list(struct weston_compositor *compositor)
+view_list_add(struct weston_compositor *compositor,
+	      struct weston_view *view)
 {
-	struct weston_surface *surface;
+	struct weston_subsurface *sub;
+
+	weston_view_update_transform(view);
+	wl_list_insert(compositor->view_list.prev, &view->link);
+
+	wl_list_for_each(sub, &view->surface->subsurface_list, parent_link)
+		if (sub->surface != view->surface)
+			view_list_add_subsurface_view(compositor, sub, view);
+}
+
+static void
+weston_compositor_build_view_list(struct weston_compositor *compositor)
+{
+	struct weston_view *view;
 	struct weston_layer *layer;
 
-	wl_list_init(&compositor->surface_list);
+	wl_list_for_each(layer, &compositor->layer_list, link)
+		wl_list_for_each(view, &layer->view_list, layer_link)
+			surface_stash_subsurface_views(view->surface);
+
+	wl_list_init(&compositor->view_list);
 	wl_list_for_each(layer, &compositor->layer_list, link) {
-		wl_list_for_each(surface, &layer->surface_list, layer_link) {
-			surface_list_add(compositor, surface);
+		wl_list_for_each(view, &layer->view_list, layer_link) {
+			view_list_add(compositor, view);
 		}
 	}
+
+	wl_list_for_each(layer, &compositor->layer_list, link)
+		wl_list_for_each(view, &layer->view_list, layer_link)
+			surface_free_unused_subsurface_views(view->surface);
 }
 
 static int
 weston_output_repaint(struct weston_output *output, uint32_t msecs)
 {
 	struct weston_compositor *ec = output->compositor;
-	struct weston_surface *es;
+	struct weston_view *ev;
 	struct weston_animation *animation, *next;
 	struct weston_frame_callback *cb, *cnext;
 	struct wl_list frame_callback_list;
@@ -1377,20 +1592,23 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs)
 	int r;
 
 	/* Rebuild the surface list and update surface transforms up front. */
-	weston_compositor_build_surface_list(ec);
+	weston_compositor_build_view_list(ec);
 
 	if (output->assign_planes && !output->disable_planes)
 		output->assign_planes(output);
 	else
-		wl_list_for_each(es, &ec->surface_list, link)
-			weston_surface_move_to_plane(es, &ec->primary_plane);
+		wl_list_for_each(ev, &ec->view_list, link)
+			weston_view_move_to_plane(ev, &ec->primary_plane);
 
 	wl_list_init(&frame_callback_list);
-	wl_list_for_each(es, &ec->surface_list, link) {
-		if (es->output == output) {
+	wl_list_for_each(ev, &ec->view_list, link) {
+		/* Note: This operation is safe to do multiple times on the
+		 * same surface.
+		 */
+		if (ev->surface->output == output) {
 			wl_list_insert_list(&frame_callback_list,
-					    &es->frame_callback_list);
-			wl_list_init(&es->frame_callback_list);
+					    &ev->surface->frame_callback_list);
+			wl_list_init(&ev->surface->frame_callback_list);
 		}
 	}
 
@@ -1476,7 +1694,7 @@ idle_repaint(void *data)
 WL_EXPORT void
 weston_layer_init(struct weston_layer *layer, struct wl_list *below)
 {
-	wl_list_init(&layer->surface_list);
+	wl_list_init(&layer->view_list);
 	if (below != NULL)
 		wl_list_insert(below, &layer->link);
 }
@@ -1649,9 +1867,8 @@ weston_surface_commit_subsurface_order(struct weston_surface *surface)
 static void
 weston_surface_commit(struct weston_surface *surface)
 {
+	struct weston_view *view;
 	pixman_region32_t opaque;
-	int surface_width = 0;
-	int surface_height = 0;
 
 	/* wl_surface.set_buffer_transform */
 	surface->buffer_transform = surface->pending.buffer_transform;
@@ -1663,15 +1880,18 @@ weston_surface_commit(struct weston_surface *surface)
 	if (surface->pending.buffer || surface->pending.newly_attached)
 		weston_surface_attach(surface, surface->pending.buffer);
 
+	surface->width = 0;
+	surface->height = 0;
 	if (surface->buffer_ref.buffer) {
-		surface_width = weston_surface_buffer_width(surface);
-		surface_height = weston_surface_buffer_height(surface);
+		/* This already includes the buffer scale */
+		surface->width = weston_surface_buffer_width(surface);
+		surface->height = weston_surface_buffer_height(surface);
 	}
 
 	if (surface->configure && surface->pending.newly_attached)
 		surface->configure(surface,
 				   surface->pending.sx, surface->pending.sy,
-				   surface_width, surface_height);
+				   surface->width, surface->height);
 
 	if (surface->pending.buffer)
 		wl_list_remove(&surface->pending.buffer_destroy_listener.link);
@@ -1685,20 +1905,21 @@ weston_surface_commit(struct weston_surface *surface)
 			      &surface->pending.damage);
 	pixman_region32_intersect_rect(&surface->damage, &surface->damage,
 				       0, 0,
-				       surface->geometry.width,
-				       surface->geometry.height);
+				       surface->width,
+				       surface->height);
 	empty_region(&surface->pending.damage);
 
 	/* wl_surface.set_opaque_region */
 	pixman_region32_init_rect(&opaque, 0, 0,
-				  surface->geometry.width,
-				  surface->geometry.height);
+				  surface->width,
+				  surface->height);
 	pixman_region32_intersect(&opaque,
 				  &opaque, &surface->pending.opaque);
 
 	if (!pixman_region32_equal(&opaque, &surface->opaque)) {
 		pixman_region32_copy(&surface->opaque, &opaque);
-		weston_surface_geometry_dirty(surface);
+		wl_list_for_each(view, &surface->views, surface_link)
+			weston_view_geometry_dirty(view);
 	}
 
 	pixman_region32_fini(&opaque);
@@ -1706,8 +1927,8 @@ weston_surface_commit(struct weston_surface *surface)
 	/* wl_surface.set_input_region */
 	pixman_region32_fini(&surface->input);
 	pixman_region32_init_rect(&surface->input, 0, 0,
-				  surface->geometry.width,
-				  surface->geometry.height);
+				  surface->width,
+				  surface->height);
 	pixman_region32_intersect(&surface->input,
 				  &surface->input, &surface->pending.input);
 
@@ -1880,9 +2101,8 @@ static void
 weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
 {
 	struct weston_surface *surface = sub->surface;
+	struct weston_view *view;
 	pixman_region32_t opaque;
-	int surface_width = 0;
-	int surface_height = 0;
 
 	/* wl_surface.set_buffer_transform */
 	surface->buffer_transform = sub->cached.buffer_transform;
@@ -1895,14 +2115,16 @@ weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
 		weston_surface_attach(surface, sub->cached.buffer_ref.buffer);
 	weston_buffer_reference(&sub->cached.buffer_ref, NULL);
 
+	surface->width = 0;
+	surface->height = 0;
 	if (surface->buffer_ref.buffer) {
-		surface_width = weston_surface_buffer_width(surface);
-		surface_height = weston_surface_buffer_height(surface);
+		surface->width = weston_surface_buffer_width(surface);
+		surface->height = weston_surface_buffer_height(surface);
 	}
 
 	if (surface->configure && sub->cached.newly_attached)
 		surface->configure(surface, sub->cached.sx, sub->cached.sy,
-				   surface_width, surface_height);
+				   surface->width, surface->height);
 	sub->cached.sx = 0;
 	sub->cached.sy = 0;
 	sub->cached.newly_attached = 0;
@@ -1912,20 +2134,21 @@ weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
 			      &sub->cached.damage);
 	pixman_region32_intersect_rect(&surface->damage, &surface->damage,
 				       0, 0,
-				       surface->geometry.width,
-				       surface->geometry.height);
+				       surface->width,
+				       surface->height);
 	empty_region(&sub->cached.damage);
 
 	/* wl_surface.set_opaque_region */
 	pixman_region32_init_rect(&opaque, 0, 0,
-				  surface->geometry.width,
-				  surface->geometry.height);
+				  surface->width,
+				  surface->height);
 	pixman_region32_intersect(&opaque,
 				  &opaque, &sub->cached.opaque);
 
 	if (!pixman_region32_equal(&opaque, &surface->opaque)) {
 		pixman_region32_copy(&surface->opaque, &opaque);
-		weston_surface_geometry_dirty(surface);
+		wl_list_for_each(view, &surface->views, surface_link)
+			weston_view_geometry_dirty(view);
 	}
 
 	pixman_region32_fini(&opaque);
@@ -1933,8 +2156,8 @@ weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
 	/* wl_surface.set_input_region */
 	pixman_region32_fini(&surface->input);
 	pixman_region32_init_rect(&surface->input, 0, 0,
-				  surface->geometry.width,
-				  surface->geometry.height);
+				  surface->width,
+				  surface->height);
 	pixman_region32_intersect(&surface->input,
 				  &surface->input, &sub->cached.input);
 
@@ -2058,9 +2281,13 @@ static void
 weston_subsurface_parent_commit(struct weston_subsurface *sub,
 				int parent_is_synchronized)
 {
+	struct weston_view *view;
 	if (sub->position.set) {
-		weston_surface_set_position(sub->surface,
-					    sub->position.x, sub->position.y);
+		wl_list_for_each(view, &sub->surface->views, surface_link)
+			weston_view_set_position(view,
+						 sub->position.x,
+						 sub->position.y);
+
 		sub->position.set = 0;
 	}
 
@@ -2073,19 +2300,19 @@ subsurface_configure(struct weston_surface *surface, int32_t dx, int32_t dy,
 		     int32_t width, int32_t height)
 {
 	struct weston_compositor *compositor = surface->compositor;
+	struct weston_view *view;
 
-	weston_surface_configure(surface,
-				 surface->geometry.x + dx,
-				 surface->geometry.y + dy,
-				 width, height);
+	wl_list_for_each(view, &surface->views, surface_link)
+		weston_view_configure(view,
+				      view->geometry.x + dx,
+				      view->geometry.y + dy,
+				      width, height);
 
 	/* No need to check parent mappedness, because if parent is not
 	 * mapped, parent is not in a visible layer, so this sub-surface
 	 * will not be drawn either.
 	 */
 	if (!weston_surface_is_mapped(surface)) {
-		wl_list_init(&surface->layer_link);
-
 		/* Cannot call weston_surface_update_transform(),
 		 * because that would call it also for the parent surface,
 		 * which might not be mapped yet. That would lead to
@@ -2357,6 +2584,8 @@ weston_subsurface_link_surface(struct weston_subsurface *sub,
 static void
 weston_subsurface_destroy(struct weston_subsurface *sub)
 {
+	struct weston_view *view, *next;
+
 	assert(sub->surface);
 
 	if (sub->resource) {
@@ -2364,7 +2593,9 @@ weston_subsurface_destroy(struct weston_subsurface *sub)
 		assert(sub->parent_destroy_listener.notify ==
 		       subsurface_handle_parent_destroy);
 
-		weston_surface_set_transform_parent(sub->surface, NULL);
+		wl_list_for_each_safe(view, next, &sub->surface->views, surface_link)
+			weston_view_destroy(view);
+
 		if (sub->parent)
 			weston_subsurface_unlink_parent(sub);
 
@@ -2403,6 +2634,8 @@ weston_subsurface_create(uint32_t id, struct weston_surface *surface,
 	if (!sub)
 		return NULL;
 
+	wl_list_init(&sub->unused_views);
+
 	sub->resource =
 		wl_resource_create(client, &wl_subsurface_interface, 1, id);
 	if (!sub->resource) {
@@ -2417,7 +2650,6 @@ weston_subsurface_create(uint32_t id, struct weston_surface *surface,
 	weston_subsurface_link_parent(sub, parent);
 	weston_subsurface_cache_init(sub);
 	sub->synchronized = 1;
-	weston_surface_set_transform_parent(surface, parent);
 
 	return sub;
 }
@@ -2455,6 +2687,7 @@ subcompositor_get_subsurface(struct wl_client *client,
 	struct weston_surface *parent =
 		wl_resource_get_user_data(parent_resource);
 	struct weston_subsurface *sub;
+	struct weston_view *view, *subview;
 	static const char where[] = "get_subsurface: wl_subsurface@";
 
 	if (surface == parent) {
@@ -2783,7 +3016,7 @@ weston_output_update_matrix(struct weston_output *output)
 		magnification = 1 / (1 - output->zoom.spring_z.current);
 		weston_matrix_init(&camera);
 		weston_matrix_init(&modelview);
-		weston_output_update_zoom(output, output->zoom.type);
+		weston_output_update_zoom(output);
 		weston_matrix_translate(&camera, output->zoom.trans_x,
 					-output->zoom.trans_y, 0);
 		weston_matrix_invert(&modelview, &camera);
@@ -3012,7 +3245,7 @@ weston_compositor_init(struct weston_compositor *ec,
 			      ec, bind_subcompositor))
 		return -1;
 
-	wl_list_init(&ec->surface_list);
+	wl_list_init(&ec->view_list);
 	wl_list_init(&ec->plane_list);
 	wl_list_init(&ec->layer_list);
 	wl_list_init(&ec->seat_list);
@@ -3044,7 +3277,6 @@ weston_compositor_init(struct weston_compositor *ec,
 	ec->ping_handler = NULL;
 
 	screenshooter_create(ec);
-	text_cursor_position_notifier_create(ec);
 	text_backend_init(ec);
 
 	wl_data_device_manager_init(ec->wl_display);
diff --git a/src/compositor.h b/src/compositor.h
index 51288759092177e9b264c0cd1571c07d1c08926c..8ae757bb17eaaf35a0980f44ef0f1d5721c89978 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -92,6 +92,8 @@ struct weston_shell_interface {
 	struct shell_surface *(*create_shell_surface)(void *shell,
 						      struct weston_surface *surface,
 						      const struct weston_shell_client *client);
+	struct weston_view *(*get_primary_view)(void *shell,
+						struct shell_surface *shsurf);
 
 	void (*set_toplevel)(struct shell_surface *shsurf);
 
@@ -140,18 +142,12 @@ struct weston_spring {
 	uint32_t clip;
 };
 
-enum {
-	ZOOM_FOCUS_POINTER,
-	ZOOM_FOCUS_TEXT
-};
-
 struct weston_fixed_point {
 	wl_fixed_t x, y;
 };
 
 struct weston_output_zoom {
 	int active;
-	uint32_t type;
 	float increment;
 	float level;
 	float max_level;
@@ -163,7 +159,6 @@ struct weston_output_zoom {
 	struct weston_fixed_point from;
 	struct weston_fixed_point to;
 	struct weston_fixed_point current;
-	struct weston_fixed_point text_cursor;
 };
 
 /* bit compatible with drm definitions. */
@@ -311,11 +306,11 @@ struct weston_pointer {
 
 	struct wl_list resource_list;
 	struct wl_list focus_resource_list;
-	struct weston_surface *focus;
+	struct weston_view *focus;
 	uint32_t focus_serial;
 	struct wl_signal focus_signal;
 
-	struct weston_surface *sprite;
+	struct weston_view *sprite;
 	struct wl_listener sprite_destroy_listener;
 	int32_t hotspot_x, hotspot_y;
 
@@ -336,7 +331,7 @@ struct weston_touch {
 
 	struct wl_list resource_list;
 	struct wl_list focus_resource_list;
-	struct weston_surface *focus;
+	struct weston_view *focus;
 	uint32_t focus_serial;
 	struct wl_signal focus_signal;
 
@@ -354,7 +349,7 @@ void
 weston_pointer_destroy(struct weston_pointer *pointer);
 void
 weston_pointer_set_focus(struct weston_pointer *pointer,
-			 struct weston_surface *surface,
+			 struct weston_view *view,
 			 wl_fixed_t sx, wl_fixed_t sy);
 void
 weston_pointer_start_grab(struct weston_pointer *pointer,
@@ -384,7 +379,7 @@ void
 weston_touch_destroy(struct weston_touch *touch);
 void
 weston_touch_set_focus(struct weston_seat *seat,
-			  struct weston_surface *surface);
+		       struct weston_view *view);
 void
 weston_touch_start_grab(struct weston_touch *device,
 			struct weston_touch_grab *grab);
@@ -504,7 +499,7 @@ enum {
 };
 
 struct weston_layer {
-	struct wl_list surface_list;
+	struct wl_list view_list;
 	struct wl_list link;
 };
 
@@ -525,10 +520,12 @@ struct weston_renderer {
 	void (*flush_damage)(struct weston_surface *surface);
 	void (*attach)(struct weston_surface *es, struct weston_buffer *buffer);
 	int (*create_surface)(struct weston_surface *surface);
+	int (*create_view)(struct weston_view *view);
 	void (*surface_set_color)(struct weston_surface *surface,
 			       float red, float green,
 			       float blue, float alpha);
 	void (*destroy_surface)(struct weston_surface *surface);
+	void (*destroy_view)(struct weston_view *view);
 	void (*destroy)(struct weston_compositor *ec);
 };
 
@@ -574,7 +571,7 @@ struct weston_compositor {
 	struct wl_list output_list;
 	struct wl_list seat_list;
 	struct wl_list layer_list;
-	struct wl_list surface_list;
+	struct wl_list view_list;
 	struct wl_list plane_list;
 	struct wl_list key_binding_list;
 	struct wl_list button_binding_list;
@@ -685,51 +682,52 @@ struct weston_subsurface {
 	} cached;
 
 	int synchronized;
+
+	/* Used for constructing the view tree */
+	struct wl_list unused_views;
 };
 
-/* Using weston_surface transformations
+/* Using weston_view transformations
  *
- * To add a transformation to a surface, create a struct weston_transform, and
- * add it to the list surface->geometry.transformation_list. Whenever you
- * change the list, anything under surface->geometry, or anything in the
+ * To add a transformation to a view, create a struct weston_transform, and
+ * add it to the list view->geometry.transformation_list. Whenever you
+ * change the list, anything under view->geometry, or anything in the
  * weston_transforms linked into the list, you must call
- * weston_surface_geometry_dirty().
+ * weston_view_geometry_dirty().
  *
  * The order in the list defines the order of transformations. Let the list
  * contain the transformation matrices M1, ..., Mn as head to tail. The
- * transformation is applied to surface-local coordinate vector p as
+ * transformation is applied to view-local coordinate vector p as
  *    P = Mn * ... * M2 * M1 * p
  * to produce the global coordinate vector P. The total transform
  *    Mn * ... * M2 * M1
- * is cached in surface->transform.matrix, and the inverse of it in
- * surface->transform.inverse.
+ * is cached in view->transform.matrix, and the inverse of it in
+ * view->transform.inverse.
  *
- * The list always contains surface->transform.position transformation, which
- * is the translation by surface->geometry.x and y.
+ * The list always contains view->transform.position transformation, which
+ * is the translation by view->geometry.x and y.
  *
  * If you want to apply a transformation in local coordinates, add your
  * weston_transform to the head of the list. If you want to apply a
  * transformation in global coordinates, add it to the tail of the list.
  *
- * If surface->geometry.parent is set, the total transformation of this
- * surface will be the parent's total transformation and this transformation
+ * If view->geometry.parent is set, the total transformation of this
+ * view will be the parent's total transformation and this transformation
  * combined:
  *    Mparent * Mn * ... * M2 * M1
  */
 
-struct weston_surface {
-	struct wl_resource *resource;
+struct weston_view {
+	struct weston_surface *surface;
+	struct wl_list surface_link;
 	struct wl_signal destroy_signal;
-	struct weston_compositor *compositor;
-	pixman_region32_t clip;
-	pixman_region32_t damage;
-	pixman_region32_t opaque;        /* part of geometry, see below */
-	pixman_region32_t input;
+
 	struct wl_list link;
 	struct wl_list layer_link;
-	float alpha;                     /* part of geometry, see below */
 	struct weston_plane *plane;
-	int32_t ref_count;
+
+	pixman_region32_t clip;
+	float alpha;                     /* part of geometry, see below */
 
 	void *renderer_state;
 
@@ -745,14 +743,14 @@ struct weston_surface {
 		struct wl_list transformation_list;
 
 		/* managed by weston_surface_set_transform_parent() */
-		struct weston_surface *parent;
+		struct weston_view *parent;
 		struct wl_listener parent_destroy_listener;
 		struct wl_list child_list; /* geometry.parent_link */
 		struct wl_list parent_link;
 	} geometry;
 
 	/* State derived from geometry state, read-only.
-	 * This is updated by weston_surface_update_transform().
+	 * This is updated by weston_view_update_transform().
 	 */
 	struct {
 		int dirty;
@@ -782,6 +780,39 @@ struct weston_surface {
 	 * displayed on.
 	 */
 	uint32_t output_mask;
+};
+
+struct weston_surface {
+	struct wl_resource *resource;
+	struct wl_signal destroy_signal;
+	struct weston_compositor *compositor;
+	pixman_region32_t damage;
+	pixman_region32_t opaque;        /* part of geometry, see below */
+	pixman_region32_t input;
+	int32_t width, height;
+	int32_t ref_count;
+
+	/* Not for long-term storage.  This exists for book-keeping while
+	 * iterating over surfaces and views
+	 */
+	int32_t touched;
+
+	void *renderer_state;
+
+	struct wl_list views;
+
+	/*
+	 * Which output to vsync this surface to.
+	 * Used to determine, whether to send or queue frame events.
+	 * Must be NULL, if 'link' is not in weston_compositor::surface_list.
+	 */
+	struct weston_output *output;
+
+	/*
+	 * A more complete representation of all outputs this surface is
+	 * displayed on.
+	 */
+	uint32_t output_mask;
 
 	struct wl_list frame_callback_list;
 
@@ -843,29 +874,29 @@ void
 weston_version(int *major, int *minor, int *micro);
 
 void
-weston_surface_update_transform(struct weston_surface *surface);
+weston_view_update_transform(struct weston_view *view);
 
 void
-weston_surface_geometry_dirty(struct weston_surface *surface);
+weston_view_geometry_dirty(struct weston_view *view);
 
 void
-weston_surface_to_global_fixed(struct weston_surface *surface,
-			       wl_fixed_t sx, wl_fixed_t sy,
-			       wl_fixed_t *x, wl_fixed_t *y);
+weston_view_to_global_fixed(struct weston_view *view,
+			    wl_fixed_t sx, wl_fixed_t sy,
+			    wl_fixed_t *x, wl_fixed_t *y);
 void
-weston_surface_to_global_float(struct weston_surface *surface,
-			       float sx, float sy, float *x, float *y);
+weston_view_to_global_float(struct weston_view *view,
+			    float sx, float sy, float *x, float *y);
 
 void
-weston_surface_from_global_float(struct weston_surface *surface,
-				 float x, float y, float *sx, float *sy);
+weston_view_from_global_float(struct weston_view *view,
+			      float x, float y, float *vx, float *vy);
 void
-weston_surface_from_global(struct weston_surface *surface,
-			   int32_t x, int32_t y, int32_t *sx, int32_t *sy);
+weston_view_from_global(struct weston_view *view,
+			int32_t x, int32_t y, int32_t *vx, int32_t *vy);
 void
-weston_surface_from_global_fixed(struct weston_surface *surface,
-			         wl_fixed_t x, wl_fixed_t y,
-			         wl_fixed_t *sx, wl_fixed_t *sy);
+weston_view_from_global_fixed(struct weston_view *view,
+			      wl_fixed_t x, wl_fixed_t y,
+			      wl_fixed_t *vx, wl_fixed_t *vy);
 int32_t
 weston_surface_buffer_width(struct weston_surface *surface);
 int32_t
@@ -876,8 +907,7 @@ weston_surface_to_buffer_float(struct weston_surface *surface,
 			       float x, float y, float *bx, float *by);
 WL_EXPORT void
 weston_surface_to_buffer(struct weston_surface *surface,
-                         int sx, int sy, int *bx, int *by);
-
+			 int sx, int sy, int *bx, int *by);
 pixman_box32_t
 weston_surface_to_buffer_rect(struct weston_surface *surface,
 			      pixman_box32_t rect);
@@ -959,10 +989,10 @@ void
 weston_compositor_offscreen(struct weston_compositor *compositor);
 void
 weston_compositor_sleep(struct weston_compositor *compositor);
-struct weston_surface *
-weston_compositor_pick_surface(struct weston_compositor *compositor,
-			       wl_fixed_t x, wl_fixed_t y,
-			       wl_fixed_t *sx, wl_fixed_t *sy);
+struct weston_view *
+weston_compositor_pick_view(struct weston_compositor *compositor,
+			    wl_fixed_t x, wl_fixed_t y,
+			    wl_fixed_t *sx, wl_fixed_t *sy);
 
 
 struct weston_binding;
@@ -1048,20 +1078,32 @@ weston_compositor_top(struct weston_compositor *compositor);
 struct weston_surface *
 weston_surface_create(struct weston_compositor *compositor);
 
+struct weston_view *
+weston_view_create(struct weston_surface *surface);
+
+void
+weston_view_destroy(struct weston_view *view);
+
+void
+weston_view_configure(struct weston_view *view,
+		      float x, float y, int width, int height);
+
 void
-weston_surface_configure(struct weston_surface *surface,
-			 float x, float y, int width, int height);
+weston_view_restack(struct weston_view *surface, struct wl_list *below);
 
 void
-weston_surface_restack(struct weston_surface *surface, struct wl_list *below);
+weston_view_set_position(struct weston_view *view,
+			 float x, float y);
 
 void
-weston_surface_set_position(struct weston_surface *surface,
-			    float x, float y);
+weston_view_set_transform_parent(struct weston_view *view,
+				 struct weston_view *parent);
+
+int
+weston_view_is_mapped(struct weston_view *view);
 
 void
-weston_surface_set_transform_parent(struct weston_surface *surface,
-				    struct weston_surface *parent);
+weston_view_schedule_repaint(struct weston_view *view);
 
 int
 weston_surface_is_mapped(struct weston_surface *surface);
@@ -1073,11 +1115,14 @@ void
 weston_surface_damage(struct weston_surface *surface);
 
 void
-weston_surface_damage_below(struct weston_surface *surface);
+weston_view_damage_below(struct weston_view *view);
 
 void
-weston_surface_move_to_plane(struct weston_surface *surface,
-			     struct weston_plane *plane);
+weston_view_move_to_plane(struct weston_view *view,
+			  struct weston_plane *plane);
+void
+weston_view_unmap(struct weston_view *view);
+
 void
 weston_surface_unmap(struct weston_surface *surface);
 
@@ -1100,12 +1145,9 @@ weston_compositor_init(struct weston_compositor *ec, struct wl_display *display,
 void
 weston_compositor_shutdown(struct weston_compositor *ec);
 void
-weston_text_cursor_position_notify(struct weston_surface *surface,
-						wl_fixed_t x, wl_fixed_t y);
-void
 weston_output_init_zoom(struct weston_output *output);
 void
-weston_output_update_zoom(struct weston_output *output, uint32_t type);
+weston_output_update_zoom(struct weston_output *output);
 void
 weston_output_update_matrix(struct weston_output *output);
 void
@@ -1187,9 +1229,6 @@ screenshooter_create(struct weston_compositor *ec);
 struct clipboard *
 clipboard_create(struct weston_seat *seat);
 
-void
-text_cursor_position_notifier_create(struct weston_compositor *ec);
-
 int
 text_backend_init(struct weston_compositor *ec);
 
@@ -1212,23 +1251,23 @@ weston_client_launch(struct weston_compositor *compositor,
 void
 weston_watch_process(struct weston_process *process);
 
-struct weston_surface_animation;
-typedef	void (*weston_surface_animation_done_func_t)(struct weston_surface_animation *animation, void *data);
+struct weston_view_animation;
+typedef	void (*weston_view_animation_done_func_t)(struct weston_view_animation *animation, void *data);
 
-struct weston_surface_animation *
-weston_zoom_run(struct weston_surface *surface, float start, float stop,
-		weston_surface_animation_done_func_t done, void *data);
+struct weston_view_animation *
+weston_zoom_run(struct weston_view *view, float start, float stop,
+		weston_view_animation_done_func_t done, void *data);
 
-struct weston_surface_animation *
-weston_fade_run(struct weston_surface *surface,
+struct weston_view_animation *
+weston_fade_run(struct weston_view *view,
 		float start, float end, float k,
-		weston_surface_animation_done_func_t done, void *data);
+		weston_view_animation_done_func_t done, void *data);
 void
-weston_fade_update(struct weston_surface_animation *fade, float target);
+weston_fade_update(struct weston_view_animation *fade, float target);
 
-struct weston_surface_animation *
-weston_slide_run(struct weston_surface *surface, float start, float stop,
-		 weston_surface_animation_done_func_t done, void *data);
+struct weston_view_animation *
+weston_slide_run(struct weston_view *view, float start, float stop,
+		 weston_view_animation_done_func_t done, void *data);
 
 void
 weston_surface_set_color(struct weston_surface *surface,
diff --git a/src/data-device.c b/src/data-device.c
index 858235f6addfb11f70ccd61a75478c906ff613ed..3e22b5137d0c6542cfa8aefdf0d3d15f339b7bf4 100644
--- a/src/data-device.c
+++ b/src/data-device.c
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <assert.h>
 
 #include "compositor.h"
 
@@ -33,11 +34,11 @@ struct weston_drag {
 	struct wl_client *client;
 	struct weston_data_source *data_source;
 	struct wl_listener data_source_listener;
-	struct weston_surface *focus;
+	struct weston_view *focus;
 	struct wl_resource *focus_resource;
 	struct wl_listener focus_listener;
 	struct weston_pointer_grab grab;
-	struct weston_surface *icon;
+	struct weston_view *icon;
 	struct wl_listener icon_destroy_listener;
 	int32_t dx, dy;
 };
@@ -178,14 +179,17 @@ drag_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_
 	struct wl_list *list;
 	float fx, fy;
 
+	assert(es->configure == drag_surface_configure);
+
 	if (!weston_surface_is_mapped(es) && es->buffer_ref.buffer) {
-		if (pointer->sprite && weston_surface_is_mapped(pointer->sprite))
+		if (pointer->sprite && weston_view_is_mapped(pointer->sprite))
 			list = &pointer->sprite->layer_link;
 		else
-			list = &es->compositor->cursor_layer.surface_list;
+			list = &es->compositor->cursor_layer.view_list;
 
-		wl_list_insert(list, &es->layer_link);
-		weston_surface_update_transform(es);
+		wl_list_remove(&drag->icon->layer_link);
+		wl_list_insert(list, &drag->icon->layer_link);
+		weston_view_update_transform(drag->icon);
 		empty_region(&es->pending.input);
 	}
 
@@ -194,7 +198,7 @@ drag_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_
 
 	fx = wl_fixed_to_double(pointer->x) + drag->dx;
 	fy = wl_fixed_to_double(pointer->y) + drag->dy;
-	weston_surface_configure(es, fx, fy, width, height);
+	weston_view_configure(drag->icon, fx, fy, width, height);
 }
 
 static void
@@ -207,7 +211,7 @@ destroy_drag_focus(struct wl_listener *listener, void *data)
 }
 
 static void
-weston_drag_set_focus(struct weston_drag *drag, struct weston_surface *surface,
+weston_drag_set_focus(struct weston_drag *drag, struct weston_view *view,
 		      wl_fixed_t sx, wl_fixed_t sy)
 {
 	struct weston_pointer *pointer = drag->grab.pointer;
@@ -215,6 +219,11 @@ weston_drag_set_focus(struct weston_drag *drag, struct weston_surface *surface,
 	struct wl_display *display = pointer->seat->compositor->wl_display;
 	uint32_t serial;
 
+	if (drag->focus && view && drag->focus->surface == view->surface) {
+		drag->focus = view;
+		return;
+	}
+
 	if (drag->focus_resource) {
 		wl_data_device_send_leave(drag->focus_resource);
 		wl_list_remove(&drag->focus_listener.link);
@@ -222,15 +231,15 @@ weston_drag_set_focus(struct weston_drag *drag, struct weston_surface *surface,
 		drag->focus = NULL;
 	}
 
-	if (!surface)
+	if (!view || !view->surface->resource)
 		return;
 
 	if (!drag->data_source &&
-	    wl_resource_get_client(surface->resource) != drag->client)
+	    wl_resource_get_client(view->surface->resource) != drag->client)
 		return;
 
 	resource = wl_resource_find_for_client(&pointer->seat->drag_resource_list,
-					       wl_resource_get_client(surface->resource));
+					       wl_resource_get_client(view->surface->resource));
 	if (!resource)
 		return;
 
@@ -243,10 +252,10 @@ weston_drag_set_focus(struct weston_drag *drag, struct weston_surface *surface,
 			return;
 	}
 
-	wl_data_device_send_enter(resource, serial, surface->resource,
+	wl_data_device_send_enter(resource, serial, view->surface->resource,
 				  sx, sy, offer);
 
-	drag->focus = surface;
+	drag->focus = view;
 	drag->focus_listener.notify = destroy_drag_focus;
 	wl_resource_add_destroy_listener(resource, &drag->focus_listener);
 	drag->focus_resource = resource;
@@ -258,14 +267,14 @@ drag_grab_focus(struct weston_pointer_grab *grab)
 	struct weston_drag *drag =
 		container_of(grab, struct weston_drag, grab);
 	struct weston_pointer *pointer = grab->pointer;
-	struct weston_surface *surface;
+	struct weston_view *view;
 	wl_fixed_t sx, sy;
 
-	surface = weston_compositor_pick_surface(pointer->seat->compositor,
-						 pointer->x, pointer->y,
-						 &sx, &sy);
-	if (drag->focus != surface)
-		weston_drag_set_focus(drag, surface, sx, sy);
+	view = weston_compositor_pick_view(pointer->seat->compositor,
+					   pointer->x, pointer->y,
+					   &sx, &sy);
+	if (drag->focus != view)
+		weston_drag_set_focus(drag, view, sx, sy);
 }
 
 static void
@@ -280,14 +289,14 @@ drag_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
 	if (drag->icon) {
 		fx = wl_fixed_to_double(pointer->x) + drag->dx;
 		fy = wl_fixed_to_double(pointer->y) + drag->dy;
-		weston_surface_set_position(drag->icon, fx, fy);
-		weston_surface_schedule_repaint(drag->icon);
+		weston_view_set_position(drag->icon, fx, fy);
+		weston_view_schedule_repaint(drag->icon);
 	}
 
 	if (drag->focus_resource) {
-		weston_surface_from_global_fixed(drag->focus,
-						 pointer->x, pointer->y,
-						 &sx, &sy);
+		weston_view_from_global_fixed(drag->focus,
+					      pointer->x, pointer->y,
+					      &sx, &sy);
 
 		wl_data_device_send_motion(drag->focus_resource, time, sx, sy);
 	}
@@ -297,12 +306,13 @@ static void
 data_device_end_drag_grab(struct weston_drag *drag)
 {
 	if (drag->icon) {
-		if (weston_surface_is_mapped(drag->icon))
-			weston_surface_unmap(drag->icon);
+		if (weston_view_is_mapped(drag->icon))
+			weston_view_unmap(drag->icon);
 
-		drag->icon->configure = NULL;
-		empty_region(&drag->icon->pending.input);
+		drag->icon->surface->configure = NULL;
+		empty_region(&drag->icon->surface->pending.input);
 		wl_list_remove(&drag->icon_destroy_listener.link);
+		weston_view_destroy(drag->icon);
 	}
 
 	weston_drag_set_focus(drag, NULL, 0, 0);
@@ -373,21 +383,28 @@ weston_seat_start_drag(struct weston_seat *seat,
 	drag->grab.interface = &drag_grab_interface;
 	drag->client = client;
 	drag->data_source = source;
-	drag->icon = icon;
-
-	if (source) {
-		drag->data_source_listener.notify = destroy_data_device_source;
-		wl_signal_add(&source->destroy_signal,
-			      &drag->data_source_listener);
-	}
 
 	if (icon) {
+		drag->icon = weston_view_create(icon);
+		if (drag->icon == NULL) {
+			free(drag);
+			return -1;
+		}
+
 		drag->icon_destroy_listener.notify = handle_drag_icon_destroy;
 		wl_signal_add(&icon->destroy_signal,
 			      &drag->icon_destroy_listener);
 
 		icon->configure = drag_surface_configure;
 		icon->configure_private = drag;
+	} else {
+		drag->icon = NULL;
+	}
+
+	if (source) {
+		drag->data_source_listener.notify = destroy_data_device_source;
+		wl_signal_add(&source->destroy_signal,
+			      &drag->data_source_listener);
 	}
 
 	weston_pointer_set_focus(seat->pointer, NULL,
@@ -409,7 +426,8 @@ data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
 
 	if (seat->pointer->button_count == 0 ||
 	    seat->pointer->grab_serial != serial ||
-	    seat->pointer->focus != wl_resource_get_user_data(origin_resource))
+	    !seat->pointer->focus ||
+	    seat->pointer->focus->surface != wl_resource_get_user_data(origin_resource))
 		return;
 
 	/* FIXME: Check that the data source type array isn't empty. */
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index f02445b752bc60c0bf19e0bfa48d54b869355f82..2cb24fac338e75ed69aa71676dac9e0bf89bfef1 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -193,7 +193,7 @@ gl_renderer_print_egl_error_state(void)
  * polygon area.
  */
 static int
-calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
+calculate_edges(struct weston_view *ev, pixman_box32_t *rect,
 		pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
 {
 
@@ -213,8 +213,8 @@ calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
 
 	/* transform surface to screen space: */
 	for (i = 0; i < surf.n; i++)
-		weston_surface_to_global_float(es, surf.x[i], surf.y[i],
-					       &surf.x[i], &surf.y[i]);
+		weston_view_to_global_float(ev, surf.x[i], surf.y[i],
+					    &surf.x[i], &surf.y[i]);
 
 	/* find bounding box: */
 	min_x = max_x = surf.x[0];
@@ -238,9 +238,8 @@ calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
 	 * there will be only four edges.  We just need to clip the surface
 	 * vertices to the clip rect bounds:
 	 */
-	if (!es->transform.enabled) {
+	if (!ev->transform.enabled)
 		return clip_simple(&ctx, &surf, ex, ey);
-	}
 
 	/* Transformed case: use a general polygon clipping algorithm to
 	 * clip the surface rectangle with each side of 'rect'.
@@ -257,11 +256,11 @@ calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
 }
 
 static int
-texture_region(struct weston_surface *es, pixman_region32_t *region,
+texture_region(struct weston_view *ev, pixman_region32_t *region,
 		pixman_region32_t *surf_region)
 {
-	struct gl_surface_state *gs = get_surface_state(es);
-	struct weston_compositor *ec = es->compositor;
+	struct gl_surface_state *gs = get_surface_state(ev->surface);
+	struct weston_compositor *ec = ev->surface->compositor;
 	struct gl_renderer *gr = get_renderer(ec);
 	GLfloat *v, inv_width, inv_height;
 	unsigned int *vtxcnt, nvtx = 0;
@@ -302,18 +301,20 @@ texture_region(struct weston_surface *es, pixman_region32_t *region,
 			 * form the intersection of the clip rect and the transformed
 			 * surface.
 			 */
-			n = calculate_edges(es, rect, surf_rect, ex, ey);
+			n = calculate_edges(ev, rect, surf_rect, ex, ey);
 			if (n < 3)
 				continue;
 
 			/* emit edge points: */
 			for (k = 0; k < n; k++) {
-				weston_surface_from_global_float(es, ex[k], ey[k], &sx, &sy);
+				weston_view_from_global_float(ev, ex[k], ey[k],
+							      &sx, &sy);
 				/* position: */
 				*(v++) = ex[k];
 				*(v++) = ey[k];
 				/* texcoord: */
-				weston_surface_to_buffer_float(es, sx, sy,
+				weston_surface_to_buffer_float(ev->surface,
+							       sx, sy,
 							       &bx, &by);
 				*(v++) = bx * inv_width;
 				if (gs->y_inverted) {
@@ -331,9 +332,9 @@ texture_region(struct weston_surface *es, pixman_region32_t *region,
 }
 
 static void
-triangle_fan_debug(struct weston_surface *surface, int first, int count)
+triangle_fan_debug(struct weston_view *view, int first, int count)
 {
-	struct weston_compositor *compositor = surface->compositor;
+	struct weston_compositor *compositor = view->surface->compositor;
 	struct gl_renderer *gr = get_renderer(compositor);
 	int i;
 	GLushort *buffer;
@@ -371,10 +372,10 @@ triangle_fan_debug(struct weston_surface *surface, int first, int count)
 }
 
 static void
-repaint_region(struct weston_surface *es, pixman_region32_t *region,
+repaint_region(struct weston_view *ev, pixman_region32_t *region,
 		pixman_region32_t *surf_region)
 {
-	struct weston_compositor *ec = es->compositor;
+	struct weston_compositor *ec = ev->surface->compositor;
 	struct gl_renderer *gr = get_renderer(ec);
 	GLfloat *v;
 	unsigned int *vtxcnt;
@@ -388,7 +389,7 @@ repaint_region(struct weston_surface *es, pixman_region32_t *region,
 	 * polygon for each pair, and store it as a triangle fan if
 	 * it has a non-zero area (at least 3 vertices1, actually).
 	 */
-	nfans = texture_region(es, region, surf_region);
+	nfans = texture_region(ev, region, surf_region);
 
 	v = gr->vertices.data;
 	vtxcnt = gr->vtxcnt.data;
@@ -404,7 +405,7 @@ repaint_region(struct weston_surface *es, pixman_region32_t *region,
 	for (i = 0, first = 0; i < nfans; i++) {
 		glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
 		if (gr->fan_debug)
-			triangle_fan_debug(es, first, vtxcnt[i]);
+			triangle_fan_debug(ev, first, vtxcnt[i]);
 		first += vtxcnt[i];
 	}
 
@@ -464,28 +465,28 @@ use_shader(struct gl_renderer *gr, struct gl_shader *shader)
 
 static void
 shader_uniforms(struct gl_shader *shader,
-		       struct weston_surface *surface,
-		       struct weston_output *output)
+		struct weston_view *view,
+		struct weston_output *output)
 {
 	int i;
-	struct gl_surface_state *gs = get_surface_state(surface);
+	struct gl_surface_state *gs = get_surface_state(view->surface);
 
 	glUniformMatrix4fv(shader->proj_uniform,
 			   1, GL_FALSE, output->matrix.d);
 	glUniform4fv(shader->color_uniform, 1, gs->color);
-	glUniform1f(shader->alpha_uniform, surface->alpha);
+	glUniform1f(shader->alpha_uniform, view->alpha);
 
 	for (i = 0; i < gs->num_textures; i++)
 		glUniform1i(shader->tex_uniforms[i], i);
 }
 
 static void
-draw_surface(struct weston_surface *es, struct weston_output *output,
-	     pixman_region32_t *damage) /* in global coordinates */
+draw_view(struct weston_view *ev, struct weston_output *output,
+	  pixman_region32_t *damage) /* in global coordinates */
 {
-	struct weston_compositor *ec = es->compositor;
+	struct weston_compositor *ec = ev->surface->compositor;
 	struct gl_renderer *gr = get_renderer(ec);
-	struct gl_surface_state *gs = get_surface_state(es);
+	struct gl_surface_state *gs = get_surface_state(ev->surface);
 	/* repaint bounding region in global coordinates: */
 	pixman_region32_t repaint;
 	/* non-opaque region in surface coordinates: */
@@ -495,8 +496,8 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
 
 	pixman_region32_init(&repaint);
 	pixman_region32_intersect(&repaint,
-				  &es->transform.boundingbox, damage);
-	pixman_region32_subtract(&repaint, &repaint, &es->clip);
+				  &ev->transform.boundingbox, damage);
+	pixman_region32_subtract(&repaint, &repaint, &ev->clip);
 
 	if (!pixman_region32_not_empty(&repaint))
 		goto out;
@@ -505,13 +506,14 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
 
 	if (gr->fan_debug) {
 		use_shader(gr, &gr->solid_shader);
-		shader_uniforms(&gr->solid_shader, es, output);
+		shader_uniforms(&gr->solid_shader, ev, output);
 	}
 
 	use_shader(gr, gs->shader);
-	shader_uniforms(gs->shader, es, output);
+	shader_uniforms(gs->shader, ev, output);
 
-	if (es->transform.enabled || output->zoom.active || output->current_scale != es->buffer_scale)
+	if (ev->transform.enabled || output->zoom.active ||
+	    output->current_scale != ev->surface->buffer_scale)
 		filter = GL_LINEAR;
 	else
 		filter = GL_NEAREST;
@@ -525,10 +527,11 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
 
 	/* blended region is whole surface minus opaque region: */
 	pixman_region32_init_rect(&surface_blend, 0, 0,
-				  es->geometry.width, es->geometry.height);
-	pixman_region32_subtract(&surface_blend, &surface_blend, &es->opaque);
+				  ev->geometry.width, ev->geometry.height);
+	pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
 
-	if (pixman_region32_not_empty(&es->opaque)) {
+	/* XXX: Should we be using ev->transform.opaque here? */
+	if (pixman_region32_not_empty(&ev->surface->opaque)) {
 		if (gs->shader == &gr->texture_shader_rgba) {
 			/* Special case for RGBA textures with possibly
 			 * bad data in alpha channel: use the shader
@@ -536,21 +539,21 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
 			 * Xwayland surfaces need this.
 			 */
 			use_shader(gr, &gr->texture_shader_rgbx);
-			shader_uniforms(&gr->texture_shader_rgbx, es, output);
+			shader_uniforms(&gr->texture_shader_rgbx, ev, output);
 		}
 
-		if (es->alpha < 1.0)
+		if (ev->alpha < 1.0)
 			glEnable(GL_BLEND);
 		else
 			glDisable(GL_BLEND);
 
-		repaint_region(es, &repaint, &es->opaque);
+		repaint_region(ev, &repaint, &ev->surface->opaque);
 	}
 
 	if (pixman_region32_not_empty(&surface_blend)) {
 		use_shader(gr, gs->shader);
 		glEnable(GL_BLEND);
-		repaint_region(es, &repaint, &surface_blend);
+		repaint_region(ev, &repaint, &surface_blend);
 	}
 
 	pixman_region32_fini(&surface_blend);
@@ -560,14 +563,14 @@ out:
 }
 
 static void
-repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
+repaint_views(struct weston_output *output, pixman_region32_t *damage)
 {
 	struct weston_compositor *compositor = output->compositor;
-	struct weston_surface *surface;
+	struct weston_view *view;
 
-	wl_list_for_each_reverse(surface, &compositor->surface_list, link)
-		if (surface->plane == &compositor->primary_plane)
-			draw_surface(surface, output, damage);
+	wl_list_for_each_reverse(view, &compositor->view_list, link)
+		if (view->plane == &compositor->primary_plane)
+			draw_view(view, output, damage);
 }
 
 
@@ -762,7 +765,7 @@ gl_renderer_repaint_output(struct weston_output *output,
 		pixman_region32_subtract(&undamaged, &output->region,
 					 output_damage);
 		gr->fan_debug = 0;
-		repaint_surfaces(output, &undamaged);
+		repaint_views(output, &undamaged);
 		gr->fan_debug = 1;
 		pixman_region32_fini(&undamaged);
 	}
@@ -775,7 +778,7 @@ gl_renderer_repaint_output(struct weston_output *output,
 
 	pixman_region32_union(&total_damage, &buffer_damage, output_damage);
 
-	repaint_surfaces(output, &total_damage);
+	repaint_views(output, &total_damage);
 
 	pixman_region32_fini(&total_damage);
 	pixman_region32_fini(&buffer_damage);
@@ -830,6 +833,8 @@ gl_renderer_flush_damage(struct weston_surface *surface)
 	struct gl_renderer *gr = get_renderer(surface->compositor);
 	struct gl_surface_state *gs = get_surface_state(surface);
 	struct weston_buffer *buffer = gs->buffer_ref.buffer;
+	struct weston_view *view;
+	int texture_used;
 	GLenum format;
 	int pixel_type;
 
@@ -850,7 +855,14 @@ gl_renderer_flush_damage(struct weston_surface *surface)
 	 * hold the reference to the buffer, in case the surface
 	 * migrates back to the primary plane.
 	 */
-	if (surface->plane != &surface->compositor->primary_plane)
+	texture_used = 0;
+	wl_list_for_each(view, &surface->views, surface_link) {
+		if (view->plane == &surface->compositor->primary_plane) {
+			texture_used = 1;
+			break;
+		}
+	}
+	if (!texture_used)
 		return;
 
 	if (!pixman_region32_not_empty(&gs->texture_damage))
diff --git a/src/input.c b/src/input.c
index 9648f62edd37e2f0b4b88aefaf5311c5c20b52ba..5ad247a9b2ae95f5576aafd639c5e6d3c319a5de 100644
--- a/src/input.c
+++ b/src/input.c
@@ -96,18 +96,18 @@ static void
 default_grab_focus(struct weston_pointer_grab *grab)
 {
 	struct weston_pointer *pointer = grab->pointer;
-	struct weston_surface *surface;
+	struct weston_view *view;
 	wl_fixed_t sx, sy;
 
 	if (pointer->button_count > 0)
 		return;
 
-	surface = weston_compositor_pick_surface(pointer->seat->compositor,
-						 pointer->x, pointer->y,
-						 &sx, &sy);
+	view = weston_compositor_pick_view(pointer->seat->compositor,
+					   pointer->x, pointer->y,
+					   &sx, &sy);
 
-	if (pointer->focus != surface)
-		weston_pointer_set_focus(pointer, surface, sx, sy);
+	if (pointer->focus != view)
+		weston_pointer_set_focus(pointer, view, sx, sy);
 }
 
 static void
@@ -120,9 +120,9 @@ default_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
 
 	resource_list = &pointer->focus_resource_list;
 	wl_resource_for_each(resource, resource_list) {
-		weston_surface_from_global_fixed(pointer->focus,
-						 pointer->x, pointer->y,
-						 &sx, &sy);
+		weston_view_from_global_fixed(pointer->focus,
+					      pointer->x, pointer->y,
+					      &sx, &sy);
 		wl_pointer_send_motion(resource, time, sx, sy);
 	}
 }
@@ -133,7 +133,7 @@ default_grab_button(struct weston_pointer_grab *grab,
 {
 	struct weston_pointer *pointer = grab->pointer;
 	struct weston_compositor *compositor = pointer->seat->compositor;
-	struct weston_surface *surface;
+	struct weston_view *view;
 	struct wl_resource *resource;
 	uint32_t serial;
 	enum wl_pointer_button_state state = state_w;
@@ -154,12 +154,11 @@ default_grab_button(struct weston_pointer_grab *grab,
 
 	if (pointer->button_count == 0 &&
 	    state == WL_POINTER_BUTTON_STATE_RELEASED) {
-		surface = weston_compositor_pick_surface(compositor,
-							 pointer->x,
-							 pointer->y,
-							 &sx, &sy);
+		view = weston_compositor_pick_view(compositor,
+						   pointer->x, pointer->y,
+						   &sx, &sy);
 
-		weston_pointer_set_focus(pointer, surface, sx, sy);
+		weston_pointer_set_focus(pointer, view, sx, sy);
 	}
 }
 
@@ -186,7 +185,7 @@ default_grab_touch_down(struct weston_touch_grab *grab, uint32_t time,
 		serial = wl_display_next_serial(display);
 		wl_resource_for_each(resource, resource_list)
 				wl_touch_send_down(resource, serial, time,
-						   touch->focus->resource,
+						   touch->focus->surface->resource,
 						   touch_id, sx, sy);
 	}
 }
@@ -295,6 +294,15 @@ find_resource_for_surface(struct wl_list *list, struct weston_surface *surface)
 	return wl_resource_find_for_client(list, wl_resource_get_client(surface->resource));
 }
 
+static struct wl_resource *
+find_resource_for_view(struct wl_list *list, struct weston_view *view)
+{
+	if (!view)
+		return NULL;
+
+	return find_resource_for_surface(list, view->surface);
+}
+
 static void
 default_grab_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
 		       uint32_t mods_depressed, uint32_t mods_latched,
@@ -311,9 +319,9 @@ default_grab_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
 		wl_keyboard_send_modifiers(resource, serial, mods_depressed,
 					   mods_latched, mods_locked, group);
 	}
-	if (pointer && pointer->focus && pointer->focus != keyboard->focus) {
+	if (pointer && pointer->focus && pointer->focus->surface != keyboard->focus) {
 		struct wl_client *pointer_client =
-			wl_resource_get_client(pointer->focus->resource);
+			wl_resource_get_client(pointer->focus->surface->resource);
 		send_modifiers_to_client_in_list(pointer_client,
 						 &keyboard->resource_list,
 						 serial,
@@ -330,12 +338,13 @@ static const struct weston_keyboard_grab_interface
 static void
 pointer_unmap_sprite(struct weston_pointer *pointer)
 {
-	if (weston_surface_is_mapped(pointer->sprite))
-		weston_surface_unmap(pointer->sprite);
+	if (weston_surface_is_mapped(pointer->sprite->surface))
+		weston_surface_unmap(pointer->sprite->surface);
 
 	wl_list_remove(&pointer->sprite_destroy_listener.link);
-	pointer->sprite->configure = NULL;
-	pointer->sprite->configure_private = NULL;
+	pointer->sprite->surface->configure = NULL;
+	pointer->sprite->surface->configure_private = NULL;
+	weston_view_destroy(pointer->sprite);
 	pointer->sprite = NULL;
 }
 
@@ -461,7 +470,7 @@ seat_send_updated_caps(struct weston_seat *seat)
 
 WL_EXPORT void
 weston_pointer_set_focus(struct weston_pointer *pointer,
-			 struct weston_surface *surface,
+			 struct weston_view *view,
 			 wl_fixed_t sx, wl_fixed_t sy)
 {
 	struct weston_keyboard *kbd = pointer->seat->keyboard;
@@ -469,27 +478,33 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
 	struct wl_display *display = pointer->seat->compositor->wl_display;
 	uint32_t serial;
 	struct wl_list *focus_resource_list;
+	int different_surface = 0;
+
+	if ((!pointer->focus && view) ||
+	    (pointer->focus && !view) ||
+	    (pointer->focus && pointer->focus->surface != view->surface))
+		different_surface = 1;
 
 	focus_resource_list = &pointer->focus_resource_list;
 
-	if (!wl_list_empty(focus_resource_list) && pointer->focus != surface) {
+	if (!wl_list_empty(focus_resource_list) && different_surface) {
 		serial = wl_display_next_serial(display);
 		wl_resource_for_each(resource, focus_resource_list) {
 			wl_pointer_send_leave(resource, serial,
-					      pointer->focus->resource);
+					      pointer->focus->surface->resource);
 		}
 
 		move_resources(&pointer->resource_list, focus_resource_list);
 	}
 
-	if (find_resource_for_surface(&pointer->resource_list, surface) &&
-	    pointer->focus != surface) {
+	if (find_resource_for_view(&pointer->resource_list, view) &&
+	    different_surface) {
 		struct wl_client *surface_client =
-			wl_resource_get_client(surface->resource);
+			wl_resource_get_client(view->surface->resource);
 
 		serial = wl_display_next_serial(display);
 
-		if (kbd && kbd->focus != pointer->focus)
+		if (kbd && kbd->focus != view->surface)
 			send_modifiers_to_client_in_list(surface_client,
 							 &kbd->resource_list,
 							 serial,
@@ -502,14 +517,14 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
 		wl_resource_for_each(resource, focus_resource_list) {
 			wl_pointer_send_enter(resource,
 					      serial,
-					      surface->resource,
+					      view->surface->resource,
 					      sx, sy);
 		}
 
 		pointer->focus_serial = serial;
 	}
 
-	pointer->focus = surface;
+	pointer->focus = view;
 	wl_signal_emit(&pointer->focus_signal, pointer);
 }
 
@@ -676,13 +691,13 @@ move_pointer(struct weston_seat *seat, wl_fixed_t x, wl_fixed_t y)
 		if (output->zoom.active &&
 		    pixman_region32_contains_point(&output->region,
 						   ix, iy, NULL))
-			weston_output_update_zoom(output, ZOOM_FOCUS_POINTER);
+			weston_output_update_zoom(output);
 
 	if (pointer->sprite) {
-		weston_surface_set_position(pointer->sprite,
-					    ix - pointer->hotspot_x,
-					    iy - pointer->hotspot_y);
-		weston_surface_schedule_repaint(pointer->sprite);
+		weston_view_set_position(pointer->sprite,
+					 ix - pointer->hotspot_x,
+					 iy - pointer->hotspot_y);
+		weston_view_schedule_repaint(pointer->sprite);
 	}
 }
 
@@ -906,8 +921,7 @@ notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
 {
 	struct weston_compositor *compositor = seat->compositor;
 	struct weston_keyboard *keyboard = seat->keyboard;
-	struct weston_surface *focus =
-		(struct weston_surface *) keyboard->focus;
+	struct weston_surface *focus = keyboard->focus;
 	struct weston_keyboard_grab *grab = keyboard->grab;
 	uint32_t serial = wl_display_next_serial(compositor->wl_display);
 	uint32_t *k, *end;
@@ -1045,28 +1059,30 @@ notify_keyboard_focus_out(struct weston_seat *seat)
 }
 
 WL_EXPORT void
-weston_touch_set_focus(struct weston_seat *seat, struct weston_surface *surface)
+weston_touch_set_focus(struct weston_seat *seat, struct weston_view *view)
 {
 	struct wl_list *focus_resource_list;
 
 	focus_resource_list = &seat->touch->focus_resource_list;
 
-	if (seat->touch->focus == surface)
+	if (seat->touch->focus->surface == view->surface) {
+		seat->touch->focus = view;
 		return;
+	}
 
 	if (!wl_list_empty(focus_resource_list)) {
 		move_resources(&seat->touch->resource_list,
 			       focus_resource_list);
 	}
 
-	if (surface) {
+	if (view) {
 		struct wl_client *surface_client =
-			wl_resource_get_client(surface->resource);
+			wl_resource_get_client(view->surface->resource);
 		move_resources_for_client(focus_resource_list,
 					  &seat->touch->resource_list,
 					  surface_client);
 	}
-	seat->touch->focus = surface;
+	seat->touch->focus = view;
 }
 
 /**
@@ -1084,7 +1100,7 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
 	struct weston_compositor *ec = seat->compositor;
 	struct weston_touch *touch = seat->touch;
 	struct weston_touch_grab *grab = touch->grab;
-	struct weston_surface *es;
+	struct weston_view *ev;
 	wl_fixed_t sx, sy;
 
 	/* Update grab's global coordinates. */
@@ -1099,15 +1115,15 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
 
 		seat->num_tp++;
 
-		/* the first finger down picks the surface, and all further go
-		 * to that surface for the remainder of the touch session i.e.
+		/* the first finger down picks the view, and all further go
+		 * to that view for the remainder of the touch session i.e.
 		 * until all touch points are up again. */
 		if (seat->num_tp == 1) {
-			es = weston_compositor_pick_surface(ec, x, y, &sx, &sy);
-			weston_touch_set_focus(seat, es);
+			ev = weston_compositor_pick_view(ec, x, y, &sx, &sy);
+			weston_touch_set_focus(seat, ev);
 		} else if (touch->focus) {
-			es = (struct weston_surface *) touch->focus;
-			weston_surface_from_global_fixed(es, x, y, &sx, &sy);
+			ev = touch->focus;
+			weston_view_from_global_fixed(ev, x, y, &sx, &sy);
 		} else {
 			/* Unexpected condition: We have non-initial touch but
 			 * there is no focused surface.
@@ -1129,11 +1145,11 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
 
 		break;
 	case WL_TOUCH_MOTION:
-		es = (struct weston_surface *) touch->focus;
-		if (!es)
+		ev = touch->focus;
+		if (!ev)
 			break;
 
-		weston_surface_from_global_fixed(es, x, y, &sx, &sy);
+		weston_view_from_global_fixed(ev, x, y, &sx, &sy);
 		grab->interface->motion(grab, time, touch_id, sx, sy);
 		break;
 	case WL_TOUCH_UP:
@@ -1159,7 +1175,7 @@ pointer_cursor_surface_configure(struct weston_surface *es,
 	if (width == 0)
 		return;
 
-	assert(es == pointer->sprite);
+	assert(es == pointer->sprite->surface);
 
 	pointer->hotspot_x -= dx;
 	pointer->hotspot_y -= dy;
@@ -1167,14 +1183,14 @@ pointer_cursor_surface_configure(struct weston_surface *es,
 	x = wl_fixed_to_int(pointer->x) - pointer->hotspot_x;
 	y = wl_fixed_to_int(pointer->y) - pointer->hotspot_y;
 
-	weston_surface_configure(pointer->sprite, x, y, width, height);
+	weston_view_configure(pointer->sprite, x, y, width, height);
 
 	empty_region(&es->pending.input);
 
 	if (!weston_surface_is_mapped(es)) {
-		wl_list_insert(&es->compositor->cursor_layer.surface_list,
-			       &es->layer_link);
-		weston_surface_update_transform(es);
+		wl_list_insert(&es->compositor->cursor_layer.view_list,
+			       &pointer->sprite->layer_link);
+		weston_view_update_transform(pointer->sprite);
 	}
 }
 
@@ -1191,17 +1207,17 @@ pointer_set_cursor(struct wl_client *client, struct wl_resource *resource,
 
 	if (pointer->focus == NULL)
 		return;
-	/* pointer->focus->resource can be NULL. Surfaces like the
+	/* pointer->focus->surface->resource can be NULL. Surfaces like the
 	black_surface used in shell.c for fullscreen don't have
 	a resource, but can still have focus */
-	if (pointer->focus->resource == NULL)
+	if (pointer->focus->surface->resource == NULL)
 		return;
-	if (wl_resource_get_client(pointer->focus->resource) != client)
+	if (wl_resource_get_client(pointer->focus->surface->resource) != client)
 		return;
 	if (pointer->focus_serial - serial > UINT32_MAX / 2)
 		return;
 
-	if (surface && surface != pointer->sprite) {
+	if (surface && pointer->sprite && surface != pointer->sprite->surface) {
 		if (surface->configure) {
 			wl_resource_post_error(surface->resource,
 					       WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -1222,7 +1238,7 @@ pointer_set_cursor(struct wl_client *client, struct wl_resource *resource,
 
 	surface->configure = pointer_cursor_surface_configure;
 	surface->configure_private = pointer;
-	pointer->sprite = surface;
+	pointer->sprite = weston_view_create(surface);
 	pointer->hotspot_x = x;
 	pointer->hotspot_y = y;
 
@@ -1266,24 +1282,21 @@ seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
 	wl_resource_set_implementation(cr, &pointer_interface, seat->pointer,
 				       unbind_resource);
 
-	if (seat->pointer->focus && seat->pointer->focus->resource &&
-	    wl_resource_get_client(seat->pointer->focus->resource) == client) {
-		struct weston_surface *surface;
+	if (seat->pointer->focus && seat->pointer->focus->surface->resource &&
+	    wl_resource_get_client(seat->pointer->focus->surface->resource) == client) {
 		wl_fixed_t sx, sy;
 
-		surface = (struct weston_surface *) seat->pointer->focus;
-		weston_surface_from_global_fixed(surface,
-						 seat->pointer->x,
-						 seat->pointer->y,
-						 &sx,
-						 &sy);
+		weston_view_from_global_fixed(seat->pointer->focus,
+					      seat->pointer->x,
+					      seat->pointer->y,
+					      &sx, &sy);
 
 		wl_list_remove(wl_resource_get_link(cr));
 		wl_list_insert(&seat->pointer->focus_resource_list,
 			       wl_resource_get_link(cr));
 		wl_pointer_send_enter(cr,
 				      seat->pointer->focus_serial,
-				      surface->resource,
+				      seat->pointer->focus->surface->resource,
 				      sx, sy);
 	}
 }
@@ -1309,7 +1322,7 @@ should_send_modifiers_to_client(struct weston_seat *seat,
 
 	if (seat->pointer &&
 	    seat->pointer->focus &&
-	    wl_resource_get_client(seat->pointer->focus->resource) == client)
+	    wl_resource_get_client(seat->pointer->focus->surface->resource) == client)
 		return 1;
 
 	return 0;
@@ -1406,7 +1419,7 @@ seat_get_touch(struct wl_client *client, struct wl_resource *resource,
 	}
 
 	if (seat->touch->focus &&
-	    wl_resource_get_client(seat->touch->focus->resource) == client) {
+	    wl_resource_get_client(seat->touch->focus->surface->resource) == client) {
 		wl_list_insert(&seat->touch->resource_list,
 			       wl_resource_get_link(cr));
 	} else {
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index 987c5393611cbe57f6e69bfcba307b627fcf2b4d..85fcd4c2a4408baee3b1e9ea8b875fa2efaad4b5 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -223,16 +223,16 @@ region_global_to_output(struct weston_output *output, pixman_region32_t *region)
 #define D2F(v) pixman_double_to_fixed((double)v)
 
 static void
-repaint_region(struct weston_surface *es, struct weston_output *output,
+repaint_region(struct weston_view *ev, struct weston_output *output,
 	       pixman_region32_t *region, pixman_region32_t *surf_region,
 	       pixman_op_t pixman_op)
 {
 	struct pixman_renderer *pr =
 		(struct pixman_renderer *) output->compositor->renderer;
-	struct pixman_surface_state *ps = get_surface_state(es);
+	struct pixman_surface_state *ps = get_surface_state(ev->surface);
 	struct pixman_output_state *po = get_output_state(output);
 	pixman_region32_t final_region;
-	float surface_x, surface_y;
+	float view_x, view_y;
 	pixman_transform_t transform;
 	pixman_fixed_t fw, fh;
 
@@ -246,11 +246,11 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
 		pixman_region32_copy(&final_region, surf_region);
 
 		/* Convert from surface to global coordinates */
-		if (!es->transform.enabled) {
-			pixman_region32_translate(&final_region, es->geometry.x, es->geometry.y);
+		if (!ev->transform.enabled) {
+			pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
 		} else {
-			weston_surface_to_global_float(es, 0, 0, &surface_x, &surface_y);
-			pixman_region32_translate(&final_region, (int)surface_x, (int)surface_y);
+			weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
+			pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
 		}
 
 		/* We need to paint the intersection */
@@ -314,22 +314,22 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
 				   pixman_double_to_fixed (output->x),
 				   pixman_double_to_fixed (output->y));
 
-	if (es->transform.enabled) {
+	if (ev->transform.enabled) {
 		/* Pixman supports only 2D transform matrix, but Weston uses 3D,
 		 * so we're omitting Z coordinate here
 		 */
 		pixman_transform_t surface_transform = {{
-				{ D2F(es->transform.matrix.d[0]),
-				  D2F(es->transform.matrix.d[4]),
-				  D2F(es->transform.matrix.d[12]),
+				{ D2F(ev->transform.matrix.d[0]),
+				  D2F(ev->transform.matrix.d[4]),
+				  D2F(ev->transform.matrix.d[12]),
 				},
-				{ D2F(es->transform.matrix.d[1]),
-				  D2F(es->transform.matrix.d[5]),
-				  D2F(es->transform.matrix.d[13]),
+				{ D2F(ev->transform.matrix.d[1]),
+				  D2F(ev->transform.matrix.d[5]),
+				  D2F(ev->transform.matrix.d[13]),
 				},
-				{ D2F(es->transform.matrix.d[3]),
-				  D2F(es->transform.matrix.d[7]),
-				  D2F(es->transform.matrix.d[15]),
+				{ D2F(ev->transform.matrix.d[3]),
+				  D2F(ev->transform.matrix.d[7]),
+				  D2F(ev->transform.matrix.d[15]),
 				}
 			}};
 
@@ -337,15 +337,15 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
 		pixman_transform_multiply (&transform, &surface_transform, &transform);
 	} else {
 		pixman_transform_translate(&transform, NULL,
-					   pixman_double_to_fixed ((double)-es->geometry.x),
-					   pixman_double_to_fixed ((double)-es->geometry.y));
+					   pixman_double_to_fixed ((double)-ev->geometry.x),
+					   pixman_double_to_fixed ((double)-ev->geometry.y));
 	}
 
 
-	fw = pixman_int_to_fixed(es->geometry.width);
-	fh = pixman_int_to_fixed(es->geometry.height);
+	fw = pixman_int_to_fixed(ev->geometry.width);
+	fh = pixman_int_to_fixed(ev->geometry.height);
 
-	switch (es->buffer_transform) {
+	switch (ev->surface->buffer_transform) {
 	case WL_OUTPUT_TRANSFORM_FLIPPED:
 	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
 	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
@@ -357,7 +357,7 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
 		break;
 	}
 
-	switch (es->buffer_transform) {
+	switch (ev->surface->buffer_transform) {
 	default:
 	case WL_OUTPUT_TRANSFORM_NORMAL:
 	case WL_OUTPUT_TRANSFORM_FLIPPED:
@@ -380,12 +380,12 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
 	}
 
 	pixman_transform_scale(&transform, NULL,
-			       pixman_double_to_fixed ((double)es->buffer_scale),
-			       pixman_double_to_fixed ((double)es->buffer_scale));
+			       pixman_double_to_fixed ((double)ev->surface->buffer_scale),
+			       pixman_double_to_fixed ((double)ev->surface->buffer_scale));
 
 	pixman_image_set_transform(ps->image, &transform);
 
-	if (es->transform.enabled || output->current_scale != es->buffer_scale)
+	if (ev->transform.enabled || output->current_scale != ev->surface->buffer_scale)
 		pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
 	else
 		pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
@@ -417,10 +417,10 @@ repaint_region(struct weston_surface *es, struct weston_output *output,
 }
 
 static void
-draw_surface(struct weston_surface *es, struct weston_output *output,
-	     pixman_region32_t *damage) /* in global coordinates */
+draw_view(struct weston_view *ev, struct weston_output *output,
+	  pixman_region32_t *damage) /* in global coordinates */
 {
-	struct pixman_surface_state *ps = get_surface_state(es);
+	struct pixman_surface_state *ps = get_surface_state(ev->surface);
 	/* repaint bounding region in global coordinates: */
 	pixman_region32_t repaint;
 	/* non-opaque region in surface coordinates: */
@@ -432,8 +432,8 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
 
 	pixman_region32_init(&repaint);
 	pixman_region32_intersect(&repaint,
-				  &es->transform.boundingbox, damage);
-	pixman_region32_subtract(&repaint, &repaint, &es->clip);
+				  &ev->transform.boundingbox, damage);
+	pixman_region32_subtract(&repaint, &repaint, &ev->clip);
 
 	if (!pixman_region32_not_empty(&repaint))
 		goto out;
@@ -444,21 +444,21 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
 	}
 
 	/* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
-	if (es->transform.enabled &&
-	    es->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
-		repaint_region(es, output, &repaint, NULL, PIXMAN_OP_OVER);
+	if (ev->transform.enabled &&
+	    ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
+		repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
 	} else {
 		/* blended region is whole surface minus opaque region: */
 		pixman_region32_init_rect(&surface_blend, 0, 0,
-					  es->geometry.width, es->geometry.height);
-		pixman_region32_subtract(&surface_blend, &surface_blend, &es->opaque);
+					  ev->geometry.width, ev->geometry.height);
+		pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
 
-		if (pixman_region32_not_empty(&es->opaque)) {
-			repaint_region(es, output, &repaint, &es->opaque, PIXMAN_OP_SRC);
+		if (pixman_region32_not_empty(&ev->surface->opaque)) {
+			repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
 		}
 
 		if (pixman_region32_not_empty(&surface_blend)) {
-			repaint_region(es, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
+			repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
 		}
 		pixman_region32_fini(&surface_blend);
 	}
@@ -471,11 +471,11 @@ static void
 repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
 {
 	struct weston_compositor *compositor = output->compositor;
-	struct weston_surface *surface;
+	struct weston_view *view;
 
-	wl_list_for_each_reverse(surface, &compositor->surface_list, link)
-		if (surface->plane == &compositor->primary_plane)
-			draw_surface(surface, output, damage);
+	wl_list_for_each_reverse(view, &compositor->view_list, link)
+		if (view->plane == &compositor->primary_plane)
+			draw_view(view, output, damage);
 }
 
 static void
diff --git a/src/rpi-renderer.c b/src/rpi-renderer.c
index a95cc604c56cac8644eca754a9125caff675625a..ea48b087bc40377a485b12a0361261ebdceddaeb 100644
--- a/src/rpi-renderer.c
+++ b/src/rpi-renderer.c
@@ -104,13 +104,8 @@ enum buffer_type {
 struct rpir_surface {
 	struct weston_surface *surface;
 
-	/* If link is empty, the surface is guaranteed to not be on screen,
-	 * i.e. updates removing Elements have completed.
-	 */
-	struct wl_list link;
-
-	DISPMANX_ELEMENT_HANDLE_T handle;
-	int layer;
+	struct wl_list views;
+	int visible_views;
 	int need_swap;
 	int single_buffer;
 
@@ -127,6 +122,20 @@ struct rpir_surface {
 	enum buffer_type buffer_type;
 };
 
+struct rpir_view {
+	struct rpir_surface *surface;
+	struct wl_list surface_link;
+	struct weston_view *view;
+
+	/* If link is empty, the view is guaranteed to not be on screen,
+	 * i.e. updates removing Elements have completed.
+	 */
+	struct wl_list link;
+
+	DISPMANX_ELEMENT_HANDLE_T handle;
+	int layer;
+};
+
 struct rpir_output {
 	DISPMANX_DISPLAY_HANDLE_T display;
 
@@ -134,10 +143,10 @@ struct rpir_output {
 	struct weston_matrix matrix;
 
 	/* all Elements currently on screen */
-	struct wl_list surface_list; /* struct rpir_surface::link */
+	struct wl_list view_list; /* struct rpir_surface::link */
 
 	/* Elements just removed, waiting for update completion */
-	struct wl_list surface_cleanup_list; /* struct rpir_surface::link */
+	struct wl_list view_cleanup_list; /* struct rpir_surface::link */
 
 	struct rpi_resource capture_buffer;
 	uint8_t *capture_data;
@@ -164,6 +173,12 @@ to_rpir_surface(struct weston_surface *surface)
 	return surface->renderer_state;
 }
 
+static inline struct rpir_view *
+to_rpir_view(struct weston_view *view)
+{
+	return view->renderer_state;
+}
+
 static inline struct rpir_output *
 to_rpir_output(struct weston_output *output)
 {
@@ -356,9 +371,8 @@ rpir_surface_create(struct rpi_renderer *renderer)
 	if (!surface)
 		return NULL;
 
-	wl_list_init(&surface->link);
+	surface->visible_views = 0;
 	surface->single_buffer = renderer->single_buffer;
-	surface->handle = DISPMANX_NO_HANDLE;
 	rpi_resource_init(&surface->resources[0]);
 	rpi_resource_init(&surface->resources[1]);
 	surface->front = &surface->resources[0];
@@ -376,15 +390,18 @@ rpir_surface_create(struct rpi_renderer *renderer)
 static void
 rpir_surface_destroy(struct rpir_surface *surface)
 {
-	wl_list_remove(&surface->link);
-
-	if (surface->handle != DISPMANX_NO_HANDLE)
+	if (surface->visible_views)
 		weston_log("ERROR rpi: destroying on-screen element\n");
 
+	assert(wl_list_empty(&surface->views));
+
+	if (surface->surface)
+		surface->surface->renderer_state = NULL;
+
 	pixman_region32_fini(&surface->prev_damage);
 	rpi_resource_release(&surface->resources[0]);
 	rpi_resource_release(&surface->resources[1]);
-	DBG("rpir_surface %p destroyed (%u)\n", surface, surface->handle);
+	DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views);
 
 	if (surface->egl_back != NULL) {
 		weston_buffer_reference(&surface->egl_back->buffer_ref, NULL);
@@ -436,6 +453,46 @@ rpir_surface_damage(struct rpir_surface *surface, struct weston_buffer *buffer,
 	return ret;
 }
 
+static struct rpir_view *
+rpir_view_create(struct rpir_surface *surface)
+{
+	struct rpir_view *view;
+
+	view = calloc(1, sizeof *view);
+	if (!view)
+		return NULL;
+
+	view->surface = surface;
+	wl_list_insert(&surface->views, &view->surface_link);
+
+	wl_list_init(&view->link);
+	view->handle = DISPMANX_NO_HANDLE;
+
+	return view;
+}
+
+static void
+rpir_view_destroy(struct rpir_view *view)
+{
+	wl_list_remove(&view->link);
+
+	if (view->handle != DISPMANX_NO_HANDLE) {
+		view->surface->visible_views--;
+		weston_log("ERROR rpi: destroying on-screen element\n");
+	}
+
+	if (view->view)
+		view->view->renderer_state = NULL;
+
+	wl_list_remove(&view->surface_link);
+	if (wl_list_empty(&view->surface->views) && view->surface->surface == NULL)
+		rpir_surface_destroy(view->surface);
+
+	DBG("rpir_view %p destroyed (%d)\n", view, view->handle);
+
+	free(view);
+}
+
 static void
 matrix_type_str(struct weston_matrix *matrix, char *buf, int len)
 {
@@ -495,13 +552,13 @@ warn_bad_matrix(struct weston_matrix *total, struct weston_matrix *output,
 /*#define SURFACE_TRANSFORM */
 
 static int
-rpir_surface_compute_rects(struct rpir_surface *surface,
-			   VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
-			   VC_IMAGE_TRANSFORM_T *flipmask)
+rpir_view_compute_rects(struct rpir_view *view,
+			VC_RECT_T *src_rect, VC_RECT_T *dst_rect,
+			VC_IMAGE_TRANSFORM_T *flipmask)
 {
-	struct weston_output *output_base = surface->surface->output;
+	struct weston_output *output_base = view->view->surface->output;
 	struct rpir_output *output = to_rpir_output(output_base);
-	struct weston_matrix matrix = surface->surface->transform.matrix;
+	struct weston_matrix matrix = view->view->transform.matrix;
 	VC_IMAGE_TRANSFORM_T flipt = 0;
 	int src_x, src_y;
 	int dst_x, dst_y;
@@ -523,14 +580,15 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
 	src_x = 0 << 16;
 	src_y = 0 << 16;
 
-	if (surface->buffer_type == BUFFER_TYPE_EGL) {
-		struct weston_buffer *buffer = surface->egl_front->buffer_ref.buffer;
+	if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
+		struct weston_buffer *buffer =
+			view->surface->egl_front->buffer_ref.buffer;
 
 		src_width = buffer->width << 16;
 		src_height = buffer->height << 16;
 	} else {
-		src_width = surface->front->width << 16;
-		src_height = surface->front->height << 16;
+		src_width = view->surface->front->width << 16;
+		src_height = view->surface->front->height << 16;
 	}
 
 	weston_matrix_multiply(&matrix, &output->matrix);
@@ -541,7 +599,7 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
 	if (matrix.type >= WESTON_MATRIX_TRANSFORM_ROTATE) {
 #endif
 		warn_bad_matrix(&matrix, &output->matrix,
-				&surface->surface->transform.matrix);
+				&view->view->transform.matrix);
 	} else {
 		if (matrix.type & WESTON_MATRIX_TRANSFORM_ROTATE) {
 			if (fabsf(matrix.d[0]) < 1e-4f &&
@@ -552,13 +610,13 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
 				/* no transpose */
 			} else {
 				warn_bad_matrix(&matrix, &output->matrix,
-					&surface->surface->transform.matrix);
+					&view->view->transform.matrix);
 			}
 		}
 	}
 
-	p2.f[0] = surface->surface->geometry.width;
-	p2.f[1] = surface->surface->geometry.height;
+	p2.f[0] = view->view->geometry.width;
+	p2.f[1] = view->view->geometry.height;
 
 	/* transform top-left and bot-right corner into screen coordinates */
 	weston_matrix_transform(&matrix, &p1);
@@ -680,9 +738,9 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
 	src_width = int_max(src_width, 0);
 	src_height = int_max(src_height, 0);
 
-	DBG("rpir_surface %p %dx%d: p1 %f, %f; p2 %f, %f\n", surface,
-	    surface->surface->geometry.width,
-	    surface->surface->geometry.height,
+	DBG("rpir_view %p %dx%d: p1 %f, %f; p2 %f, %f\n", view,
+	    view->view->geometry.width,
+	    view->view->geometry.height,
 	    p1.f[0], p1.f[1], p2.f[0], p2.f[1]);
 	DBG("src rect %d;%d, %d;%d, %d;%dx%d;%d\n",
 	    src_x >> 16, src_x & 0xffff,
@@ -706,7 +764,7 @@ rpir_surface_compute_rects(struct rpir_surface *surface,
 	}
 
 	/* EGL buffers will be upside-down related to what DispmanX expects */
-	if (surface->buffer_type == BUFFER_TYPE_EGL)
+	if (view->surface->buffer_type == BUFFER_TYPE_EGL)
 		flipt ^= TRANSFORM_VFLIP;
 
 	vc_dispmanx_rect_set(src_rect, src_x, src_y, src_width, src_height);
@@ -760,8 +818,8 @@ rpir_surface_get_resource(struct rpir_surface *surface)
 }
 
 static int
-rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
-		    DISPMANX_UPDATE_HANDLE_T update, int layer)
+rpir_view_dmx_add(struct rpir_view *view, struct rpir_output *output,
+		  DISPMANX_UPDATE_HANDLE_T update, int layer)
 {
 	/* Do not use DISPMANX_FLAGS_ALPHA_PREMULT here.
 	 * If you define PREMULT and ALPHA_MIX, the hardware will not
@@ -771,7 +829,7 @@ rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
 	VC_DISPMANX_ALPHA_T alphasetup = {
 		DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
 		DISPMANX_FLAGS_ALPHA_MIX,
-		float2uint8(surface->surface->alpha), /* opacity 0-255 */
+		float2uint8(view->view->alpha), /* opacity 0-255 */
 		0 /* mask resource handle */
 	};
 	VC_RECT_T dst_rect;
@@ -780,18 +838,17 @@ rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
 	int ret;
 	DISPMANX_RESOURCE_HANDLE_T resource_handle;
 
-	resource_handle = rpir_surface_get_resource(surface);
+	resource_handle = rpir_surface_get_resource(view->surface);
 	if (resource_handle == DISPMANX_NO_HANDLE) {
 		weston_log("%s: no buffer yet, aborting\n", __func__);
 		return 0;
 	}
 
-	ret = rpir_surface_compute_rects(surface, &src_rect, &dst_rect,
-					 &flipmask);
+	ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
 	if (ret < 0)
 		return 0;
 
-	surface->handle = vc_dispmanx_element_add(
+	view->handle = vc_dispmanx_element_add(
 		update,
 		output->display,
 		layer,
@@ -802,37 +859,42 @@ rpir_surface_dmx_add(struct rpir_surface *surface, struct rpir_output *output,
 		&alphasetup,
 		NULL /* clamp */,
 		vc_image2dispmanx_transform(flipmask));
-	DBG("rpir_surface %p add %u, alpha %f resource %d\n", surface,
-	    surface->handle, surface->surface->alpha, resource_handle);
+	DBG("rpir_surface %p add %u, alpha %f resource %d\n", view,
+	    view->handle, view->view->alpha, resource_handle);
+
+	if (view->handle == DISPMANX_NO_HANDLE)
+		return -1;
+
+	view->surface->visible_views++;
 
 	return 1;
 }
 
 static void
-rpir_surface_dmx_swap(struct rpir_surface *surface,
-		      DISPMANX_UPDATE_HANDLE_T update)
+rpir_view_dmx_swap(struct rpir_view *view,
+		   DISPMANX_UPDATE_HANDLE_T update)
 {
 	VC_RECT_T rect;
 	pixman_box32_t *r;
 
 	/* XXX: skip, iff resource was not reallocated, and single-buffering */
-	vc_dispmanx_element_change_source(update, surface->handle,
-					  surface->front->handle);
+	vc_dispmanx_element_change_source(update, view->handle,
+					  view->surface->front->handle);
 
 	/* This is current damage now, after rpir_surface_damage() */
-	r = pixman_region32_extents(&surface->prev_damage);
+	r = pixman_region32_extents(&view->surface->prev_damage);
 
 	vc_dispmanx_rect_set(&rect, r->x1, r->y1,
 			     r->x2 - r->x1, r->y2 - r->y1);
-	vc_dispmanx_element_modified(update, surface->handle, &rect);
-	DBG("rpir_surface %p swap\n", surface);
+	vc_dispmanx_element_modified(update, view->handle, &rect);
+	DBG("rpir_view %p swap\n", view);
 }
 
 static int
-rpir_surface_dmx_move(struct rpir_surface *surface,
-		      DISPMANX_UPDATE_HANDLE_T update, int layer)
+rpir_view_dmx_move(struct rpir_view *view,
+		   DISPMANX_UPDATE_HANDLE_T update, int layer)
 {
-	uint8_t alpha = float2uint8(surface->surface->alpha);
+	uint8_t alpha = float2uint8(view->view->alpha);
 	VC_RECT_T dst_rect;
 	VC_RECT_T src_rect;
 	VC_IMAGE_TRANSFORM_T flipmask;
@@ -840,28 +902,27 @@ rpir_surface_dmx_move(struct rpir_surface *surface,
 
 	/* XXX: return early, if all attributes stay the same */
 
-	if (surface->buffer_type == BUFFER_TYPE_EGL) {
+	if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
 		DISPMANX_RESOURCE_HANDLE_T resource_handle;
 
-		resource_handle = rpir_surface_get_resource(surface);
+		resource_handle = rpir_surface_get_resource(view->surface);
 		if (resource_handle == DISPMANX_NO_HANDLE) {
 			weston_log("%s: no buffer yet, aborting\n", __func__);
 			return 0;
 		}
 
 		vc_dispmanx_element_change_source(update,
-						  surface->handle,
+						  view->handle,
 						  resource_handle);
 	}
 
-	ret = rpir_surface_compute_rects(surface, &src_rect, &dst_rect,
-					 &flipmask);
+	ret = rpir_view_compute_rects(view, &src_rect, &dst_rect, &flipmask);
 	if (ret < 0)
 		return 0;
 
 	ret = vc_dispmanx_element_change_attributes(
 		update,
-		surface->handle,
+		view->handle,
 		ELEMENT_CHANGE_LAYER |
 			ELEMENT_CHANGE_OPACITY |
 			ELEMENT_CHANGE_TRANSFORM |
@@ -875,7 +936,7 @@ rpir_surface_dmx_move(struct rpir_surface *surface,
 		/* This really is DISPMANX_TRANSFORM_T, no matter
 		 * what the header says. */
 		vc_image2dispmanx_transform(flipmask));
-	DBG("rpir_surface %p move\n", surface);
+	DBG("rpir_view %p move\n", view);
 
 	if (ret)
 		return -1;
@@ -884,15 +945,16 @@ rpir_surface_dmx_move(struct rpir_surface *surface,
 }
 
 static void
-rpir_surface_dmx_remove(struct rpir_surface *surface,
-			DISPMANX_UPDATE_HANDLE_T update)
+rpir_view_dmx_remove(struct rpir_view *view,
+		     DISPMANX_UPDATE_HANDLE_T update)
 {
-	if (surface->handle == DISPMANX_NO_HANDLE)
+	if (view->handle == DISPMANX_NO_HANDLE)
 		return;
 
-	vc_dispmanx_element_remove(update, surface->handle);
-	DBG("rpir_surface %p remove %u\n", surface, surface->handle);
-	surface->handle = DISPMANX_NO_HANDLE;
+	vc_dispmanx_element_remove(update, view->handle);
+	DBG("rpir_view %p remove %u\n", view, view->handle);
+	view->handle = DISPMANX_NO_HANDLE;
+	view->surface->visible_views--;
 }
 
 static void
@@ -900,23 +962,31 @@ rpir_surface_swap_pointers(struct rpir_surface *surface)
 {
 	struct rpi_resource *tmp;
 
-	tmp = surface->front;
-	surface->front = surface->back;
-	surface->back = tmp;
-	surface->need_swap = 0;
+	if (surface->buffer_type == BUFFER_TYPE_EGL) {
+		if (surface->egl_back != NULL) {
+			assert(surface->egl_old_front == NULL);
+			surface->egl_old_front = surface->egl_front;
+			surface->egl_front = surface->egl_back;
+			surface->egl_back = NULL;
+		}
+	} else {
+		tmp = surface->front;
+		surface->front = surface->back;
+		surface->back = tmp;
+	}
 	DBG("new back %p, new front %p\n", surface->back, surface->front);
 }
 
 static int
-is_surface_not_visible(struct weston_surface *surface)
+is_view_not_visible(struct weston_view *view)
 {
 	/* Return true, if surface is guaranteed to be totally obscured. */
 	int ret;
 	pixman_region32_t unocc;
 
 	pixman_region32_init(&unocc);
-	pixman_region32_subtract(&unocc, &surface->transform.boundingbox,
-				 &surface->clip);
+	pixman_region32_subtract(&unocc, &view->transform.boundingbox,
+				 &view->clip);
 	ret = !pixman_region32_not_empty(&unocc);
 	pixman_region32_fini(&unocc);
 
@@ -924,81 +994,55 @@ is_surface_not_visible(struct weston_surface *surface)
 }
 
 static void
-rpir_surface_update(struct rpir_surface *surface, struct rpir_output *output,
-		    DISPMANX_UPDATE_HANDLE_T update, int layer)
+rpir_view_update(struct rpir_view *view, struct rpir_output *output,
+		 DISPMANX_UPDATE_HANDLE_T update, int layer)
 {
-	int need_swap = surface->need_swap;
 	int ret;
 	int obscured;
 
-	if (surface->buffer_type == BUFFER_TYPE_EGL) {
-		if (surface->egl_back != NULL) {
-			assert(surface->egl_old_front == NULL);
-			surface->egl_old_front = surface->egl_front;
-			surface->egl_front = surface->egl_back;
-			surface->egl_back = NULL;
-		}
-		if (surface->egl_front->buffer_ref.buffer == NULL) {
-			weston_log("warning: client unreffed current front buffer\n");
-
-			wl_list_remove(&surface->link);
-			if (surface->handle == DISPMANX_NO_HANDLE) {
-				wl_list_init(&surface->link);
-			} else {
-				rpir_surface_dmx_remove(surface, update);
-				wl_list_insert(&output->surface_cleanup_list,
-						   &surface->link);
-			}
-
-			goto out;
-		}
-	} else {
-		if (need_swap)
-			rpir_surface_swap_pointers(surface);
-	}
 
-	obscured = is_surface_not_visible(surface->surface);
+	obscured = is_view_not_visible(view->view);
 	if (obscured) {
-		DBG("rpir_surface %p totally obscured.\n", surface);
+		DBG("rpir_view %p totally obscured.\n", view);
 
-		wl_list_remove(&surface->link);
-		if (surface->handle == DISPMANX_NO_HANDLE) {
-			wl_list_init(&surface->link);
+		wl_list_remove(&view->link);
+		if (view->handle == DISPMANX_NO_HANDLE) {
+			wl_list_init(&view->link);
 		} else {
-			rpir_surface_dmx_remove(surface, update);
-			wl_list_insert(&output->surface_cleanup_list,
-				       &surface->link);
+			rpir_view_dmx_remove(view, update);
+			wl_list_insert(&output->view_cleanup_list,
+				       &view->link);
 		}
 
 		goto out;
 	}
 
-	if (surface->handle == DISPMANX_NO_HANDLE) {
-		ret = rpir_surface_dmx_add(surface, output, update, layer);
+	if (view->handle == DISPMANX_NO_HANDLE) {
+		ret = rpir_view_dmx_add(view, output, update, layer);
 		if (ret == 0) {
-			wl_list_remove(&surface->link);
-			wl_list_init(&surface->link);
+			wl_list_remove(&view->link);
+			wl_list_init(&view->link);
 		} else if (ret < 0) {
-			weston_log("ERROR rpir_surface_dmx_add() failed.\n");
+			weston_log("ERROR rpir_view_dmx_add() failed.\n");
 		}
 	} else {
-		if (need_swap)
-			rpir_surface_dmx_swap(surface, update);
+		if (view->surface->need_swap)
+			rpir_view_dmx_swap(view, update);
 
-		ret = rpir_surface_dmx_move(surface, update, layer);
+		ret = rpir_view_dmx_move(view, update, layer);
 		if (ret == 0) {
-			rpir_surface_dmx_remove(surface, update);
+			rpir_view_dmx_remove(view, update);
 
-			wl_list_remove(&surface->link);
-			wl_list_insert(&output->surface_cleanup_list,
-				       &surface->link);
+			wl_list_remove(&view->link);
+			wl_list_insert(&output->view_cleanup_list,
+				       &view->link);
 		} else if (ret < 0) {
-			weston_log("ERROR rpir_surface_dmx_move() failed.\n");
+			weston_log("ERROR rpir_view_dmx_move() failed.\n");
 		}
 	}
 
 out:
-	surface->layer = layer;
+	view->layer = layer;
 }
 
 static int
@@ -1105,15 +1149,15 @@ static void
 rpir_output_dmx_remove_all(struct rpir_output *output,
 			   DISPMANX_UPDATE_HANDLE_T update)
 {
-	struct rpir_surface *surface;
+	struct rpir_view *view;
 
-	while (!wl_list_empty(&output->surface_list)) {
-		surface = container_of(output->surface_list.next,
-				       struct rpir_surface, link);
-		rpir_surface_dmx_remove(surface, update);
+	while (!wl_list_empty(&output->view_list)) {
+		view = container_of(output->view_list.next,
+				    struct rpir_view, link);
+		rpir_view_dmx_remove(view, update);
 
-		wl_list_remove(&surface->link);
-		wl_list_insert(&output->surface_cleanup_list, &surface->link);
+		wl_list_remove(&view->link);
+		wl_list_insert(&output->view_cleanup_list, &view->link);
 	}
 }
 
@@ -1186,8 +1230,8 @@ rpi_renderer_repaint_output(struct weston_output *base,
 {
 	struct weston_compositor *compositor = base->compositor;
 	struct rpir_output *output = to_rpir_output(base);
-	struct weston_surface *ws;
-	struct rpir_surface *surface;
+	struct weston_view *wv;
+	struct rpir_view *view;
 	struct wl_list done_list;
 	int layer = 1;
 
@@ -1199,27 +1243,59 @@ rpi_renderer_repaint_output(struct weston_output *base,
 	free(output->capture_data);
 	output->capture_data = NULL;
 
+	/* Swap resources on surfaces as needed */
+	wl_list_for_each_reverse(wv, &compositor->view_list, link)
+		wv->surface->touched = 0;
+
+	wl_list_for_each_reverse(wv, &compositor->view_list, link) {
+		view = to_rpir_view(wv);
+
+		if (!wv->surface->touched) {
+			wv->surface->touched = 1;
+
+			if (view->surface->need_swap)
+				rpir_surface_swap_pointers(view->surface);
+		}
+
+		if (view->surface->egl_front->buffer_ref.buffer == NULL) {
+			weston_log("warning: client unreffed current front buffer\n");
+
+			wl_list_remove(&view->link);
+			if (view->handle == DISPMANX_NO_HANDLE) {
+				wl_list_init(&view->link);
+			} else {
+				rpir_view_dmx_remove(view, output->update);
+				wl_list_insert(&output->view_cleanup_list,
+					       &view->link);
+			}
+		}
+	}
+
 	/* update all renderable surfaces */
 	wl_list_init(&done_list);
-	wl_list_for_each_reverse(ws, &compositor->surface_list, link) {
-		if (ws->plane != &compositor->primary_plane)
+	wl_list_for_each_reverse(wv, &compositor->view_list, link) {
+		if (wv->plane != &compositor->primary_plane)
 			continue;
 
-		surface = to_rpir_surface(ws);
-		assert(!wl_list_empty(&surface->link) ||
-		       surface->handle == DISPMANX_NO_HANDLE);
+		view = to_rpir_view(wv);
+		assert(!wl_list_empty(&view->link) ||
+		       view->handle == DISPMANX_NO_HANDLE);
 
-		wl_list_remove(&surface->link);
-		wl_list_insert(&done_list, &surface->link);
-		rpir_surface_update(surface, output, output->update, layer++);
+		wl_list_remove(&view->link);
+		wl_list_insert(&done_list, &view->link);
+		rpir_view_update(view, output, output->update, layer++);
 	}
 
+	/* Mark all surfaces as swapped */
+	wl_list_for_each_reverse(wv, &compositor->view_list, link)
+		to_rpir_surface(wv->surface)->need_swap = 0;
+
 	/* Remove all surfaces that are still on screen, but were
 	 * not rendered this time.
 	 */
 	rpir_output_dmx_remove_all(output, output->update);
 
-	wl_list_insert_list(&output->surface_list, &done_list);
+	wl_list_insert_list(&output->view_list, &done_list);
 	output->update = DISPMANX_NO_HANDLE;
 
 	/* The frame_signal is emitted in rpi_renderer_finish_frame(),
@@ -1263,7 +1339,7 @@ rpi_renderer_attach(struct weston_surface *base, struct weston_buffer *buffer)
 			/* XXX: need to check if in middle of update */
 			rpi_resource_release(surface->back);
 
-		if (surface->handle == DISPMANX_NO_HANDLE)
+		if (!surface->visible_views)
 			/* XXX: cannot do this, if middle of an update */
 			rpi_resource_release(surface->front);
 
@@ -1336,6 +1412,23 @@ rpi_renderer_create_surface(struct weston_surface *base)
 	return 0;
 }
 
+static int
+rpi_renderer_create_view(struct weston_view *base)
+{
+	struct rpir_surface *surface = to_rpir_surface(base->surface);
+	struct rpir_view *view;
+
+	assert(base->renderer_state == NULL);
+
+	view = rpir_view_create(surface);
+	if (!view)
+		return -1;
+
+	view->view = base;
+	base->renderer_state = view;
+	return 0;
+}
+
 static void
 rpi_renderer_surface_set_color(struct weston_surface *base,
 			       float red, float green, float blue, float alpha)
@@ -1390,13 +1483,27 @@ rpi_renderer_destroy_surface(struct weston_surface *base)
 	surface->surface = NULL;
 	base->renderer_state = NULL;
 
-	/* If guaranteed to not be on screen, just detroy it. */
-	if (wl_list_empty(&surface->link))
+	if (wl_list_empty(&surface->views))
 		rpir_surface_destroy(surface);
+}
 
-	/* Otherwise, the surface is either on screen and needs
+static void
+rpi_renderer_destroy_view(struct weston_view *base)
+{
+	struct rpir_view *view = to_rpir_view(base);
+
+	assert(view);
+	assert(view->view == base);
+	if (!view)
+		return;
+
+	/* If guaranteed to not be on screen, just detroy it. */
+	if (wl_list_empty(&view->link))
+		rpir_view_destroy(view);
+
+	/* Otherwise, the view is either on screen and needs
 	 * to be removed by a repaint update, or it is in the
-	 * surface_cleanup_list, and will be destroyed by
+	 * view_cleanup_list, and will be destroyed by
 	 * rpi_renderer_finish_frame().
 	 */
 }
@@ -1440,8 +1547,10 @@ rpi_renderer_create(struct weston_compositor *compositor,
 	renderer->base.flush_damage = rpi_renderer_flush_damage;
 	renderer->base.attach = rpi_renderer_attach;
 	renderer->base.create_surface = rpi_renderer_create_surface;
+	renderer->base.create_view = rpi_renderer_create_view;
 	renderer->base.surface_set_color = rpi_renderer_surface_set_color;
 	renderer->base.destroy_surface = rpi_renderer_destroy_surface;
+	renderer->base.destroy_view = rpi_renderer_destroy_view;
 	renderer->base.destroy = rpi_renderer_destroy;
 
 #ifdef ENABLE_EGL
@@ -1504,8 +1613,8 @@ rpi_renderer_output_create(struct weston_output *base,
 
 	output->display = display;
 	output->update = DISPMANX_NO_HANDLE;
-	wl_list_init(&output->surface_list);
-	wl_list_init(&output->surface_cleanup_list);
+	wl_list_init(&output->view_list);
+	wl_list_init(&output->view_cleanup_list);
 	rpi_resource_init(&output->capture_buffer);
 	base->renderer_state = output;
 
@@ -1516,7 +1625,7 @@ WL_EXPORT void
 rpi_renderer_output_destroy(struct weston_output *base)
 {
 	struct rpir_output *output = to_rpir_output(base);
-	struct rpir_surface *surface;
+	struct rpir_view *view;
 	DISPMANX_UPDATE_HANDLE_T update;
 
 	rpi_resource_release(&output->capture_buffer);
@@ -1527,12 +1636,10 @@ rpi_renderer_output_destroy(struct weston_output *base)
 	rpir_output_dmx_remove_all(output, update);
 	vc_dispmanx_update_submit_sync(update);
 
-	while (!wl_list_empty(&output->surface_cleanup_list)) {
-		surface = container_of(output->surface_cleanup_list.next,
-				       struct rpir_surface, link);
-		if (surface->surface)
-			surface->surface->renderer_state = NULL;
-		rpir_surface_destroy(surface);
+	while (!wl_list_empty(&output->view_cleanup_list)) {
+		view = container_of(output->view_cleanup_list.next,
+				    struct rpir_view, link);
+		rpir_view_destroy(view);
 	}
 
 	free(output);
@@ -1553,41 +1660,41 @@ rpi_renderer_finish_frame(struct weston_output *base)
 {
 	struct rpir_output *output = to_rpir_output(base);
 	struct weston_compositor *compositor = base->compositor;
-	struct weston_surface *ws;
-	struct rpir_surface *surface;
+	struct weston_view *wv;
+	struct rpir_view *view;
 
-	while (!wl_list_empty(&output->surface_cleanup_list)) {
-		surface = container_of(output->surface_cleanup_list.next,
-				       struct rpir_surface, link);
+	while (!wl_list_empty(&output->view_cleanup_list)) {
+		view = container_of(output->view_cleanup_list.next,
+				    struct rpir_view, link);
 
-		if (surface->surface) {
-			/* The weston_surface still exists, but is
+		if (view->view) {
+			/* The weston_view still exists, but is
 			 * temporarily not visible, and hence its Element
 			 * was removed. The current front buffer contents
 			 * must be preserved.
 			 */
-			if (!surface->single_buffer)
-				rpi_resource_release(surface->back);
+			if (!view->surface->visible_views)
+				rpi_resource_release(view->surface->back);
 
-			wl_list_remove(&surface->link);
-			wl_list_init(&surface->link);
+			wl_list_remove(&view->link);
+			wl_list_init(&view->link);
 		} else {
-			rpir_surface_destroy(surface);
+			rpir_view_destroy(view);
 		}
 	}
 
-	wl_list_for_each(ws, &compositor->surface_list, link) {
-		surface = to_rpir_surface(ws);
+	wl_list_for_each(wv, &compositor->view_list, link) {
+		view = to_rpir_view(wv);
 
-		if (surface->buffer_type != BUFFER_TYPE_EGL)
+		if (view->surface->buffer_type != BUFFER_TYPE_EGL)
 			continue;
 
-		if(surface->egl_old_front == NULL)
+		if (view->surface->egl_old_front == NULL)
 			continue;
 
-		weston_buffer_reference(&surface->egl_old_front->buffer_ref, NULL);
-		free(surface->egl_old_front);
-		surface->egl_old_front = NULL;
+		weston_buffer_reference(&view->surface->egl_old_front->buffer_ref, NULL);
+		free(view->surface->egl_old_front);
+		view->surface->egl_old_front = NULL;
 	}
 
 	wl_signal_emit(&base->frame_signal, base);
diff --git a/src/shell.c b/src/shell.c
index e0c352724d99ce92e76db0a3cbc9374dda64c703..9663870419f83c9dc48e4924f8494664cdd83e59 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -79,6 +79,7 @@ struct input_panel_surface {
 
 	struct wl_list link;
 	struct weston_surface *surface;
+	struct weston_view *view;
 	struct wl_listener surface_destroy_listener;
 
 	struct weston_output *output;
@@ -155,8 +156,8 @@ struct desktop_shell {
 	} input_panel;
 
 	struct {
-		struct weston_surface *surface;
-		struct weston_surface_animation *animation;
+		struct weston_view *view;
+		struct weston_view_animation *animation;
 		enum fade_type type;
 		struct wl_event_source *startup_timer;
 	} fade;
@@ -186,6 +187,7 @@ struct shell_surface {
 	struct wl_signal destroy_signal;
 
 	struct weston_surface *surface;
+	struct weston_view *view;
 	struct wl_listener surface_destroy_listener;
 	struct weston_surface *parent;
 	struct desktop_shell *shell;
@@ -218,7 +220,7 @@ struct shell_surface {
 		enum wl_shell_surface_fullscreen_method type;
 		struct weston_transform transform; /* matrix from x, y */
 		uint32_t framerate;
-		struct weston_surface *black_surface;
+		struct weston_view *black_view;
 	} fullscreen;
 
 	struct ping_timer *ping_timer;
@@ -299,17 +301,17 @@ static bool
 shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
 {
 	struct desktop_shell *shell;
-	struct weston_surface *top_fs_es;
+	struct weston_view *top_fs_ev;
 
 	shell = shell_surface_get_shell(shsurf);
 
-	if (wl_list_empty(&shell->fullscreen_layer.surface_list))
+	if (wl_list_empty(&shell->fullscreen_layer.view_list))
 		return false;
 
-	top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
-			         struct weston_surface,
+	top_fs_ev = container_of(shell->fullscreen_layer.view_list.next,
+			         struct weston_view,
 				 layer_link);
-	return (shsurf == get_shell_surface(top_fs_es));
+	return (shsurf == get_shell_surface(top_fs_ev->surface));
 }
 
 static void
@@ -323,6 +325,26 @@ destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
 	grab->shsurf = NULL;
 }
 
+static struct weston_view *
+get_default_view(struct weston_surface *surface)
+{
+	struct shell_surface *shsurf;
+	struct weston_view *view;
+
+	if (!surface || wl_list_empty(&surface->views))
+		return NULL;
+
+	shsurf = get_shell_surface(surface);
+	if (shsurf)
+		return shsurf->view;
+
+	wl_list_for_each(view, &surface->views, surface_link)
+		if (weston_view_is_mapped(view))
+			return view;
+
+	return container_of(surface->views.next, struct weston_view, surface_link);
+}
+
 static void
 popup_grab_end(struct weston_pointer *pointer);
 
@@ -347,7 +369,8 @@ shell_grab_start(struct shell_grab *grab,
 	if (shell->child.desktop_shell) {
 		desktop_shell_send_grab_cursor(shell->child.desktop_shell,
 					       cursor);
-		weston_pointer_set_focus(pointer, shell->grab_surface,
+		weston_pointer_set_focus(pointer,
+					 get_default_view(shell->grab_surface),
 					 wl_fixed_from_int(0),
 					 wl_fixed_from_int(0));
 	}
@@ -380,7 +403,8 @@ shell_touch_grab_start(struct shell_touch_grab *grab,
 
 	weston_touch_start_grab(touch, &grab->grab);
 	if (shell->child.desktop_shell)
-		weston_touch_set_focus(touch->seat, shell->grab_surface);
+		weston_touch_set_focus(touch->seat,
+				       get_default_view(shell->grab_surface));
 }
 
 static void
@@ -393,7 +417,7 @@ shell_touch_grab_end(struct shell_touch_grab *grab)
 }
 
 static void
-center_on_output(struct weston_surface *surface,
+center_on_output(struct weston_view *view,
 		 struct weston_output *output);
 
 static enum weston_keyboard_modifier
@@ -481,17 +505,17 @@ focus_state_surface_destroy(struct wl_listener *listener, void *data)
 						 struct focus_state,
 						 surface_destroy_listener);
 	struct desktop_shell *shell;
-	struct weston_surface *main_surface;
-	struct weston_surface *surface, *next;
+	struct weston_surface *main_surface, *next;
+	struct weston_view *view;
 
 	main_surface = weston_surface_get_main_surface(state->keyboard_focus);
 
 	next = NULL;
-	wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) {
-		if (surface == main_surface)
+	wl_list_for_each(view, &state->ws->layer.view_list, layer_link) {
+		if (view->surface == main_surface)
 			continue;
 
-		next = surface;
+		next = view->surface;
 		break;
 	}
 
@@ -630,7 +654,7 @@ workspace_create(void)
 static int
 workspace_is_empty(struct workspace *ws)
 {
-	return wl_list_empty(&ws->layer.surface_list);
+	return wl_list_empty(&ws->layer.view_list);
 }
 
 static struct workspace *
@@ -666,53 +690,53 @@ get_output_height(struct weston_output *output)
 }
 
 static void
-surface_translate(struct weston_surface *surface, double d)
+view_translate(struct weston_view *view, double d)
 {
-	struct shell_surface *shsurf = get_shell_surface(surface);
+	struct shell_surface *shsurf = get_shell_surface(view->surface);
 	struct weston_transform *transform;
 
 	transform = &shsurf->workspace_transform;
 	if (wl_list_empty(&transform->link))
-		wl_list_insert(surface->geometry.transformation_list.prev,
+		wl_list_insert(view->geometry.transformation_list.prev,
 			       &shsurf->workspace_transform.link);
 
 	weston_matrix_init(&shsurf->workspace_transform.matrix);
 	weston_matrix_translate(&shsurf->workspace_transform.matrix,
 				0.0, d, 0.0);
-	weston_surface_geometry_dirty(surface);
+	weston_view_geometry_dirty(view);
 }
 
 static void
 workspace_translate_out(struct workspace *ws, double fraction)
 {
-	struct weston_surface *surface;
+	struct weston_view *view;
 	unsigned int height;
 	double d;
 
-	wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
-		height = get_output_height(surface->output);
+	wl_list_for_each(view, &ws->layer.view_list, layer_link) {
+		height = get_output_height(view->surface->output);
 		d = height * fraction;
 
-		surface_translate(surface, d);
+		view_translate(view, d);
 	}
 }
 
 static void
 workspace_translate_in(struct workspace *ws, double fraction)
 {
-	struct weston_surface *surface;
+	struct weston_view *view;
 	unsigned int height;
 	double d;
 
-	wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
-		height = get_output_height(surface->output);
+	wl_list_for_each(view, &ws->layer.view_list, layer_link) {
+		height = get_output_height(view->surface->output);
 
 		if (fraction > 0)
 			d = -(height - height * fraction);
 		else
 			d = height + height * fraction;
 
-		surface_translate(surface, d);
+		view_translate(view, d);
 	}
 }
 
@@ -746,16 +770,16 @@ reverse_workspace_change_animation(struct desktop_shell *shell,
 static void
 workspace_deactivate_transforms(struct workspace *ws)
 {
-	struct weston_surface *surface;
+	struct weston_view *view;
 	struct shell_surface *shsurf;
 
-	wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
-		shsurf = get_shell_surface(surface);
+	wl_list_for_each(view, &ws->layer.view_list, layer_link) {
+		shsurf = get_shell_surface(view->surface);
 		if (!wl_list_empty(&shsurf->workspace_transform.link)) {
 			wl_list_remove(&shsurf->workspace_transform.link);
 			wl_list_init(&shsurf->workspace_transform.link);
 		}
-		weston_surface_geometry_dirty(surface);
+		weston_view_geometry_dirty(view);
 	}
 }
 
@@ -881,7 +905,7 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
 		return;
 
 	/* Don't change workspace when there is any fullscreen surfaces. */
-	if (!wl_list_empty(&shell->fullscreen_layer.surface_list))
+	if (!wl_list_empty(&shell->fullscreen_layer.view_list))
 		return;
 
 	from = get_current_workspace(shell);
@@ -913,7 +937,7 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
 static bool
 workspace_has_only(struct workspace *ws, struct weston_surface *surface)
 {
-	struct wl_list *list = &ws->layer.surface_list;
+	struct wl_list *list = &ws->layer.view_list;
 	struct wl_list *e;
 
 	if (wl_list_empty(list))
@@ -924,20 +948,20 @@ workspace_has_only(struct workspace *ws, struct weston_surface *surface)
 	if (e->next != list)
 		return false;
 
-	return container_of(e, struct weston_surface, layer_link) == surface;
+	return container_of(e, struct weston_view, layer_link)->surface == surface;
 }
 
 static void
-move_surface_to_workspace(struct desktop_shell *shell,
-			  struct weston_surface *surface,
-			  uint32_t workspace)
+move_view_to_workspace(struct desktop_shell *shell,
+		       struct weston_view *view,
+		       uint32_t workspace)
 {
 	struct workspace *from;
 	struct workspace *to;
 	struct weston_seat *seat;
 	struct weston_surface *focus;
 
-	assert(weston_surface_get_main_surface(surface) == surface);
+	assert(weston_surface_get_main_surface(view->surface) == view->surface);
 
 	if (workspace == shell->workspaces.current)
 		return;
@@ -948,20 +972,20 @@ move_surface_to_workspace(struct desktop_shell *shell,
 	from = get_current_workspace(shell);
 	to = get_workspace(shell, workspace);
 
-	wl_list_remove(&surface->layer_link);
-	wl_list_insert(&to->layer.surface_list, &surface->layer_link);
+	wl_list_remove(&view->layer_link);
+	wl_list_insert(&to->layer.view_list, &view->layer_link);
 
-	drop_focus_state(shell, from, surface);
+	drop_focus_state(shell, from, view->surface);
 	wl_list_for_each(seat, &shell->compositor->seat_list, link) {
 		if (!seat->keyboard)
 			continue;
 
 		focus = weston_surface_get_main_surface(seat->keyboard->focus);
-		if (focus == surface)
+		if (focus == view->surface)
 			weston_keyboard_set_focus(seat->keyboard, NULL);
 	}
 
-	weston_surface_damage_below(surface);
+	weston_view_damage_below(view);
 }
 
 static void
@@ -970,21 +994,23 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell,
 				  unsigned int index)
 {
 	struct weston_surface *surface;
+	struct weston_view *view;
 	struct shell_surface *shsurf;
 	struct workspace *from;
 	struct workspace *to;
 	struct focus_state *state;
 
 	surface = weston_surface_get_main_surface(seat->keyboard->focus);
-	if (surface == NULL ||
+	view = get_default_view(surface);
+	if (view == NULL ||
 	    index == shell->workspaces.current)
 		return;
 
 	from = get_current_workspace(shell);
 	to = get_workspace(shell, index);
 
-	wl_list_remove(&surface->layer_link);
-	wl_list_insert(&to->layer.surface_list, &surface->layer_link);
+	wl_list_remove(&view->layer_link);
+	wl_list_insert(&to->layer.view_list, &view->layer_link);
 
 	replace_focus_state(shell, to, seat);
 	drop_focus_state(shell, from, surface);
@@ -1034,9 +1060,13 @@ workspace_manager_move_surface(struct wl_client *client,
 	struct weston_surface *surface =
 		wl_resource_get_user_data(surface_resource);
 	struct weston_surface *main_surface;
+	struct weston_view *view;
 
 	main_surface = weston_surface_get_main_surface(surface);
-	move_surface_to_workspace(shell, main_surface, workspace);
+	view = get_default_view(main_surface);
+	if (!view)
+		return;
+	move_view_to_workspace(shell, view, workspace);
 }
 
 static const struct workspace_manager_interface workspace_manager_implementation = {
@@ -1107,8 +1137,9 @@ touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time,
 
 	es = shsurf->surface;
 
-	weston_surface_configure(es, dx, dy,
-				 es->geometry.width, es->geometry.height);
+	weston_view_configure(shsurf->view, dx, dy,
+			      shsurf->view->geometry.width,
+			      shsurf->view->geometry.height);
 
 	weston_compositor_schedule_repaint(es->compositor);
 }
@@ -1134,9 +1165,9 @@ surface_touch_move(struct shell_surface *shsurf, struct weston_seat *seat)
 	if (!move)
 		return -1;
 
-	move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
+	move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
 			seat->touch->grab_x;
-	move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
+	move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
 			seat->touch->grab_y;
 
 	shell_touch_grab_start(&move->base, &touch_move_grab_interface, shsurf,
@@ -1156,19 +1187,17 @@ move_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
 	struct weston_move_grab *move = (struct weston_move_grab *) grab;
 	struct weston_pointer *pointer = grab->pointer;
 	struct shell_surface *shsurf = move->base.shsurf;
-	struct weston_surface *es;
 	int dx = wl_fixed_to_int(pointer->x + move->dx);
 	int dy = wl_fixed_to_int(pointer->y + move->dy);
 
 	if (!shsurf)
 		return;
 
-	es = shsurf->surface;
-
-	weston_surface_configure(es, dx, dy,
-				 es->geometry.width, es->geometry.height);
+	weston_view_configure(shsurf->view, dx, dy,
+			      shsurf->view->geometry.width,
+			      shsurf->view->geometry.height);
 
-	weston_compositor_schedule_repaint(es->compositor);
+	weston_compositor_schedule_repaint(shsurf->surface->compositor);
 }
 
 static void
@@ -1208,9 +1237,9 @@ surface_move(struct shell_surface *shsurf, struct weston_seat *seat)
 	if (!move)
 		return -1;
 
-	move->dx = wl_fixed_from_double(shsurf->surface->geometry.x) -
+	move->dx = wl_fixed_from_double(shsurf->view->geometry.x) -
 			seat->pointer->grab_x;
-	move->dy = wl_fixed_from_double(shsurf->surface->geometry.y) -
+	move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
 			seat->pointer->grab_y;
 
 	shell_grab_start(&move->base, &move_grab_interface, shsurf,
@@ -1230,13 +1259,13 @@ shell_surface_move(struct wl_client *client, struct wl_resource *resource,
 	if (seat->pointer &&
 	    seat->pointer->button_count > 0 &&
 	    seat->pointer->grab_serial == serial) {
-		surface = weston_surface_get_main_surface(seat->pointer->focus);
+		surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
 		if ((surface == shsurf->surface) && 
 		    (surface_move(shsurf, seat) < 0))
 			wl_resource_post_no_memory(resource);
 	} else if (seat->touch &&
 		   seat->touch->grab_serial == serial) {
-		surface = weston_surface_get_main_surface(seat->touch->focus);
+		surface = weston_surface_get_main_surface(seat->touch->focus->surface);
 		if ((surface == shsurf->surface) && 
 		    (surface_touch_move(shsurf, seat) < 0))
 			wl_resource_post_no_memory(resource);
@@ -1262,11 +1291,11 @@ resize_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
 	if (!shsurf)
 		return;
 
-	weston_surface_from_global_fixed(shsurf->surface,
-				         pointer->grab_x, pointer->grab_y,
-				         &from_x, &from_y);
-	weston_surface_from_global_fixed(shsurf->surface,
-				         pointer->x, pointer->y, &to_x, &to_y);
+	weston_view_from_global_fixed(shsurf->view,
+				      pointer->grab_x, pointer->grab_y,
+				      &from_x, &from_y);
+	weston_view_from_global_fixed(shsurf->view,
+				      pointer->x, pointer->y, &to_x, &to_y);
 
 	width = resize->width;
 	if (resize->edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
@@ -1332,15 +1361,15 @@ surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
 	struct weston_subsurface *subsurface;
 
 	pixman_region32_init_rect(&region, 0, 0,
-	                          surface->geometry.width,
-	                          surface->geometry.height);
+	                          surface->width,
+	                          surface->height);
 
 	wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
 		pixman_region32_union_rect(&region, &region,
 		                           subsurface->position.x,
 		                           subsurface->position.y,
-		                           subsurface->surface->geometry.width,
-		                           subsurface->surface->geometry.height);
+		                           subsurface->surface->width,
+		                           subsurface->surface->height);
 	}
 
 	box = pixman_region32_extents(&region);
@@ -1396,7 +1425,7 @@ shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
 	if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
 		return;
 
-	surface = weston_surface_get_main_surface(seat->pointer->focus);
+	surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
 	if (seat->pointer->button_count == 0 ||
 	    seat->pointer->grab_serial != serial ||
 	    surface != shsurf->surface)
@@ -1414,14 +1443,14 @@ busy_cursor_grab_focus(struct weston_pointer_grab *base)
 {
 	struct shell_grab *grab = (struct shell_grab *) base;
 	struct weston_pointer *pointer = base->pointer;
-	struct weston_surface *surface;
+	struct weston_view *view;
 	wl_fixed_t sx, sy;
 
-	surface = weston_compositor_pick_surface(pointer->seat->compositor,
-						 pointer->x, pointer->y,
-						 &sx, &sy);
+	view = weston_compositor_pick_view(pointer->seat->compositor,
+					   pointer->x, pointer->y,
+					   &sx, &sy);
 
-	if (!grab->shsurf || grab->shsurf->surface != surface)
+	if (!grab->shsurf || grab->shsurf->surface != view->surface)
 		end_busy_cursor(grab->shsurf, pointer);
 }
 
@@ -1501,7 +1530,7 @@ ping_timeout_handler(void *data)
 	shsurf->unresponsive = 1;
 
 	wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link)
-		if (seat->pointer->focus == shsurf->surface)
+		if (seat->pointer->focus->surface == shsurf->surface)
 			set_busy_cursor(shsurf, seat->pointer);
 
 	return 1;
@@ -1541,22 +1570,22 @@ static void
 handle_pointer_focus(struct wl_listener *listener, void *data)
 {
 	struct weston_pointer *pointer = data;
-	struct weston_surface *surface = pointer->focus;
+	struct weston_view *view = pointer->focus;
 	struct weston_compositor *compositor;
 	struct shell_surface *shsurf;
 	uint32_t serial;
 
-	if (!surface)
+	if (!view)
 		return;
 
-	compositor = surface->compositor;
-	shsurf = get_shell_surface(surface);
+	compositor = view->surface->compositor;
+	shsurf = get_shell_surface(view->surface);
 
 	if (shsurf && shsurf->unresponsive) {
 		set_busy_cursor(shsurf, pointer);
 	} else {
 		serial = wl_display_next_serial(compositor->wl_display);
-		ping_handler(surface, serial);
+		ping_handler(view->surface, serial);
 	}
 }
 
@@ -1661,21 +1690,21 @@ shell_unset_fullscreen(struct shell_surface *shsurf)
 	shsurf->fullscreen.framerate = 0;
 	wl_list_remove(&shsurf->fullscreen.transform.link);
 	wl_list_init(&shsurf->fullscreen.transform.link);
-	if (shsurf->fullscreen.black_surface)
-		weston_surface_destroy(shsurf->fullscreen.black_surface);
-	shsurf->fullscreen.black_surface = NULL;
+	if (shsurf->fullscreen.black_view)
+		weston_surface_destroy(shsurf->fullscreen.black_view->surface);
+	shsurf->fullscreen.black_view = NULL;
 	shsurf->fullscreen_output = NULL;
-	weston_surface_set_position(shsurf->surface,
-				    shsurf->saved_x, shsurf->saved_y);
+	weston_view_set_position(shsurf->view,
+				 shsurf->saved_x, shsurf->saved_y);
 	if (shsurf->saved_rotation_valid) {
-		wl_list_insert(&shsurf->surface->geometry.transformation_list,
+		wl_list_insert(&shsurf->view->geometry.transformation_list,
         	               &shsurf->rotation.transform.link);
 		shsurf->saved_rotation_valid = false;
 	}
 
 	ws = get_current_workspace(shsurf->shell);
-	wl_list_remove(&shsurf->surface->layer_link);
-	wl_list_insert(&ws->layer.surface_list, &shsurf->surface->layer_link);
+	wl_list_remove(&shsurf->view->layer_link);
+	wl_list_insert(&ws->layer.view_list, &shsurf->view->layer_link);
 }
 
 static void
@@ -1684,19 +1713,19 @@ shell_unset_maximized(struct shell_surface *shsurf)
 	struct workspace *ws;
 	/* undo all maximized things here */
 	shsurf->output = get_default_output(shsurf->surface->compositor);
-	weston_surface_set_position(shsurf->surface,
-				    shsurf->saved_x,
-				    shsurf->saved_y);
+	weston_view_set_position(shsurf->view,
+				 shsurf->saved_x,
+				 shsurf->saved_y);
 
 	if (shsurf->saved_rotation_valid) {
-		wl_list_insert(&shsurf->surface->geometry.transformation_list,
-						   &shsurf->rotation.transform.link);
+		wl_list_insert(&shsurf->view->geometry.transformation_list,
+			       &shsurf->rotation.transform.link);
 		shsurf->saved_rotation_valid = false;
 	}
 
 	ws = get_current_workspace(shsurf->shell);
-	wl_list_remove(&shsurf->surface->layer_link);
-	wl_list_insert(&ws->layer.surface_list, &shsurf->surface->layer_link);
+	wl_list_remove(&shsurf->view->layer_link);
+	wl_list_insert(&ws->layer.view_list, &shsurf->view->layer_link);
 }
 
 static int
@@ -1724,8 +1753,8 @@ reset_shell_surface_type(struct shell_surface *surface)
 static void
 set_surface_type(struct shell_surface *shsurf)
 {
-	struct weston_surface *surface = shsurf->surface;
 	struct weston_surface *pes = shsurf->parent;
+	struct weston_view *pev = get_default_view(pes);
 
 	reset_shell_surface_type(shsurf);
 
@@ -1736,28 +1765,29 @@ set_surface_type(struct shell_surface *shsurf)
 	case SHELL_SURFACE_TOPLEVEL:
 		break;
 	case SHELL_SURFACE_TRANSIENT:
-		weston_surface_set_position(surface,
-				pes->geometry.x + shsurf->transient.x,
-				pes->geometry.y + shsurf->transient.y);
+		if (pev)
+			weston_view_set_position(shsurf->view,
+						 pev->geometry.x + shsurf->transient.x,
+						 pev->geometry.y + shsurf->transient.y);
 		break;
 
 	case SHELL_SURFACE_MAXIMIZED:
 	case SHELL_SURFACE_FULLSCREEN:
-		shsurf->saved_x = surface->geometry.x;
-		shsurf->saved_y = surface->geometry.y;
+		shsurf->saved_x = shsurf->view->geometry.x;
+		shsurf->saved_y = shsurf->view->geometry.y;
 		shsurf->saved_position_valid = true;
 
 		if (!wl_list_empty(&shsurf->rotation.transform.link)) {
 			wl_list_remove(&shsurf->rotation.transform.link);
 			wl_list_init(&shsurf->rotation.transform.link);
-			weston_surface_geometry_dirty(shsurf->surface);
+			weston_view_geometry_dirty(shsurf->view);
 			shsurf->saved_rotation_valid = true;
 		}
 		break;
 
 	case SHELL_SURFACE_XWAYLAND:
-		weston_surface_set_position(surface, shsurf->transient.x,
-					    shsurf->transient.y);
+		weston_view_set_position(shsurf->view, shsurf->transient.x,
+					 shsurf->transient.y);
 		break;
 
 	default:
@@ -1815,15 +1845,15 @@ static int
 get_output_panel_height(struct desktop_shell *shell,
 			struct weston_output *output)
 {
-	struct weston_surface *surface;
+	struct weston_view *view;
 	int panel_height = 0;
 
 	if (!output)
 		return 0;
 
-	wl_list_for_each(surface, &shell->panel_layer.surface_list, layer_link) {
-		if (surface->output == output) {
-			panel_height = surface->geometry.height;
+	wl_list_for_each(view, &shell->panel_layer.view_list, layer_link) {
+		if (view->surface->output == output) {
+			panel_height = view->geometry.height;
 			break;
 		}
 	}
@@ -1864,29 +1894,37 @@ shell_surface_set_maximized(struct wl_client *client,
 static void
 black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height);
 
-static struct weston_surface *
+static struct weston_view *
 create_black_surface(struct weston_compositor *ec,
 		     struct weston_surface *fs_surface,
 		     float x, float y, int w, int h)
 {
 	struct weston_surface *surface = NULL;
+	struct weston_view *view;
 
 	surface = weston_surface_create(ec);
 	if (surface == NULL) {
 		weston_log("no memory\n");
 		return NULL;
 	}
+	view = weston_view_create(surface);
+	if (surface == NULL) {
+		weston_log("no memory\n");
+		weston_surface_destroy(surface);
+		return NULL;
+	}
 
 	surface->configure = black_surface_configure;
 	surface->configure_private = fs_surface;
-	weston_surface_configure(surface, x, y, w, h);
 	weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
 	pixman_region32_fini(&surface->opaque);
 	pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
 	pixman_region32_fini(&surface->input);
 	pixman_region32_init_rect(&surface->input, 0, 0, w, h);
 
-	return surface;
+	weston_view_configure(view, x, y, w, h);
+
+	return view;
 }
 
 /* Create black surface and append it to the associated fullscreen surface.
@@ -1903,33 +1941,35 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 	if (shsurf->fullscreen.type != WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER)
 		restore_output_mode(output);
 
-	if (!shsurf->fullscreen.black_surface)
-		shsurf->fullscreen.black_surface =
+	if (!shsurf->fullscreen.black_view)
+		shsurf->fullscreen.black_view =
 			create_black_surface(surface->compositor,
 					     surface,
 					     output->x, output->y,
 					     output->width,
 					     output->height);
 
-	wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
-	wl_list_insert(&surface->layer_link,
-		       &shsurf->fullscreen.black_surface->layer_link);
-	shsurf->fullscreen.black_surface->output = output;
+	wl_list_remove(&shsurf->fullscreen.black_view->layer_link);
+	wl_list_insert(&shsurf->view->layer_link,
+		       &shsurf->fullscreen.black_view->layer_link);
+	shsurf->fullscreen.black_view->surface->output = output;
+	shsurf->fullscreen.black_view->output = output;
 
-	surface_subsurfaces_boundingbox(surface, &surf_x, &surf_y,
+	surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
 	                                &surf_width, &surf_height);
 
 	switch (shsurf->fullscreen.type) {
 	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
 		if (surface->buffer_ref.buffer)
-			center_on_output(surface, shsurf->fullscreen_output);
+			center_on_output(shsurf->view, shsurf->fullscreen_output);
 		break;
 	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
 		/* 1:1 mapping between surface and output dimensions */
 		if (output->width == surf_width &&
 			output->height == surf_height) {
-			weston_surface_set_position(surface, output->x - surf_x,
-			                                     output->y - surf_y);
+			weston_view_set_position(shsurf->view,
+						 output->x - surf_x,
+						 output->y - surf_y);
 			break;
 		}
 
@@ -1938,8 +1978,9 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 
 		output_aspect = (float) output->width /
 			(float) output->height;
-		surface_aspect = (float) surface->geometry.width /
-			(float) surface->geometry.height;
+		/* XXX: Use surf_width and surf_height here? */
+		surface_aspect = (float) surface->width /
+			(float) surface->height;
 		if (output_aspect < surface_aspect)
 			scale = (float) output->width /
 				(float) surf_width;
@@ -1949,11 +1990,11 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 
 		weston_matrix_scale(matrix, scale, scale, 1);
 		wl_list_remove(&shsurf->fullscreen.transform.link);
-		wl_list_insert(&surface->geometry.transformation_list,
+		wl_list_insert(&shsurf->view->geometry.transformation_list,
 			       &shsurf->fullscreen.transform.link);
 		x = output->x + (output->width - surf_width * scale) / 2 - surf_x;
 		y = output->y + (output->height - surf_height * scale) / 2 - surf_y;
-		weston_surface_set_position(surface, x, y);
+		weston_view_set_position(shsurf->view, x, y);
 
 		break;
 	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
@@ -1965,23 +2006,23 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 
 			if (weston_output_switch_mode(output, &mode, surface->buffer_scale,
 					WESTON_MODE_SWITCH_SET_TEMPORARY) == 0) {
-				weston_surface_set_position(surface,
-							    output->x - surf_x,
-							    output->y - surf_y);
-				weston_surface_configure(shsurf->fullscreen.black_surface,
-					                 output->x - surf_x,
-					                 output->y - surf_y,
-							 output->width,
-							 output->height);
+				weston_view_set_position(shsurf->view,
+							 output->x - surf_x,
+							 output->y - surf_y);
+				weston_view_configure(shsurf->fullscreen.black_view,
+						      output->x - surf_x,
+						      output->y - surf_y,
+						      output->width,
+						      output->height);
 				break;
 			} else {
 				restore_output_mode(output);
-				center_on_output(surface, output);
+				center_on_output(shsurf->view, output);
 			}
 		}
 		break;
 	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
-		center_on_output(surface, output);
+		center_on_output(shsurf->view, output);
 		break;
 	default:
 		break;
@@ -1993,26 +2034,25 @@ static void
 shell_stack_fullscreen(struct shell_surface *shsurf)
 {
 	struct weston_output *output = shsurf->fullscreen_output;
-	struct weston_surface *surface = shsurf->surface;
 	struct desktop_shell *shell = shell_surface_get_shell(shsurf);
 
-	wl_list_remove(&surface->layer_link);
-	wl_list_insert(&shell->fullscreen_layer.surface_list,
-		       &surface->layer_link);
-	weston_surface_damage(surface);
+	wl_list_remove(&shsurf->view->layer_link);
+	wl_list_insert(&shell->fullscreen_layer.view_list,
+		       &shsurf->view->layer_link);
+	weston_surface_damage(shsurf->surface);
 
-	if (!shsurf->fullscreen.black_surface)
-		shsurf->fullscreen.black_surface =
-			create_black_surface(surface->compositor,
-					     surface,
+	if (!shsurf->fullscreen.black_view)
+		shsurf->fullscreen.black_view =
+			create_black_surface(shsurf->surface->compositor,
+					     shsurf->surface,
 					     output->x, output->y,
 					     output->width,
 					     output->height);
 
-	wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
-	wl_list_insert(&surface->layer_link,
-		       &shsurf->fullscreen.black_surface->layer_link);
-	weston_surface_damage(shsurf->fullscreen.black_surface);
+	wl_list_remove(&shsurf->fullscreen.black_view->layer_link);
+	wl_list_insert(&shsurf->view->layer_link,
+		       &shsurf->fullscreen.black_view->layer_link);
+	weston_surface_damage(shsurf->fullscreen.black_view->surface);
 }
 
 static void
@@ -2141,18 +2181,19 @@ static void
 popup_grab_focus(struct weston_pointer_grab *grab)
 {
 	struct weston_pointer *pointer = grab->pointer;
-	struct weston_surface *surface;
+	struct weston_view *view;
 	struct shell_seat *shseat =
 	    container_of(grab, struct shell_seat, popup_grab.grab);
 	struct wl_client *client = shseat->popup_grab.client;
 	wl_fixed_t sx, sy;
 
-	surface = weston_compositor_pick_surface(pointer->seat->compositor,
-						 pointer->x, pointer->y,
-						 &sx, &sy);
+	view = weston_compositor_pick_view(pointer->seat->compositor,
+					   pointer->x, pointer->y,
+					   &sx, &sy);
 
-	if (surface && wl_resource_get_client(surface->resource) == client) {
-		weston_pointer_set_focus(pointer, surface, sx, sy);
+	if (view && view->surface->resource &&
+	    wl_resource_get_client(view->surface->resource) == client) {
+		weston_pointer_set_focus(pointer, view, sx, sy);
 	} else {
 		weston_pointer_set_focus(pointer, NULL,
 					 wl_fixed_from_int(0),
@@ -2168,9 +2209,9 @@ popup_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
 	wl_fixed_t sx, sy;
 
 	wl_resource_for_each(resource, &pointer->focus_resource_list) {
-		weston_surface_from_global_fixed(pointer->focus,
-						 pointer->x, pointer->y,
-						 &sx, &sy);
+		weston_view_from_global_fixed(pointer->focus,
+					      pointer->x, pointer->y,
+					      &sx, &sy);
 		wl_pointer_send_motion(resource, time, sx, sy);
 	}
 }
@@ -2276,14 +2317,14 @@ static void
 shell_map_popup(struct shell_surface *shsurf)
 {
 	struct shell_seat *shseat = shsurf->popup.shseat;
-	struct weston_surface *es = shsurf->surface;
-	struct weston_surface *parent = shsurf->parent;
+	struct weston_view *parent_view = get_default_view(shsurf->parent);
 
-	es->output = parent->output;
+	shsurf->surface->output = parent_view->output;
+	shsurf->view->output = parent_view->output;
 
-	weston_surface_set_transform_parent(es, parent);
-	weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
-	weston_surface_update_transform(es);
+	weston_view_set_transform_parent(shsurf->view, parent_view);
+	weston_view_set_position(shsurf->view, shsurf->popup.x, shsurf->popup.y);
+	weston_view_update_transform(shsurf->view);
 
 	if (shseat->seat->pointer->grab_serial == shsurf->popup.serial) {
 		add_popup_grab(shsurf, shseat);
@@ -2337,8 +2378,8 @@ destroy_shell_surface(struct shell_surface *shsurf)
 	    shell_surface_is_top_fullscreen(shsurf))
 		restore_output_mode (shsurf->fullscreen_output);
 
-	if (shsurf->fullscreen.black_surface)
-		weston_surface_destroy(shsurf->fullscreen.black_surface);
+	if (shsurf->fullscreen.black_view)
+		weston_surface_destroy(shsurf->fullscreen.black_view->surface);
 
 	/* As destroy_resource() use wl_list_for_each_safe(),
 	 * we can always remove the listener.
@@ -2348,6 +2389,8 @@ destroy_shell_surface(struct shell_surface *shsurf)
 	ping_timer_destroy(shsurf);
 	free(shsurf->title);
 
+	weston_view_destroy(shsurf->view);
+
 	wl_list_remove(&shsurf->link);
 	free(shsurf);
 }
@@ -2402,6 +2445,13 @@ create_shell_surface(void *shell, struct weston_surface *surface,
 		return NULL;
 	}
 
+	shsurf->view = weston_view_create(surface);
+	if (!shsurf->view) {
+		weston_log("no memory to allocate shell surface\n");
+		free(shsurf);
+		return NULL;
+	}
+
 	surface->configure = shell_surface_configure;
 	surface->configure_private = shsurf;
 
@@ -2412,7 +2462,7 @@ create_shell_surface(void *shell, struct weston_surface *surface,
 	shsurf->surface = surface;
 	shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
 	shsurf->fullscreen.framerate = 0;
-	shsurf->fullscreen.black_surface = NULL;
+	shsurf->fullscreen.black_view = NULL;
 	shsurf->ping_timer = NULL;
 	wl_list_init(&shsurf->fullscreen.transform.link);
 
@@ -2439,6 +2489,12 @@ create_shell_surface(void *shell, struct weston_surface *surface,
 	return shsurf;
 }
 
+static struct weston_view *
+get_primary_view(void *shell, struct shell_surface *shsurf)
+{
+	return shsurf->view;
+}
+
 static void
 shell_get_shell_surface(struct wl_client *client,
 			struct wl_resource *resource,
@@ -2534,25 +2590,25 @@ terminate_screensaver(struct desktop_shell *shell)
 }
 
 static void
-configure_static_surface(struct weston_surface *es, struct weston_layer *layer, int32_t width, int32_t height)
+configure_static_view(struct weston_view *ev, struct weston_layer *layer, int32_t width, int32_t height)
 {
-	struct weston_surface *s, *next;
+	struct weston_view *v, *next;
 
 	if (width == 0)
 		return;
 
-	wl_list_for_each_safe(s, next, &layer->surface_list, layer_link) {
-		if (s->output == es->output && s != es) {
-			weston_surface_unmap(s);
-			s->configure = NULL;
+	wl_list_for_each_safe(v, next, &layer->view_list, layer_link) {
+		if (v->output == ev->output && v != ev) {
+			weston_view_unmap(v);
+			v->surface->configure = NULL;
 		}
 	}
 
-	weston_surface_configure(es, es->output->x, es->output->y, width, height);
+	weston_view_configure(ev, ev->output->x, ev->output->y, width, height);
 
-	if (wl_list_empty(&es->layer_link)) {
-		wl_list_insert(&layer->surface_list, &es->layer_link);
-		weston_compositor_schedule_repaint(es->compositor);
+	if (wl_list_empty(&ev->layer_link)) {
+		wl_list_insert(&layer->view_list, &ev->layer_link);
+		weston_compositor_schedule_repaint(ev->surface->compositor);
 	}
 }
 
@@ -2560,8 +2616,11 @@ static void
 background_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height)
 {
 	struct desktop_shell *shell = es->configure_private;
+	struct weston_view *view;
 
-	configure_static_surface(es, &shell->background_layer, width, height);
+	view = container_of(es->views.next, struct weston_view, surface_link);
+
+	configure_static_view(view, &shell->background_layer, width, height);
 }
 
 static void
@@ -2573,6 +2632,7 @@ desktop_shell_set_background(struct wl_client *client,
 	struct desktop_shell *shell = wl_resource_get_user_data(resource);
 	struct weston_surface *surface =
 		wl_resource_get_user_data(surface_resource);
+	struct weston_view *view, *next;
 
 	if (surface->configure) {
 		wl_resource_post_error(surface_resource,
@@ -2581,9 +2641,14 @@ desktop_shell_set_background(struct wl_client *client,
 		return;
 	}
 
+	wl_list_for_each_safe(view, next, &surface->views, surface_link)
+		weston_view_destroy(view);
+	view = weston_view_create(surface);
+
 	surface->configure = background_configure;
 	surface->configure_private = shell;
 	surface->output = wl_resource_get_user_data(output_resource);
+	view->output = surface->output;
 	desktop_shell_send_configure(resource, 0,
 				     surface_resource,
 				     surface->output->width,
@@ -2594,8 +2659,11 @@ static void
 panel_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32_t width, int32_t height)
 {
 	struct desktop_shell *shell = es->configure_private;
+	struct weston_view *view;
+
+	view = container_of(es->views.next, struct weston_view, surface_link);
 
-	configure_static_surface(es, &shell->panel_layer, width, height);
+	configure_static_view(view, &shell->panel_layer, width, height);
 }
 
 static void
@@ -2607,6 +2675,7 @@ desktop_shell_set_panel(struct wl_client *client,
 	struct desktop_shell *shell = wl_resource_get_user_data(resource);
 	struct weston_surface *surface =
 		wl_resource_get_user_data(surface_resource);
+	struct weston_view *view, *next;
 
 	if (surface->configure) {
 		wl_resource_post_error(surface_resource,
@@ -2615,9 +2684,14 @@ desktop_shell_set_panel(struct wl_client *client,
 		return;
 	}
 
+	wl_list_for_each_safe(view, next, &surface->views, surface_link)
+		weston_view_destroy(view);
+	view = weston_view_create(surface);
+
 	surface->configure = panel_configure;
 	surface->configure_private = shell;
 	surface->output = wl_resource_get_user_data(output_resource);
+	view->output = surface->output;
 	desktop_shell_send_configure(resource, 0,
 				     surface_resource,
 				     surface->output->width,
@@ -2628,18 +2702,23 @@ static void
 lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy, int32_t width, int32_t height)
 {
 	struct desktop_shell *shell = surface->configure_private;
+	struct weston_view *view;
+
+	view = container_of(surface->views.next, struct weston_view, surface_link);
 
 	if (width == 0)
 		return;
 
-	surface->geometry.width = width;
-	surface->geometry.height = height;
-	center_on_output(surface, get_default_output(shell->compositor));
+	surface->width = width;
+	surface->height = height;
+	view->geometry.width = width;
+	view->geometry.height = height;
+	center_on_output(view, get_default_output(shell->compositor));
 
 	if (!weston_surface_is_mapped(surface)) {
-		wl_list_insert(&shell->lock_layer.surface_list,
-			       &surface->layer_link);
-		weston_surface_update_transform(surface);
+		wl_list_insert(&shell->lock_layer.view_list,
+			       &view->layer_link);
+		weston_view_update_transform(view);
 		shell_fade(shell, FADE_IN);
 	}
 }
@@ -2816,21 +2895,21 @@ resize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *d
 	    shsurf->type == SHELL_SURFACE_MAXIMIZED)
 		return;
 
-	weston_surface_from_global(surface,
-				   wl_fixed_to_int(seat->pointer->grab_x),
-				   wl_fixed_to_int(seat->pointer->grab_y),
-				   &x, &y);
+	weston_view_from_global(shsurf->view,
+				wl_fixed_to_int(seat->pointer->grab_x),
+				wl_fixed_to_int(seat->pointer->grab_y),
+				&x, &y);
 
-	if (x < surface->geometry.width / 3)
+	if (x < shsurf->view->geometry.width / 3)
 		edges |= WL_SHELL_SURFACE_RESIZE_LEFT;
-	else if (x < 2 * surface->geometry.width / 3)
+	else if (x < 2 * shsurf->view->geometry.width / 3)
 		edges |= 0;
 	else
 		edges |= WL_SHELL_SURFACE_RESIZE_RIGHT;
 
-	if (y < surface->geometry.height / 3)
+	if (y < shsurf->view->geometry.height / 3)
 		edges |= WL_SHELL_SURFACE_RESIZE_TOP;
-	else if (y < 2 * surface->geometry.height / 3)
+	else if (y < 2 * shsurf->view->geometry.height / 3)
 		edges |= 0;
 	else
 		edges |= WL_SHELL_SURFACE_RESIZE_BOTTOM;
@@ -2857,14 +2936,14 @@ surface_opacity_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
 	if (!shsurf)
 		return;
 
-	surface->alpha -= wl_fixed_to_double(value) * step;
+	shsurf->view->alpha -= wl_fixed_to_double(value) * step;
 
-	if (surface->alpha > 1.0)
-		surface->alpha = 1.0;
-	if (surface->alpha < step)
-		surface->alpha = step;
+	if (shsurf->view->alpha > 1.0)
+		shsurf->view->alpha = 1.0;
+	if (shsurf->view->alpha < step)
+		shsurf->view->alpha = step;
 
-	weston_surface_geometry_dirty(surface);
+	weston_view_geometry_dirty(shsurf->view);
 	weston_surface_damage(surface);
 }
 
@@ -2906,7 +2985,7 @@ do_zoom(struct weston_seat *seat, uint32_t time, uint32_t key, uint32_t axis,
 
 			output->zoom.spring_z.target = output->zoom.level;
 
-			weston_output_update_zoom(output, output->zoom.type);
+			weston_output_update_zoom(output);
 		}
 	}
 }
@@ -2941,23 +3020,20 @@ rotate_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
 		container_of(grab, struct rotate_grab, base.grab);
 	struct weston_pointer *pointer = grab->pointer;
 	struct shell_surface *shsurf = rotate->base.shsurf;
-	struct weston_surface *surface;
 	float cx, cy, dx, dy, cposx, cposy, dposx, dposy, r;
 
 	if (!shsurf)
 		return;
 
-	surface = shsurf->surface;
-
-	cx = 0.5f * surface->geometry.width;
-	cy = 0.5f * surface->geometry.height;
+	cx = 0.5f * shsurf->view->geometry.width;
+	cy = 0.5f * shsurf->view->geometry.height;
 
 	dx = wl_fixed_to_double(pointer->x) - rotate->center.x;
 	dy = wl_fixed_to_double(pointer->y) - rotate->center.y;
 	r = sqrtf(dx * dx + dy * dy);
 
 	wl_list_remove(&shsurf->rotation.transform.link);
-	weston_surface_geometry_dirty(shsurf->surface);
+	weston_view_geometry_dirty(shsurf->view);
 
 	if (r > 20.0f) {
 		struct weston_matrix *matrix =
@@ -2973,7 +3049,7 @@ rotate_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
 		weston_matrix_translate(matrix, cx, cy, 0.0f);
 
 		wl_list_insert(
-			&shsurf->surface->geometry.transformation_list,
+			&shsurf->view->geometry.transformation_list,
 			&shsurf->rotation.transform.link);
 	} else {
 		wl_list_init(&shsurf->rotation.transform.link);
@@ -2983,14 +3059,14 @@ rotate_grab_motion(struct weston_pointer_grab *grab, uint32_t time)
 
 	/* We need to adjust the position of the surface
 	 * in case it was resized in a rotated state before */
-	cposx = surface->geometry.x + cx;
-	cposy = surface->geometry.y + cy;
+	cposx = shsurf->view->geometry.x + cx;
+	cposy = shsurf->view->geometry.y + cy;
 	dposx = rotate->center.x - cposx;
 	dposy = rotate->center.y - cposy;
 	if (dposx != 0.0f || dposy != 0.0f) {
-		weston_surface_set_position(surface,
-					    surface->geometry.x + dposx,
-					    surface->geometry.y + dposy);
+		weston_view_set_position(shsurf->view,
+					 shsurf->view->geometry.x + dposx,
+					 shsurf->view->geometry.y + dposy);
 	}
 
 	/* Repaint implies weston_surface_update_transform(), which
@@ -3036,10 +3112,10 @@ surface_rotate(struct shell_surface *surface, struct weston_seat *seat)
 	if (!rotate)
 		return;
 
-	weston_surface_to_global_float(surface->surface,
-				       surface->surface->geometry.width * 0.5f,
-				       surface->surface->geometry.height * 0.5f,
-				       &rotate->center.x, &rotate->center.y);
+	weston_view_to_global_float(surface->view,
+				    surface->view->geometry.width * 0.5f,
+				    surface->view->geometry.height * 0.5f,
+				    &rotate->center.x, &rotate->center.y);
 
 	dx = wl_fixed_to_double(seat->pointer->x) - rotate->center.x;
 	dy = wl_fixed_to_double(seat->pointer->y) - rotate->center.y;
@@ -3087,13 +3163,13 @@ static void
 lower_fullscreen_layer(struct desktop_shell *shell)
 {
 	struct workspace *ws;
-	struct weston_surface *surface, *prev;
+	struct weston_view *view, *prev;
 
 	ws = get_current_workspace(shell);
-	wl_list_for_each_reverse_safe(surface, prev,
-				      &shell->fullscreen_layer.surface_list,
+	wl_list_for_each_reverse_safe(view, prev,
+				      &shell->fullscreen_layer.view_list,
 				      layer_link)
-		weston_surface_restack(surface, &ws->layer.surface_list);
+		weston_view_restack(view, &ws->layer.view_list);
 }
 
 static void
@@ -3101,6 +3177,7 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
 	 struct weston_seat *seat)
 {
 	struct weston_surface *main_surface;
+	struct weston_view *main_view;
 	struct focus_state *state;
 	struct workspace *ws;
 
@@ -3125,7 +3202,9 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
 	default:
 		restore_all_output_modes(shell->compositor);
 		ws = get_current_workspace(shell);
-		weston_surface_restack(main_surface, &ws->layer.surface_list);
+		main_view = get_default_view(main_surface);
+		if (main_view)
+			weston_view_restack(main_view, &ws->layer.view_list);
 		break;
 	}
 }
@@ -3156,6 +3235,7 @@ activate_binding(struct weston_seat *seat,
 
 	if (!focus)
 		return;
+	focus = seat->pointer->focus->surface;
 
 	if (is_black_surface(focus, &main_surface))
 		focus = main_surface;
@@ -3241,7 +3321,7 @@ unlock(struct desktop_shell *shell)
 }
 
 static void
-shell_fade_done(struct weston_surface_animation *animation, void *data)
+shell_fade_done(struct weston_view_animation *animation, void *data)
 {
 	struct desktop_shell *shell = data;
 
@@ -3249,8 +3329,8 @@ shell_fade_done(struct weston_surface_animation *animation, void *data)
 
 	switch (shell->fade.type) {
 	case FADE_IN:
-		weston_surface_destroy(shell->fade.surface);
-		shell->fade.surface = NULL;
+		weston_surface_destroy(shell->fade.view->surface);
+		shell->fade.view = NULL;
 		break;
 	case FADE_OUT:
 		lock(shell);
@@ -3258,23 +3338,30 @@ shell_fade_done(struct weston_surface_animation *animation, void *data)
 	}
 }
 
-static struct weston_surface *
+static struct weston_view *
 shell_fade_create_surface(struct desktop_shell *shell)
 {
 	struct weston_compositor *compositor = shell->compositor;
 	struct weston_surface *surface;
+	struct weston_view *view;
 
 	surface = weston_surface_create(compositor);
 	if (!surface)
 		return NULL;
 
-	weston_surface_configure(surface, 0, 0, 8192, 8192);
+	view = weston_view_create(surface);
+	if (!view) {
+		weston_surface_destroy(surface);
+		return NULL;
+	}
+
+	weston_view_configure(view, 0, 0, 8192, 8192);
 	weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
-	wl_list_insert(&compositor->fade_layer.surface_list,
-		       &surface->layer_link);
+	wl_list_insert(&compositor->fade_layer.view_list,
+		       &view->layer_link);
 	pixman_region32_init(&surface->input);
 
-	return surface;
+	return view;
 }
 
 static void
@@ -3296,20 +3383,20 @@ shell_fade(struct desktop_shell *shell, enum fade_type type)
 
 	shell->fade.type = type;
 
-	if (shell->fade.surface == NULL) {
-		shell->fade.surface = shell_fade_create_surface(shell);
-		if (!shell->fade.surface)
+	if (shell->fade.view == NULL) {
+		shell->fade.view = shell_fade_create_surface(shell);
+		if (!shell->fade.view)
 			return;
 
-		shell->fade.surface->alpha = 1.0 - tint;
-		weston_surface_update_transform(shell->fade.surface);
+		shell->fade.view->alpha = 1.0 - tint;
+		weston_view_update_transform(shell->fade.view);
 	}
 
 	if (shell->fade.animation)
 		weston_fade_update(shell->fade.animation, tint);
 	else
 		shell->fade.animation =
-			weston_fade_run(shell->fade.surface,
+			weston_fade_run(shell->fade.view,
 					1.0 - tint, tint, 300.0,
 					shell_fade_done, shell);
 }
@@ -3322,8 +3409,8 @@ do_shell_fade_startup(void *data)
 	if (shell->startup_animation_type == ANIMATION_FADE)
 		shell_fade(shell, FADE_IN);
 	else if (shell->startup_animation_type == ANIMATION_NONE) {
-		weston_surface_destroy(shell->fade.surface);
-		shell->fade.surface = NULL;
+		weston_surface_destroy(shell->fade.view->surface);
+		shell->fade.view = NULL;
 	}
 }
 
@@ -3361,18 +3448,18 @@ shell_fade_init(struct desktop_shell *shell)
 
 	struct wl_event_loop *loop;
 
-	if (shell->fade.surface != NULL) {
+	if (shell->fade.view != NULL) {
 		weston_log("%s: warning: fade surface already exists\n",
 			   __func__);
 		return;
 	}
 
-	shell->fade.surface = shell_fade_create_surface(shell);
-	if (!shell->fade.surface)
+	shell->fade.view = shell_fade_create_surface(shell);
+	if (!shell->fade.view)
 		return;
 
-	weston_surface_update_transform(shell->fade.surface);
-	weston_surface_damage(shell->fade.surface);
+	weston_view_update_transform(shell->fade.view);
+	weston_surface_damage(shell->fade.view->surface);
 
 	loop = wl_display_get_event_loop(shell->compositor->wl_display);
 	shell->fade.startup_timer =
@@ -3405,8 +3492,7 @@ show_input_panels(struct wl_listener *listener, void *data)
 	struct desktop_shell *shell =
 		container_of(listener, struct desktop_shell,
 			     show_input_panel_listener);
-	struct input_panel_surface *surface, *next;
-	struct weston_surface *ws;
+	struct input_panel_surface *ipsurf, *next;
 
 	shell->text_input.surface = (struct weston_surface*)data;
 
@@ -3419,17 +3505,17 @@ show_input_panels(struct wl_listener *listener, void *data)
 		wl_list_insert(&shell->panel_layer.link,
 			       &shell->input_panel_layer.link);
 
-	wl_list_for_each_safe(surface, next,
+	wl_list_for_each_safe(ipsurf, next,
 			      &shell->input_panel.surfaces, link) {
-		ws = surface->surface;
-		if (!ws->buffer_ref.buffer)
+		if (!ipsurf->surface->buffer_ref.buffer)
 			continue;
-		wl_list_insert(&shell->input_panel_layer.surface_list,
-			       &ws->layer_link);
-		weston_surface_geometry_dirty(ws);
-		weston_surface_update_transform(ws);
-		weston_surface_damage(ws);
-		weston_slide_run(ws, ws->geometry.height, 0, NULL, NULL);
+		wl_list_insert(&shell->input_panel_layer.view_list,
+			       &ipsurf->view->layer_link);
+		weston_view_geometry_dirty(ipsurf->view);
+		weston_view_update_transform(ipsurf->view);
+		weston_surface_damage(ipsurf->surface);
+		weston_slide_run(ipsurf->view, ipsurf->view->geometry.height,
+				 0, NULL, NULL);
 	}
 }
 
@@ -3439,7 +3525,7 @@ hide_input_panels(struct wl_listener *listener, void *data)
 	struct desktop_shell *shell =
 		container_of(listener, struct desktop_shell,
 			     hide_input_panel_listener);
-	struct weston_surface *surface, *next;
+	struct weston_view *view, *next;
 
 	if (!shell->showing_input_panels)
 		return;
@@ -3449,9 +3535,9 @@ hide_input_panels(struct wl_listener *listener, void *data)
 	if (!shell->locked)
 		wl_list_remove(&shell->input_panel_layer.link);
 
-	wl_list_for_each_safe(surface, next,
-			      &shell->input_panel_layer.surface_list, layer_link)
-		weston_surface_unmap(surface);
+	wl_list_for_each_safe(view, next,
+			      &shell->input_panel_layer.view_list, layer_link)
+		weston_view_unmap(view);
 }
 
 static void
@@ -3465,22 +3551,22 @@ update_input_panels(struct wl_listener *listener, void *data)
 }
 
 static void
-center_on_output(struct weston_surface *surface, struct weston_output *output)
+center_on_output(struct weston_view *view, struct weston_output *output)
 {
 	int32_t surf_x, surf_y, width, height;
 	float x, y;
 
-	surface_subsurfaces_boundingbox(surface, &surf_x, &surf_y, &width, &height);
+	surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y, &width, &height);
 
 	x = output->x + (output->width - width) / 2 - surf_x / 2;
 	y = output->y + (output->height - height) / 2 - surf_y / 2;
 
-	weston_surface_configure(surface, x, y, width, height);
+	weston_view_configure(view, x, y, width, height);
 }
 
 static void
-weston_surface_set_initial_position (struct weston_surface *surface,
-				     struct desktop_shell *shell)
+weston_view_set_initial_position(struct weston_view *view,
+				 struct desktop_shell *shell)
 {
 	struct weston_compositor *compositor = shell->compositor;
 	int ix = 0, iy = 0;
@@ -3510,8 +3596,8 @@ weston_surface_set_initial_position (struct weston_surface *surface,
 	}
 
 	if (!target_output) {
-		weston_surface_set_position(surface, 10 + random() % 400,
-					   10 + random() % 400);
+		weston_view_set_position(view, 10 + random() % 400,
+					 10 + random() % 400);
 		return;
 	}
 
@@ -3520,9 +3606,9 @@ weston_surface_set_initial_position (struct weston_surface *surface,
 	 * output.
 	 */
 	panel_height = get_output_panel_height(shell, target_output);
-	range_x = target_output->width - surface->geometry.width;
+	range_x = target_output->width - view->geometry.width;
 	range_y = (target_output->height - panel_height) -
-		  surface->geometry.height;
+		  view->geometry.height;
 
 	if (range_x > 0)
 		dx = random() % range_x;
@@ -3537,61 +3623,65 @@ weston_surface_set_initial_position (struct weston_surface *surface,
 	x = target_output->x + dx;
 	y = target_output->y + dy;
 
-	weston_surface_set_position (surface, x, y);
+	weston_view_set_position(view, x, y);
 }
 
 static void
-map(struct desktop_shell *shell, struct weston_surface *surface,
+map(struct desktop_shell *shell, struct shell_surface *shsurf,
     int32_t width, int32_t height, int32_t sx, int32_t sy)
 {
 	struct weston_compositor *compositor = shell->compositor;
-	struct shell_surface *shsurf = get_shell_surface(surface);
-	enum shell_surface_type surface_type = shsurf->type;
-	struct weston_surface *parent;
+	struct weston_view *parent;
 	struct weston_seat *seat;
 	struct workspace *ws;
 	int panel_height = 0;
 	int32_t surf_x, surf_y;
 
-	surface->geometry.width = width;
-	surface->geometry.height = height;
-	weston_surface_geometry_dirty(surface);
+	shsurf->view->geometry.width = width;
+	shsurf->view->geometry.height = height;
+	weston_view_geometry_dirty(shsurf->view);
 
 	/* initial positioning, see also configure() */
-	switch (surface_type) {
+	switch (shsurf->type) {
 	case SHELL_SURFACE_TOPLEVEL:
-		weston_surface_set_initial_position(surface, shell);
+		weston_view_set_initial_position(shsurf->view, shell);
 		break;
 	case SHELL_SURFACE_FULLSCREEN:
-		center_on_output(surface, shsurf->fullscreen_output);
+		center_on_output(shsurf->view, shsurf->fullscreen_output);
 		shell_map_fullscreen(shsurf);
 		break;
 	case SHELL_SURFACE_MAXIMIZED:
 		/* use surface configure to set the geometry */
-		panel_height = get_output_panel_height(shell,surface->output);
-		surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
-		                                                 NULL, NULL);
-		weston_surface_set_position(surface, shsurf->output->x - surf_x,
-		                            shsurf->output->y + panel_height - surf_y);
+		panel_height = get_output_panel_height(shell, shsurf->output);
+		surface_subsurfaces_boundingbox(shsurf->surface,
+						&surf_x, &surf_y, NULL, NULL);
+		weston_view_set_position(shsurf->view,
+					 shsurf->output->x - surf_x,
+		                         shsurf->output->y + panel_height - surf_y);
 		break;
 	case SHELL_SURFACE_POPUP:
 		shell_map_popup(shsurf);
 		break;
 	case SHELL_SURFACE_NONE:
-		weston_surface_set_position(surface,
-					    surface->geometry.x + sx,
-					    surface->geometry.y + sy);
+		weston_view_set_position(shsurf->view,
+					 shsurf->view->geometry.x + sx,
+					 shsurf->view->geometry.y + sy);
 		break;
 	default:
 		;
 	}
 
 	/* surface stacking order, see also activate() */
-	switch (surface_type) {
+	switch (shsurf->type) {
 	case SHELL_SURFACE_POPUP:
 	case SHELL_SURFACE_TRANSIENT:
-		parent = shsurf->parent;
-		wl_list_insert(parent->layer_link.prev, &surface->layer_link);
+		/* TODO: Handle a parent with multiple views */
+		parent = get_default_view(shsurf->parent);
+		if (parent) {
+			wl_list_remove(&shsurf->view->layer_link);
+			wl_list_insert(parent->layer_link.prev,
+				       &shsurf->view->layer_link);
+		}
 		break;
 	case SHELL_SURFACE_FULLSCREEN:
 	case SHELL_SURFACE_NONE:
@@ -3599,17 +3689,20 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
 	case SHELL_SURFACE_XWAYLAND:
 	default:
 		ws = get_current_workspace(shell);
-		wl_list_insert(&ws->layer.surface_list, &surface->layer_link);
+		wl_list_remove(&shsurf->view->layer_link);
+		wl_list_insert(&ws->layer.view_list, &shsurf->view->layer_link);
 		break;
 	}
 
-	if (surface_type != SHELL_SURFACE_NONE) {
-		weston_surface_update_transform(surface);
-		if (surface_type == SHELL_SURFACE_MAXIMIZED)
-			surface->output = shsurf->output;
+	if (shsurf->type != SHELL_SURFACE_NONE) {
+		weston_view_update_transform(shsurf->view);
+		if (shsurf->type == SHELL_SURFACE_MAXIMIZED) {
+			shsurf->surface->output = shsurf->output;
+			shsurf->view->output = shsurf->output;
+		}
 	}
 
-	switch (surface_type) {
+	switch (shsurf->type) {
 	/* XXX: xwayland's using the same fields for transient type */
 	case SHELL_SURFACE_XWAYLAND:
 	case SHELL_SURFACE_TRANSIENT:
@@ -3621,21 +3714,21 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
 	case SHELL_SURFACE_MAXIMIZED:
 		if (!shell->locked) {
 			wl_list_for_each(seat, &compositor->seat_list, link)
-				activate(shell, surface, seat);
+				activate(shell, shsurf->surface, seat);
 		}
 		break;
 	default:
 		break;
 	}
 
-	if (surface_type == SHELL_SURFACE_TOPLEVEL)
+	if (shsurf->type == SHELL_SURFACE_TOPLEVEL)
 	{
 		switch (shell->win_animation_type) {
 		case ANIMATION_FADE:
-			weston_fade_run(surface, 0.0, 1.0, 300.0, NULL, NULL);
+			weston_fade_run(shsurf->view, 0.0, 1.0, 300.0, NULL, NULL);
 			break;
 		case ANIMATION_ZOOM:
-			weston_zoom_run(surface, 0.5, 1.0, NULL, NULL);
+			weston_zoom_run(shsurf->view, 0.5, 1.0, NULL, NULL);
 			break;
 		default:
 			break;
@@ -3649,13 +3742,19 @@ configure(struct desktop_shell *shell, struct weston_surface *surface,
 {
 	enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
 	struct shell_surface *shsurf;
+	struct weston_view *view;
 	int32_t surf_x, surf_y;
 
 	shsurf = get_shell_surface(surface);
 	if (shsurf)
 		surface_type = shsurf->type;
 
-	weston_surface_configure(surface, x, y, width, height);
+	/* TODO:
+	 * This should probably be changed to be more shell_surface
+	 * dependent
+	 */
+	wl_list_for_each(view, &surface->views, surface_link)
+		weston_view_configure(view, x, y, width, height);
 
 	switch (surface_type) {
 	case SHELL_SURFACE_FULLSCREEN:
@@ -3666,9 +3765,9 @@ configure(struct desktop_shell *shell, struct weston_surface *surface,
 		/* setting x, y and using configure to change that geometry */
 		surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
 		                                                 NULL, NULL);
-		surface->geometry.x = surface->output->x - surf_x;
-		surface->geometry.y = surface->output->y +
-		get_output_panel_height(shell,surface->output) - surf_y;
+		shsurf->view->geometry.x = shsurf->output->x - surf_x;
+		shsurf->view->geometry.y = shsurf->output->y +
+			get_output_panel_height(shell,shsurf->output) - surf_y;
 		break;
 	case SHELL_SURFACE_TOPLEVEL:
 		break;
@@ -3678,7 +3777,8 @@ configure(struct desktop_shell *shell, struct weston_surface *surface,
 
 	/* XXX: would a fullscreen surface need the same handling? */
 	if (surface->output) {
-		weston_surface_update_transform(surface);
+		wl_list_for_each(view, &surface->views, surface_link)
+			weston_view_update_transform(view);
 
 		if (surface_type == SHELL_SURFACE_MAXIMIZED)
 			surface->output = shsurf->output;
@@ -3708,18 +3808,18 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy, int32
 	}
 
 	if (!weston_surface_is_mapped(es)) {
-		map(shell, es, width, height, sx, sy);
+		map(shell, shsurf, width, height, sx, sy);
 	} else if (type_changed || sx != 0 || sy != 0 ||
-		   es->geometry.width != width ||
-		   es->geometry.height != height) {
+		   shsurf->view->geometry.width != width ||
+		   shsurf->view->geometry.height != height) {
 		float from_x, from_y;
 		float to_x, to_y;
 
-		weston_surface_to_global_float(es, 0, 0, &from_x, &from_y);
-		weston_surface_to_global_float(es, sx, sy, &to_x, &to_y);
+		weston_view_to_global_float(shsurf->view, 0, 0, &from_x, &from_y);
+		weston_view_to_global_float(shsurf->view, sx, sy, &to_x, &to_y);
 		configure(shell, es,
-			  es->geometry.x + to_x - from_x,
-			  es->geometry.y + to_y - from_y,
+			  shsurf->view->geometry.x + to_x - from_x,
+			  shsurf->view->geometry.y + to_y - from_y,
 			  width, height);
 	}
 }
@@ -3824,6 +3924,7 @@ static void
 screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy, int32_t width, int32_t height)
 {
 	struct desktop_shell *shell = surface->configure_private;
+	struct weston_view *view;
 
 	if (width == 0)
 		return;
@@ -3832,12 +3933,13 @@ screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy, in
 	if (!shell->locked)
 		return;
 
-	center_on_output(surface, surface->output);
+	view = container_of(surface->views.next, struct weston_view, surface_link);
+	center_on_output(view, surface->output);
 
-	if (wl_list_empty(&surface->layer_link)) {
-		wl_list_insert(shell->lock_layer.surface_list.prev,
-			       &surface->layer_link);
-		weston_surface_update_transform(surface);
+	if (wl_list_empty(&view->layer_link)) {
+		wl_list_insert(shell->lock_layer.view_list.prev,
+			       &view->layer_link);
+		weston_view_update_transform(view);
 		wl_event_source_timer_update(shell->screensaver.timer,
 					     shell->screensaver.duration);
 		shell_fade(shell, FADE_IN);
@@ -3854,6 +3956,12 @@ screensaver_set_surface(struct wl_client *client,
 	struct weston_surface *surface =
 		wl_resource_get_user_data(surface_resource);
 	struct weston_output *output = wl_resource_get_user_data(output_resource);
+	struct weston_view *view, *next;
+
+	/* Make sure we only have one view */
+	wl_list_for_each_safe(view, next, &surface->views, surface_link)
+		weston_view_destroy(view);
+	weston_view_create(surface);
 
 	surface->configure = screensaver_configure;
 	surface->configure_private = shell;
@@ -3915,23 +4023,21 @@ input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy, in
 	fprintf(stderr, "%s panel: %d, output: %p\n", __FUNCTION__, ip_surface->panel, ip_surface->output);
 
 	if (ip_surface->panel) {
-		x = shell->text_input.surface->geometry.x + shell->text_input.cursor_rectangle.x2;
-		y = shell->text_input.surface->geometry.y + shell->text_input.cursor_rectangle.y2;
+		x = get_default_view(shell->text_input.surface)->geometry.x + shell->text_input.cursor_rectangle.x2;
+		y = get_default_view(shell->text_input.surface)->geometry.y + shell->text_input.cursor_rectangle.y2;
 	} else {
 		x = ip_surface->output->x + (ip_surface->output->width - width) / 2;
 		y = ip_surface->output->y + ip_surface->output->height - height;
 	}
 
-	weston_surface_configure(surface,
-				 x, y,
-				 width, height);
+	weston_view_configure(ip_surface->view, x, y, width, height);
 
 	if (show_surface) {
-		wl_list_insert(&shell->input_panel_layer.surface_list,
-			       &surface->layer_link);
-		weston_surface_update_transform(surface);
+		wl_list_insert(&shell->input_panel_layer.view_list,
+			       &ip_surface->view->layer_link);
+		weston_view_update_transform(ip_surface->view);
 		weston_surface_damage(surface);
-		weston_slide_run(surface, surface->geometry.height, 0, NULL, NULL);
+		weston_slide_run(ip_surface->view, ip_surface->view->geometry.height, 0, NULL, NULL);
 	}
 }
 
@@ -3944,6 +4050,7 @@ destroy_input_panel_surface(struct input_panel_surface *input_panel_surface)
 	wl_list_remove(&input_panel_surface->link);
 
 	input_panel_surface->surface->configure = NULL;
+	weston_view_destroy(input_panel_surface->view);
 
 	free(input_panel_surface);
 }
@@ -3988,6 +4095,7 @@ create_input_panel_surface(struct desktop_shell *shell,
 	input_panel_surface->shell = shell;
 
 	input_panel_surface->surface = surface;
+	input_panel_surface->view = weston_view_create(surface);
 
 	wl_signal_init(&input_panel_surface->destroy_signal);
 	input_panel_surface->surface_destroy_listener.notify = input_panel_handle_surface_destroy;
@@ -4124,33 +4232,33 @@ struct switcher {
 static void
 switcher_next(struct switcher *switcher)
 {
-	struct weston_surface *surface;
+	struct weston_view *view;
 	struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
 	struct shell_surface *shsurf;
 	struct workspace *ws = get_current_workspace(switcher->shell);
 
-	wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
-		switch (get_shell_surface_type(surface)) {
+	wl_list_for_each(view, &ws->layer.view_list, layer_link) {
+		switch (get_shell_surface_type(view->surface)) {
 		case SHELL_SURFACE_TOPLEVEL:
 		case SHELL_SURFACE_FULLSCREEN:
 		case SHELL_SURFACE_MAXIMIZED:
 			if (first == NULL)
-				first = surface;
+				first = view->surface;
 			if (prev == switcher->current)
-				next = surface;
-			prev = surface;
-			surface->alpha = 0.25;
-			weston_surface_geometry_dirty(surface);
-			weston_surface_damage(surface);
+				next = view->surface;
+			prev = view->surface;
+			view->alpha = 0.25;
+			weston_view_geometry_dirty(view);
+			weston_surface_damage(view->surface);
 			break;
 		default:
 			break;
 		}
 
-		if (is_black_surface(surface, NULL)) {
-			surface->alpha = 0.25;
-			weston_surface_geometry_dirty(surface);
-			weston_surface_damage(surface);
+		if (is_black_surface(view->surface, NULL)) {
+			view->alpha = 0.25;
+			weston_view_geometry_dirty(view);
+			weston_surface_damage(view->surface);
 		}
 	}
 
@@ -4164,11 +4272,12 @@ switcher_next(struct switcher *switcher)
 	wl_signal_add(&next->destroy_signal, &switcher->listener);
 
 	switcher->current = next;
-	next->alpha = 1.0;
+	wl_list_for_each(view, &next->views, surface_link)
+		view->alpha = 1.0;
 
 	shsurf = get_shell_surface(switcher->current);
 	if (shsurf && shsurf->type ==SHELL_SURFACE_FULLSCREEN)
-		shsurf->fullscreen.black_surface->alpha = 1.0;
+		shsurf->fullscreen.black_view->alpha = 1.0;
 }
 
 static void
@@ -4183,13 +4292,13 @@ switcher_handle_surface_destroy(struct wl_listener *listener, void *data)
 static void
 switcher_destroy(struct switcher *switcher)
 {
-	struct weston_surface *surface;
+	struct weston_view *view;
 	struct weston_keyboard *keyboard = switcher->grab.keyboard;
 	struct workspace *ws = get_current_workspace(switcher->shell);
 
-	wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
-		surface->alpha = 1.0;
-		weston_surface_damage(surface);
+	wl_list_for_each(view, &ws->layer.view_list, layer_link) {
+		view->alpha = 1.0;
+		weston_surface_damage(view->surface);
 	}
 
 	if (switcher->current)
@@ -4638,6 +4747,7 @@ module_init(struct weston_compositor *ec,
 	ec->ping_handler = ping_handler;
 	ec->shell_interface.shell = shell;
 	ec->shell_interface.create_shell_surface = create_shell_surface;
+	ec->shell_interface.get_primary_view = get_primary_view;
 	ec->shell_interface.set_toplevel = set_toplevel;
 	ec->shell_interface.set_transient = set_transient;
 	ec->shell_interface.set_fullscreen = set_fullscreen;
diff --git a/src/spring-tool.c b/src/spring-tool.c
index 935acc4b2a726e69a18d70e33e7a9639c54ec217..41cc52ce23d2fc38572b54259abe35d7d22b36a9 100644
--- a/src/spring-tool.c
+++ b/src/spring-tool.c
@@ -25,7 +25,7 @@
 #include "compositor.h"
 
 WL_EXPORT void
-weston_surface_geometry_dirty(struct weston_surface *surface)
+weston_view_geometry_dirty(struct weston_view *view)
 {
 }
 
@@ -36,7 +36,7 @@ weston_log(const char *fmt, ...)
 }
 
 WL_EXPORT void
-weston_compositor_schedule_repaint(struct weston_compositor *compositor)
+weston_view_schedule_repaint(struct weston_view *view)
 {
 }
 
diff --git a/src/tablet-shell.c b/src/tablet-shell.c
index b055ab23b99f03ab30a375778d3326522725c608..5e9267884172902f6c9c57c5cd7eff0861cdc85e 100644
--- a/src/tablet-shell.c
+++ b/src/tablet-shell.c
@@ -28,6 +28,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <linux/input.h>
+#include <assert.h>
 
 #include "compositor.h"
 #include "tablet-shell-server-protocol.h"
@@ -124,27 +125,43 @@ tablet_shell_set_state(struct tablet_shell *shell, int state)
 	shell->state = state;
 }
 
+static struct weston_view *
+get_surface_view(struct weston_surface *surface, int create)
+{
+	if (!surface)
+		return NULL;
+
+	if (wl_list_empty(&surface->views)) {
+		if (create)
+			return weston_view_create(surface);
+		else
+			return NULL;
+	}
+
+	return container_of(surface->views.next, struct weston_view, surface_link);
+}
+
 static void
 tablet_shell_surface_configure(struct weston_surface *surface,
 			       int32_t sx, int32_t sy, int32_t width, int32_t height)
 {
 	struct tablet_shell *shell = get_shell(surface->compositor);
+	struct weston_view *view = get_surface_view(surface, 0);
+	assert(view);
 
 	if (weston_surface_is_mapped(surface) || width == 0)
 		return;
 
-	weston_surface_configure(surface, 0, 0, width, height);
-
 	if (surface == shell->lockscreen_surface) {
-			wl_list_insert(&shell->lockscreen_layer.surface_list,
-					&surface->layer_link);
+		wl_list_insert(&shell->lockscreen_layer.view_list,
+				&view->layer_link);
 	} else if (surface == shell->switcher_surface) {
 		/* */
 	} else if (surface == shell->home_surface) {
 		if (shell->state == STATE_STARTING) {
 	                /* homescreen always visible, at the bottom */
-			wl_list_insert(&shell->homescreen_layer.surface_list,
-					&surface->layer_link);
+			wl_list_insert(&shell->homescreen_layer.view_list,
+					&view->layer_link);
 
 			tablet_shell_set_state(shell, STATE_LOCKED);
 			shell->previous_state = STATE_HOME;
@@ -155,12 +172,15 @@ tablet_shell_surface_configure(struct weston_surface *surface,
 		   shell->current_client->client == wl_resource_get_client(surface->resource)) {
 		tablet_shell_set_state(shell, STATE_TASK);
 		shell->current_client->surface = surface;
-		weston_zoom_run(surface, 0.3, 1.0, NULL, NULL);
-		wl_list_insert(&shell->application_layer.surface_list,
-			       &surface->layer_link);
+		weston_zoom_run(view, 0.3, 1.0, NULL, NULL);
+		wl_list_insert(&shell->application_layer.view_list,
+			       &view->layer_link);
 	}
 
-	weston_surface_update_transform(surface);
+	if (view) {
+		weston_view_configure(view, 0, 0, width, height);
+		weston_view_update_transform(view);
+	}
 }
 
 static void
@@ -181,10 +201,12 @@ tablet_shell_set_lockscreen(struct wl_client *client,
 {
 	struct tablet_shell *shell = wl_resource_get_user_data(resource);
 	struct weston_surface *es = wl_resource_get_user_data(surface_resource);
+	struct weston_view *view;
 
-	weston_surface_set_position(es, 0, 0);
+	view = weston_view_create(es);
+	weston_view_set_position(view, 0, 0);
 	shell->lockscreen_surface = es;
-	shell->lockscreen_surface->configure = tablet_shell_surface_configure;
+	es->configure = tablet_shell_surface_configure;
 	shell->lockscreen_listener.notify = handle_lockscreen_surface_destroy;
 	wl_signal_add(&es->destroy_signal, &shell->lockscreen_listener);
 }
@@ -208,14 +230,16 @@ tablet_shell_set_switcher(struct wl_client *client,
 {
 	struct tablet_shell *shell = wl_resource_get_user_data(resource);
 	struct weston_surface *es = wl_resource_get_user_data(surface_resource);
+	struct weston_view *view;
 
 	/* FIXME: Switcher should be centered and the compositor
 	 * should do the tinting of the background.  With the cache
 	 * layer idea, we should be able to hit the framerate on the
 	 * fade/zoom in. */
-	shell->switcher_surface = es;
-	weston_surface_set_position(shell->switcher_surface, 0, 0);
+	view = weston_view_create(es);
+	weston_view_set_position(view, 0, 0);
 
+	shell->switcher_surface = es;
 	shell->switcher_listener.notify = handle_switcher_surface_destroy;
 	wl_signal_add(&es->destroy_signal, &shell->switcher_listener);
 }
@@ -226,15 +250,18 @@ tablet_shell_set_homescreen(struct wl_client *client,
 			    struct wl_resource *surface_resource)
 {
 	struct tablet_shell *shell = wl_resource_get_user_data(resource);
+	struct weston_surface *es = wl_resource_get_user_data(surface_resource);
+	struct weston_view *view;
 
-	shell->home_surface = wl_resource_get_user_data(surface_resource);
-	shell->home_surface->configure = tablet_shell_surface_configure;
+	view = weston_view_create(es);
+	weston_view_set_position(view, 0, 0);
 
-	weston_surface_set_position(shell->home_surface, 0, 0);
+	shell->home_surface = es;
+	es->configure = tablet_shell_surface_configure;
 }
 
 static void
-minimize_zoom_done(struct weston_surface_animation *zoom, void *data)
+minimize_zoom_done(struct weston_view_animation *zoom, void *data)
 {
 	struct tablet_shell *shell = data;
 	struct weston_compositor *compositor = shell->compositor;
@@ -246,11 +273,12 @@ minimize_zoom_done(struct weston_surface_animation *zoom, void *data)
 
 static void
 tablet_shell_switch_to(struct tablet_shell *shell,
-			     struct weston_surface *surface)
+		       struct weston_surface *surface)
 {
 	struct weston_compositor *compositor = shell->compositor;
 	struct weston_seat *seat;
 	struct weston_surface *current;
+	struct weston_view *view = get_surface_view(surface, 1);
 
 	if (shell->state == STATE_SWITCHER) {
 		wl_list_remove(&shell->switcher_listener.link);
@@ -262,15 +290,15 @@ tablet_shell_switch_to(struct tablet_shell *shell,
 
 		if (shell->current_client && shell->current_client->surface) {
 			current = shell->current_client->surface;
-			weston_zoom_run(current, 1.0, 0.3,
-				      minimize_zoom_done, shell);
+			weston_zoom_run(get_surface_view(current, 0), 1.0, 0.3,
+				        minimize_zoom_done, shell);
 		}
 	} else {
-		fprintf(stderr, "switch to %p\n", surface);
+		fprintf(stderr, "switch to %p\n", view);
 		wl_list_for_each(seat, &compositor->seat_list, link)
-			weston_surface_activate(surface, seat);
+			weston_surface_activate(view->surface, seat);
 		tablet_shell_set_state(shell, STATE_TASK);
-		weston_zoom_run(surface, 0.3, 1.0, NULL, NULL);
+		weston_zoom_run(view, 0.3, 1.0, NULL, NULL);
 	}
 }
 
diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c
index a889278627d52d77d92b9f42c535b0e5b84cc419..9c500e13d578156805d8261253cb8e2dd059b106 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -124,6 +124,7 @@ struct weston_wm_window {
 	cairo_surface_t *cairo_surface;
 	struct weston_surface *surface;
 	struct shell_surface *shsurf;
+	struct weston_view *view;
 	struct wl_listener surface_destroy_listener;
 	struct wl_event_source *repaint_source;
 	struct wl_event_source *configure_source;
@@ -716,13 +717,13 @@ weston_wm_window_transform(struct wl_listener *listener, void *data)
 	if (!window || !wm)
 		return;
 
-	if (!weston_surface_is_mapped(surface))
+	if (!window->view || !weston_view_is_mapped(window->view))
 		return;
 
-	if (window->x != surface->geometry.x ||
-	    window->y != surface->geometry.y) {
-		values[0] = surface->geometry.x;
-		values[1] = surface->geometry.y;
+	if (window->x != window->view->geometry.x ||
+	    window->y != window->view->geometry.y) {
+		values[0] = window->view->geometry.x;
+		values[1] = window->view->geometry.y;
 		mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
 
 		xcb_configure_window(wm->conn, window->frame_id, mask, values);
@@ -958,7 +959,8 @@ weston_wm_window_draw_decoration(void *data)
 						  window->width + 2,
 						  window->height + 2);
 		}
-		weston_surface_geometry_dirty(window->surface);
+		if (window->view)
+			weston_view_geometry_dirty(window->view);
 	}
 
 	if (window->surface && !window->fullscreen) {
@@ -986,7 +988,8 @@ weston_wm_window_schedule_repaint(struct weston_wm_window *window)
 				pixman_region32_init_rect(&window->surface->pending.opaque, 0, 0,
 							  width, height);
 			}
-			weston_surface_geometry_dirty(window->surface);
+			if (window->view)
+				weston_view_geometry_dirty(window->view);
 		}
 		return;
 	}
@@ -1177,8 +1180,8 @@ weston_wm_window_handle_moveresize(struct weston_wm_window *window,
 	struct weston_shell_interface *shell_interface =
 		&wm->server->compositor->shell_interface;
 
-	if (seat->pointer->button_count != 1 ||
-	    seat->pointer->focus != window->surface)
+	if (seat->pointer->button_count != 1 || !window->view
+	    || seat->pointer->focus != window->view)
 		return;
 
 	detail = client_message->data.data32[2];
@@ -2169,10 +2172,15 @@ xserver_map_shell_surface(struct weston_wm *wm,
 	if (!shell_interface->create_shell_surface)
 		return;
 
+	if (!shell_interface->get_primary_view)
+		return;
+
 	window->shsurf = 
 		shell_interface->create_shell_surface(shell_interface->shell,
 						      window->surface,
 						      &shell_client);
+	window->view = shell_interface->get_primary_view(shell_interface->shell,
+							 window->shsurf);
 
 	if (window->name)
 		shell_interface->set_title(window->shsurf, window->name);
diff --git a/src/zoom.c b/src/zoom.c
index 220b2b6ed157d997f1dae6aa9a6edc67c74f0049..962ed6d6ae8604a11965d204265db74c2d224e33 100644
--- a/src/zoom.c
+++ b/src/zoom.c
@@ -27,97 +27,6 @@
 #include "compositor.h"
 #include "text-cursor-position-server-protocol.h"
 
-struct text_cursor_position {
-	struct weston_compositor *ec;
-	struct wl_global *global;
-	struct wl_listener destroy_listener;
-};
-
-static void
-text_cursor_position_notify(struct wl_client *client,
-			    struct wl_resource *resource,
-			    struct wl_resource *surface_resource,
-			    wl_fixed_t x, wl_fixed_t y)
-{
-	struct weston_surface *surface =
-		wl_resource_get_user_data(surface_resource);
-
-	weston_text_cursor_position_notify(surface, x, y);
-}
-
-struct text_cursor_position_interface text_cursor_position_implementation = {
-	text_cursor_position_notify
-};
-
-static void
-bind_text_cursor_position(struct wl_client *client,
-	     void *data, uint32_t version, uint32_t id)
-{
-	struct wl_resource *resource;
-
-	resource = wl_resource_create(client,
-				      &text_cursor_position_interface, 1, id);
-	if (resource)
-		wl_resource_set_implementation(resource,
-					       &text_cursor_position_implementation,
-					       data, NULL);
-}
-
-static void
-text_cursor_position_notifier_destroy(struct wl_listener *listener, void *data)
-{
-	struct text_cursor_position *text_cursor_position =
-		container_of(listener, struct text_cursor_position, destroy_listener);
-
-	wl_global_destroy(text_cursor_position->global);
-	free(text_cursor_position);
-}
-
-void
-text_cursor_position_notifier_create(struct weston_compositor *ec)
-{
-	struct text_cursor_position *text_cursor_position;
-
-	text_cursor_position = malloc(sizeof *text_cursor_position);
-	if (text_cursor_position == NULL)
-		return;
-
-	text_cursor_position->ec = ec;
-
-	text_cursor_position->global =
-		wl_global_create(ec->wl_display,
-				 &text_cursor_position_interface, 1,
-				 text_cursor_position,
-				 bind_text_cursor_position);
-
-	text_cursor_position->destroy_listener.notify =
-		text_cursor_position_notifier_destroy;
-	wl_signal_add(&ec->destroy_signal, &text_cursor_position->destroy_listener);
-}
-
-WL_EXPORT void
-weston_text_cursor_position_notify(struct weston_surface *surface,
-						wl_fixed_t cur_pos_x,
-						wl_fixed_t cur_pos_y)
-{
-	struct weston_output *output;
-	wl_fixed_t global_x, global_y;
-
-	weston_surface_to_global_fixed(surface, cur_pos_x, cur_pos_y,
-						&global_x, &global_y);
-
-	wl_list_for_each(output, &surface->compositor->output_list, link)
-		if (output->zoom.active &&
-		    pixman_region32_contains_point(&output->region,
-						wl_fixed_to_int(global_x),
-						wl_fixed_to_int(global_y),
-						NULL)) {
-			output->zoom.text_cursor.x = global_x;
-			output->zoom.text_cursor.y = global_y;
-			weston_output_update_zoom(output, ZOOM_FOCUS_TEXT);
-		}
-}
-
 static void
 weston_zoom_frame_z(struct weston_animation *animation,
 		struct weston_output *output, uint32_t msecs)
@@ -176,12 +85,8 @@ weston_zoom_frame_xy(struct weston_animation *animation,
 
 	if (weston_spring_done(&output->zoom.spring_xy)) {
 		output->zoom.spring_xy.current = output->zoom.spring_xy.target;
-		output->zoom.current.x =
-			output->zoom.type == ZOOM_FOCUS_POINTER ?
-				seat->pointer->x : output->zoom.text_cursor.x;
-		output->zoom.current.y =
-			output->zoom.type == ZOOM_FOCUS_POINTER ?
-				seat->pointer->y : output->zoom.text_cursor.y;
+		output->zoom.current.x = seat->pointer->x;
+		output->zoom.current.y = seat->pointer->y;
 		wl_list_remove(&animation->link);
 		wl_list_init(&animation->link);
 	}
@@ -251,7 +156,6 @@ weston_zoom_apply_output_transform(struct weston_output *output,
 static void
 weston_output_update_zoom_transform(struct weston_output *output)
 {
-	uint32_t type = output->zoom.type;
 	float global_x, global_y;
 	wl_fixed_t x = output->zoom.current.x;
 	wl_fixed_t y = output->zoom.current.y;
@@ -265,8 +169,7 @@ weston_output_update_zoom_transform(struct weston_output *output)
 	    level == 0.0f)
 		return;
 
-	if (type == ZOOM_FOCUS_POINTER &&
-			wl_list_empty(&output->zoom.animation_xy.link))
+	if (wl_list_empty(&output->zoom.animation_xy.link))
 		zoom_area_center_from_pointer(output, &x, &y);
 
 	global_x = wl_fixed_to_double(x);
@@ -297,39 +200,8 @@ weston_output_update_zoom_transform(struct weston_output *output)
 }
 
 static void
-weston_zoom_transition(struct weston_output *output, uint32_t type,
-						wl_fixed_t x, wl_fixed_t y)
+weston_zoom_transition(struct weston_output *output, wl_fixed_t x, wl_fixed_t y)
 {
-	if (output->zoom.type != type) {
-		/* Set from/to points and start animation */
-		output->zoom.spring_xy.current = 0.0;
-		output->zoom.spring_xy.previous = 0.0;
-		output->zoom.spring_xy.target = 1.0;
-
-		if (wl_list_empty(&output->zoom.animation_xy.link)) {
-			output->zoom.animation_xy.frame_counter = 0;
-			wl_list_insert(output->animation_list.prev,
-				&output->zoom.animation_xy.link);
-
-			output->zoom.from.x = (type == ZOOM_FOCUS_TEXT) ?
-						x : output->zoom.text_cursor.x;
-			output->zoom.from.y = (type == ZOOM_FOCUS_TEXT) ?
-						y : output->zoom.text_cursor.y;
-		} else {
-			output->zoom.from.x = output->zoom.current.x;
-			output->zoom.from.y = output->zoom.current.y;
-		}
-
-		output->zoom.to.x = (type == ZOOM_FOCUS_POINTER) ?
-						x : output->zoom.text_cursor.x;
-		output->zoom.to.y = (type == ZOOM_FOCUS_POINTER) ?
-						y : output->zoom.text_cursor.y;
-		output->zoom.current.x = output->zoom.from.x;
-		output->zoom.current.y = output->zoom.from.y;
-
-		output->zoom.type = type;
-	}
-
 	if (output->zoom.level != output->zoom.spring_z.current) {
 		output->zoom.spring_z.target = output->zoom.level;
 		if (wl_list_empty(&output->zoom.animation_z.link)) {
@@ -344,7 +216,7 @@ weston_zoom_transition(struct weston_output *output, uint32_t type,
 }
 
 WL_EXPORT void
-weston_output_update_zoom(struct weston_output *output, uint32_t type)
+weston_output_update_zoom(struct weston_output *output)
 {
 	struct weston_seat *seat = weston_zoom_pick_seat(output->compositor);
 	wl_fixed_t x = seat->pointer->x;
@@ -352,27 +224,15 @@ weston_output_update_zoom(struct weston_output *output, uint32_t type)
 
 	zoom_area_center_from_pointer(output, &x, &y);
 
-	if (type == ZOOM_FOCUS_POINTER) {
-		if (wl_list_empty(&output->zoom.animation_xy.link)) {
-			output->zoom.current.x = seat->pointer->x;
-			output->zoom.current.y = seat->pointer->y;
-		} else {
-			output->zoom.to.x = x;
-			output->zoom.to.y = y;
-		}
-	}
-
-	if (type == ZOOM_FOCUS_TEXT) {
-		if (wl_list_empty(&output->zoom.animation_xy.link)) {
-			output->zoom.current.x = output->zoom.text_cursor.x;
-			output->zoom.current.y = output->zoom.text_cursor.y;
-		} else {
-			output->zoom.to.x = output->zoom.text_cursor.x;
-			output->zoom.to.y = output->zoom.text_cursor.y;
-		}
+	if (wl_list_empty(&output->zoom.animation_xy.link)) {
+		output->zoom.current.x = seat->pointer->x;
+		output->zoom.current.y = seat->pointer->y;
+	} else {
+		output->zoom.to.x = x;
+		output->zoom.to.y = y;
 	}
 
-	weston_zoom_transition(output, type, x, y);
+	weston_zoom_transition(output, x, y);
 	weston_output_update_zoom_transform(output);
 }
 
@@ -385,7 +245,6 @@ weston_output_init_zoom(struct weston_output *output)
 	output->zoom.level = 0.0;
 	output->zoom.trans_x = 0.0;
 	output->zoom.trans_y = 0.0;
-	output->zoom.type = ZOOM_FOCUS_POINTER;
 	weston_spring_init(&output->zoom.spring_z, 250.0, 0.0, 0.0);
 	output->zoom.spring_z.friction = 1000;
 	output->zoom.animation_z.frame = weston_zoom_frame_z;
diff --git a/tests/surface-global-test.c b/tests/surface-global-test.c
index 04b64d6ac46e01bc51ecf0e48fe4d36ad56211a8..788e694dee511a2d1e731055890fe963def2c524 100644
--- a/tests/surface-global-test.c
+++ b/tests/surface-global-test.c
@@ -29,39 +29,42 @@ surface_to_from_global(void *data)
 {
 	struct weston_compositor *compositor = data;
 	struct weston_surface *surface;
+	struct weston_view *view;
 	float x, y;
 	wl_fixed_t fx, fy;
 	int32_t ix, iy;
 
 	surface = weston_surface_create(compositor);
 	assert(surface);
-	weston_surface_configure(surface, 5, 10, 50, 50);
-	weston_surface_update_transform(surface);
+	view = weston_view_create(surface);
+	assert(view);
+	weston_view_configure(view, 5, 10, 50, 50);
+	weston_view_update_transform(view);
 
-	weston_surface_to_global_float(surface, 33, 22, &x, &y);
+	weston_view_to_global_float(view, 33, 22, &x, &y);
 	assert(x == 38 && y == 32);
 
-	weston_surface_to_global_float(surface, -8, -2, &x, &y);
+	weston_view_to_global_float(view, -8, -2, &x, &y);
 	assert(x == -3 && y == 8);
 
-	weston_surface_to_global_fixed(surface, wl_fixed_from_int(12),
+	weston_view_to_global_fixed(view, wl_fixed_from_int(12),
 				       wl_fixed_from_int(5), &fx, &fy);
 	assert(fx == wl_fixed_from_int(17) && fy == wl_fixed_from_int(15));
 
-	weston_surface_from_global_float(surface, 38, 32, &x, &y);
+	weston_view_from_global_float(view, 38, 32, &x, &y);
 	assert(x == 33 && y == 22);
 
-	weston_surface_from_global_float(surface, 42, 5, &x, &y);
+	weston_view_from_global_float(view, 42, 5, &x, &y);
 	assert(x == 37 && y == -5);
 
-	weston_surface_from_global_fixed(surface, wl_fixed_from_int(21),
+	weston_view_from_global_fixed(view, wl_fixed_from_int(21),
 					 wl_fixed_from_int(100), &fx, &fy);
 	assert(fx == wl_fixed_from_int(16) && fy == wl_fixed_from_int(90));
 
-	weston_surface_from_global(surface, 0, 0, &ix, &iy);
+	weston_view_from_global(view, 0, 0, &ix, &iy);
 	assert(ix == -5 && iy == -10);
 
-	weston_surface_from_global(surface, 5, 10, &ix, &iy);
+	weston_view_from_global(view, 5, 10, &ix, &iy);
 	assert(ix == 0 && iy == 0);
 
 	wl_display_terminate(compositor->wl_display);
diff --git a/tests/surface-test.c b/tests/surface-test.c
index e8af2ed70546134d629aa32186cdac8b439481c8..4a8b2b29d18d4fb5e2cf237d743ad05201ad8eff 100644
--- a/tests/surface-test.c
+++ b/tests/surface-test.c
@@ -31,20 +31,23 @@ surface_transform(void *data)
 {
 	struct weston_compositor *compositor = data;
 	struct weston_surface *surface;
+	struct weston_view *view;
 	float x, y;
 
 	surface = weston_surface_create(compositor);
 	assert(surface);
-	weston_surface_configure(surface, 100, 100, 200, 200);
-	weston_surface_update_transform(surface);
-	weston_surface_to_global_float(surface, 20, 20, &x, &y);
+	view = weston_view_create(surface);
+	assert(view);
+	weston_view_configure(view, 100, 100, 200, 200);
+	weston_view_update_transform(view);
+	weston_view_to_global_float(view, 20, 20, &x, &y);
 
 	fprintf(stderr, "20,20 maps to %f, %f\n", x, y);
 	assert(x == 120 && y == 120);
 
-	weston_surface_set_position(surface, 150, 300);
-	weston_surface_update_transform(surface);
-	weston_surface_to_global_float(surface, 50, 40, &x, &y);
+	weston_view_set_position(view, 150, 300);
+	weston_view_update_transform(view);
+	weston_view_to_global_float(view, 50, 40, &x, &y);
 	assert(x == 200 && y == 340);
 
 	wl_display_terminate(compositor->wl_display);
diff --git a/tests/weston-test.c b/tests/weston-test.c
index a825d123571a371ade6e79d352cd011138311cce..5f341d86d3961a1f348b3e9fc724676bc09eff8d 100644
--- a/tests/weston-test.c
+++ b/tests/weston-test.c
@@ -36,6 +36,7 @@ struct weston_test {
 
 struct weston_test_surface {
 	struct weston_surface *surface;
+	struct weston_view *view;
 	int32_t x, y;
 	struct weston_test *test;
 };
@@ -79,15 +80,16 @@ test_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy, i
 	struct weston_test_surface *test_surface = surface->configure_private;
 	struct weston_test *test = test_surface->test;
 
-	if (wl_list_empty(&surface->layer_link))
-		wl_list_insert(&test->layer.surface_list,
-			       &surface->layer_link);
+	if (wl_list_empty(&test_surface->view->layer_link))
+		wl_list_insert(&test->layer.view_list,
+			       &test_surface->view->layer_link);
 
-	weston_surface_configure(surface, test_surface->x, test_surface->y,
-				 width, height);
+	weston_view_configure(test_surface->view,
+			      test_surface->x, test_surface->y,
+			      width, height);
 
-	if (!weston_surface_is_mapped(surface))
-		weston_surface_update_transform(surface);
+	if (!weston_view_is_mapped(test_surface->view))
+		weston_view_update_transform(test_surface->view);
 }
 
 static void
@@ -99,13 +101,23 @@ move_surface(struct wl_client *client, struct wl_resource *resource,
 		wl_resource_get_user_data(surface_resource);
 	struct weston_test_surface *test_surface;
 
-	surface->configure = test_surface_configure;
-	if (surface->configure_private == NULL)
-		surface->configure_private = malloc(sizeof *test_surface);
 	test_surface = surface->configure_private;
-	if (test_surface == NULL) {
-		wl_resource_post_no_memory(resource);
-		return;
+	if (!test_surface) {
+		test_surface = malloc(sizeof *test_surface);
+		if (!test_surface) {
+			wl_resource_post_no_memory(resource);
+			return;
+		}
+
+		test_surface->view = weston_view_create(surface);
+		if (!test_surface->view) {
+			wl_resource_post_no_memory(resource);
+			free(test_surface);
+			return;
+		}
+
+		surface->configure_private = test_surface;
+		surface->configure = test_surface_configure;
 	}
 
 	test_surface->surface = surface;