compositor: Track opaque region of a surface
diff --git a/compositor/compositor.c b/compositor/compositor.c
index a6dc025..e6dba98 100644
--- a/compositor/compositor.c
+++ b/compositor/compositor.c
@@ -255,6 +255,7 @@
 	surface->buffer = NULL;
 
 	pixman_region32_init(&surface->damage);
+	pixman_region32_init(&surface->opaque);
 
 	surface->buffer_destroy_listener.func = surface_handle_buffer_destroy;
 	wl_list_init(&surface->buffer_destroy_listener.link);
@@ -302,6 +303,31 @@
 	wlsc_compositor_schedule_repaint(surface->compositor);
 }
 
+WL_EXPORT void
+wlsc_surface_configure(struct wlsc_surface *surface,
+		       int x, int y, int width, int height)
+{
+	struct wlsc_compositor *compositor = surface->compositor;
+
+	wlsc_surface_damage_below(surface);
+
+	surface->x = x;
+	surface->y = y;
+	surface->width = width;
+	surface->height = height;
+
+	wlsc_surface_assign_output(surface);
+	wlsc_surface_damage(surface);
+
+	pixman_region32_fini(&surface->opaque);
+	if (surface->visual == &compositor->compositor.rgb_visual)
+		pixman_region32_init_rect(&surface->opaque,
+					  surface->x, surface->y,
+					  surface->width, surface->height);
+	else
+		pixman_region32_init(&surface->opaque);
+}
+
 WL_EXPORT uint32_t
 wlsc_compositor_get_time(void)
 {
@@ -751,7 +777,7 @@
 	struct wlsc_compositor *ec = output->compositor;
 	struct wlsc_surface *es;
 	struct wlsc_input_device *device;
-	pixman_region32_t clip, new_damage, total_damage, region, opaque;
+	pixman_region32_t clip, new_damage, total_damage;
 
 	output->prepare_render(output);
 
@@ -769,11 +795,7 @@
 	wl_list_for_each(es, &ec->surface_list, link) {
 		pixman_region32_intersect(&es->damage, &es->damage, &clip);
 		pixman_region32_union(&new_damage, &new_damage, &es->damage);
-		if (es->visual == &ec->compositor.rgb_visual) {
-			pixman_region32_init_rect(&region, es->x, es->y, es->width, es->height);
-			pixman_region32_subtract(&clip, &clip, &region);
-			pixman_region32_fini(&region);
-		}
+		pixman_region32_subtract(&clip, &clip, &es->opaque);
 	}
 
 	pixman_region32_subtract(&ec->damage, &ec->damage, &output->region);
@@ -825,14 +847,10 @@
 			glClear(GL_COLOR_BUFFER_BIT);
 		wlsc_surface_draw(es, output, &total_damage);
 	} else {
-		pixman_region32_init(&opaque);
 		wl_list_for_each(es, &ec->surface_list, link) {
-			pixman_region32_subtract(&es->damage, &total_damage, &opaque);
-			if (es->visual == &ec->compositor.rgb_visual)
-				pixman_region32_union_rect(&opaque, &opaque,
-							   es->x, es->y, es->width, es->height);
+			pixman_region32_copy(&es->damage, &total_damage);
+			pixman_region32_subtract(&total_damage, &total_damage, &es->opaque);
 		}
-		pixman_region32_fini(&opaque);
 
 		wl_list_for_each_reverse(es, &ec->surface_list, link) {
 			wlsc_surface_draw(es, output, &es->damage);
@@ -969,13 +987,6 @@
 {
 	struct wlsc_surface *es = (struct wlsc_surface *) surface;
 
-	/* FIXME: This damages the entire old surface, but we should
-	 * really just damage the part that's no longer covered by the
-	 * surface.  Anything covered by the new surface will be
-	 * damaged by the client. */
-	if (es->buffer)
-		wlsc_surface_damage_below(es);
-
 	buffer->busy_count++;
 	wlsc_buffer_post_release(es->buffer);
 
@@ -984,15 +995,12 @@
 	wl_list_insert(es->buffer->resource.destroy_listener_list.prev,
 		       &es->buffer_destroy_listener.link);
 
-	es->x += x;
-	es->y += y;
-	es->width = buffer->width;
-	es->height = buffer->height;
-	if (x != 0 || y != 0)
-		wlsc_surface_assign_output(es);
 	if (es->visual == NULL)
 		wl_list_insert(&es->compositor->surface_list, &es->link);
 
+	wlsc_surface_configure(es, es->x + x, es->y + y,
+			       buffer->width, buffer->height);
+
 	wlsc_buffer_attach(buffer, surface);
 
 	es->compositor->shell->attach(es->compositor->shell, es);
diff --git a/compositor/compositor.h b/compositor/compositor.h
index e2cf9ef..5c5e40c 100644
--- a/compositor/compositor.h
+++ b/compositor/compositor.h
@@ -238,6 +238,7 @@
 	struct wlsc_compositor *compositor;
 	GLuint texture, saved_texture;
 	pixman_region32_t damage;
+	pixman_region32_t opaque;
 	int32_t x, y, width, height;
 	int32_t pitch;
 	int32_t saved_x, saved_y;
@@ -320,6 +321,10 @@
 		    int32_t x, int32_t y, int32_t width, int32_t height);
 
 void
+wlsc_surface_configure(struct wlsc_surface *surface,
+		       int x, int y, int width, int height);
+
+void
 wlsc_surface_assign_output(struct wlsc_surface *surface);
 
 void
diff --git a/compositor/shell.c b/compositor/shell.c
index b1e780c..91af256 100644
--- a/compositor/shell.c
+++ b/compositor/shell.c
@@ -46,11 +46,8 @@
 	struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
 	struct wlsc_surface *es = move->surface;
 
-	wlsc_surface_damage_below(es);
-	es->x = x + move->dx;
-	es->y = y + move->dy;
-	wlsc_surface_assign_output(es);
-	wlsc_surface_damage(es);
+	wlsc_surface_configure(es, x + move->dx, y + move->dy,
+			       es->width, es->height);
 }
 
 static void