screenshooter: Grab pixel data directly before buffer swap
diff --git a/src/screenshooter.c b/src/screenshooter.c
index b4b341b..7ba475d 100644
--- a/src/screenshooter.c
+++ b/src/screenshooter.c
@@ -36,6 +36,12 @@
 	struct wl_listener destroy_listener;
 };
 
+struct screenshooter_read_pixels {
+	struct weston_read_pixels base;
+	struct wl_buffer *buffer;
+	struct wl_resource *resource;
+};
+
 static void
 copy_bgra_yflip(uint8_t *dst, uint8_t *src, int height,
 		int dst_stride, int src_stride)
@@ -82,37 +88,20 @@
 }
 
 static void
-screenshooter_shoot(struct wl_client *client,
-		    struct wl_resource *resource,
-		    struct wl_resource *output_resource,
-		    struct wl_resource *buffer_resource)
+screenshooter_read_pixels_done(struct weston_read_pixels *base,
+			       struct weston_output *output)
 {
-	struct weston_output *output = output_resource->data;
-	struct wl_buffer *buffer = buffer_resource->data;
-	uint8_t *tmp, *d, *s;
+	struct screenshooter_read_pixels *r =
+		(struct screenshooter_read_pixels *) base;
 	int32_t buffer_stride, output_stride;
+	uint8_t *d, *s;
 
-	if (!wl_buffer_is_shm(buffer))
-		return;
-
-	if (buffer->width < output->current->width ||
-	    buffer->height < output->current->height)
-		return;
-
-	buffer_stride = wl_shm_buffer_get_stride(buffer);
+	buffer_stride = wl_shm_buffer_get_stride(r->buffer);
 	output_stride = output->current->width * 4;
-	tmp = malloc(output_stride * output->current->height);
-	if (tmp == NULL) {
-		wl_resource_post_no_memory(resource);
-		return;
-	}
 
-	glPixelStorei(GL_PACK_ALIGNMENT, 1);
-	output->read_pixels(output, tmp);
-
-	d = wl_shm_buffer_get_data(buffer) + output->y * buffer_stride +
-							output->x * 4;
-	s = tmp + output_stride * (output->current->height - 1);
+	d = wl_shm_buffer_get_data(r->buffer) +
+		output->y * buffer_stride + output->x * 4;
+	s = r->base.data + output_stride * (output->current->height - 1);
 
 	switch (output->compositor->read_format) {
 	case GL_BGRA_EXT:
@@ -127,7 +116,56 @@
 		break;
 	}
 
-	free(tmp);
+	wl_list_remove(&r->base.link);
+
+	screenshooter_send_done(r->resource);
+	free(r->base.data);
+	free(r);
+
+}
+
+static void
+screenshooter_shoot(struct wl_client *client,
+		    struct wl_resource *resource,
+		    struct wl_resource *output_resource,
+		    struct wl_resource *buffer_resource)
+{
+	struct weston_output *output = output_resource->data;
+	struct screenshooter_read_pixels *r;
+	struct wl_buffer *buffer = buffer_resource->data;
+	int32_t stride;
+
+	if (!wl_buffer_is_shm(buffer))
+		return;
+
+	if (buffer->width < output->current->width ||
+	    buffer->height < output->current->height)
+		return;
+
+	r = malloc(sizeof *r);
+	if (r == NULL) {
+		wl_resource_post_no_memory(resource);
+		return;
+	}
+
+	r->base.x = 0;
+	r->base.y = 0;
+	r->base.width = output->current->width;
+	r->base.height = output->current->height;
+	r->base.done = screenshooter_read_pixels_done;
+	r->buffer = buffer;
+	r->resource = resource;
+	stride = buffer->width * 4;
+	r->base.data = malloc(stride * buffer->height);
+
+	if (r->base.data == NULL) {
+		free(r);
+		wl_resource_post_no_memory(resource);
+		return;
+	}
+
+	wl_list_insert(output->read_pixels_list.prev, &r->base.link);
+	weston_compositor_schedule_repaint(output->compositor);
 }
 
 struct screenshooter_interface screenshooter_implementation = {