diff --git a/examples/screencopy.c b/examples/screencopy.c
index 7be06d68..dc1984e6 100644
--- a/examples/screencopy.c
+++ b/examples/screencopy.c
@@ -44,11 +44,24 @@ static struct wl_output *output = NULL;
static struct {
struct wl_buffer *wl_buffer;
void *data;
+ enum wl_shm_format format;
int width, height, stride;
bool y_invert;
} buffer;
bool buffer_copy_done = false;
+// wl_shm_format describes little-endian formats, ImageMagick uses big-endian
+// formats.
+static const struct {
+ enum wl_shm_format wl_format;
+ char *str_format;
+} formats[] = {
+ {WL_SHM_FORMAT_XRGB8888, "BGRA"},
+ {WL_SHM_FORMAT_ARGB8888, "BGRA"},
+ {WL_SHM_FORMAT_XBGR8888, "RGBA"},
+ {WL_SHM_FORMAT_ABGR8888, "RGBA"},
+};
+
static int backingfile(off_t size) {
char template[] = "/tmp/wlroots-shared-XXXXXX";
int fd = mkstemp(template);
@@ -69,9 +82,8 @@ static int backingfile(off_t size) {
return fd;
}
-static struct wl_buffer *create_shm_buffer(int width, int height,
- int *stride_out, void **data_out) {
- int stride = width * 4;
+static struct wl_buffer *create_shm_buffer(enum wl_shm_format fmt,
+ int width, int height, int stride, void **data_out) {
int size = stride * height;
int fd = backingfile(size);
@@ -90,21 +102,22 @@ static struct wl_buffer *create_shm_buffer(int width, int height,
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
close(fd);
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, width, height,
- stride, WL_SHM_FORMAT_XRGB8888);
+ stride, fmt);
wl_shm_pool_destroy(pool);
*data_out = data;
- *stride_out = stride;
return buffer;
}
static void frame_handle_buffer(void *data,
- struct zwlr_screencopy_frame_v1 *frame, uint32_t width, uint32_t height,
- uint32_t format, uint32_t stride) {
+ struct zwlr_screencopy_frame_v1 *frame, uint32_t format,
+ uint32_t width, uint32_t height, uint32_t stride) {
+ buffer.format = format;
buffer.width = width;
buffer.height = height;
+ buffer.stride = stride;
buffer.wl_buffer =
- create_shm_buffer(width, height, &buffer.stride, &buffer.data);
+ create_shm_buffer(format, width, height, stride, &buffer.data);
if (buffer.wl_buffer == NULL) {
fprintf(stderr, "failed to create buffer\n");
exit(EXIT_FAILURE);
@@ -160,11 +173,26 @@ static const struct wl_registry_listener registry_listener = {
.global_remove = handle_global_remove,
};
-static void write_image(char *filename, int width, int height, int stride,
- bool y_invert, void *data) {
+static void write_image(char *filename, enum wl_shm_format wl_fmt, int width,
+ int height, int stride, bool y_invert, void *data) {
char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits
sprintf(size, "%dx%d+0", width, height);
+ const char *fmt_str = NULL;
+ for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) {
+ if (formats[i].wl_format == wl_fmt) {
+ fmt_str = formats[i].str_format;
+ break;
+ }
+ }
+ if (fmt_str == NULL) {
+ fprintf(stderr, "unsupported format %"PRIu32"\n", wl_fmt);
+ exit(EXIT_FAILURE);
+ }
+ char convert[strlen(fmt_str) + 3];
+ memcpy(convert, fmt_str, strlen(fmt_str) + 1);
+ strcat(convert, ":-");
+
int fd[2];
if (pipe(fd) != 0) {
fprintf(stderr, "cannot create pipe: %s\n", strerror(errno));
@@ -191,9 +219,7 @@ static void write_image(char *filename, int width, int height, int stride,
}
close(fd[0]);
- // We requested WL_SHM_FORMAT_XRGB8888 in little endian, so that's BGRA
- // in big endian.
- char *argv[11] = {"convert", "-depth", "8", "-size", size, "bgra:-",
+ char *argv[11] = {"convert", "-depth", "8", "-size", size, convert,
"-alpha", "opaque", filename, NULL};
if (y_invert) {
argv[8] = "-flip";
@@ -241,8 +267,8 @@ int main(int argc, char *argv[]) {
// This space is intentionally left blank
}
- write_image("wayland-screenshot.png", buffer.width, buffer.height,
- buffer.stride, buffer.y_invert, buffer.data);
+ write_image("wayland-screenshot.png", buffer.format, buffer.width,
+ buffer.height, buffer.stride, buffer.y_invert, buffer.data);
wl_buffer_destroy(buffer.wl_buffer);
return EXIT_SUCCESS;
diff --git a/include/wlr/types/wlr_screencopy_v1.h b/include/wlr/types/wlr_screencopy_v1.h
index 4766d680..69f62437 100644
--- a/include/wlr/types/wlr_screencopy_v1.h
+++ b/include/wlr/types/wlr_screencopy_v1.h
@@ -18,7 +18,9 @@ struct wlr_screencopy_frame_v1 {
struct wlr_screencopy_manager_v1 *manager;
struct wl_list link;
- struct wlr_box buffer_box;
+ enum wl_shm_format format;
+ struct wlr_box box;
+ int stride;
struct wl_shm_buffer *buffer;
diff --git a/protocol/wlr-screencopy-unstable-v1.xml b/protocol/wlr-screencopy-unstable-v1.xml
index c54b7268..a7a2d172 100644
--- a/protocol/wlr-screencopy-unstable-v1.xml
+++ b/protocol/wlr-screencopy-unstable-v1.xml
@@ -43,11 +43,6 @@
source.
-
-
-
-
Capture the next frame of an entire output.
@@ -63,8 +58,8 @@
Capture the next frame of an output's region.
The region is given in output logical coordinates, see
- xdg_output.logical_size. Trying to capture a region spanning outside the
- output extents is a protocol error.
+ xdg_output.logical_size. The region will be clipped to the output's
+ extents.
+
-
-
+
@@ -120,8 +114,8 @@
correct size, see zwlr_screencopy_frame_v1.buffer. The buffer needs to
have a supported format.
- If the frame is successfully copied, a ready event is sent. Otherwise,
- an abort event is sent.
+ If the frame is successfully copied, a "flags" and a "ready" events are
+ sent. Otherwise, a "failed" event is sent.
@@ -129,9 +123,8 @@
-
-
+
diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c
index a600a716..027d4b51 100644
--- a/types/wlr_screencopy_v1.c
+++ b/types/wlr_screencopy_v1.c
@@ -28,8 +28,8 @@ static void frame_handle_output_swap_buffers(struct wl_listener *listener,
wl_list_remove(&frame->output_swap_buffers.link);
wl_list_init(&frame->output_swap_buffers.link);
- int x = frame->buffer_box.x;
- int y = frame->buffer_box.y;
+ int x = frame->box.x;
+ int y = frame->box.y;
struct wl_shm_buffer *buffer = frame->buffer;
assert(buffer != NULL);
@@ -66,27 +66,24 @@ static void frame_handle_copy(struct wl_client *client,
struct wl_resource *buffer_resource) {
struct wlr_screencopy_frame_v1 *frame = frame_from_resource(frame_resource);
struct wlr_output *output = frame->output;
- struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
struct wl_shm_buffer *buffer = wl_shm_buffer_get(buffer_resource);
if (buffer == NULL) {
- zwlr_screencopy_frame_v1_send_failed(frame_resource);
- return;
- }
-
- enum wl_shm_format fmt = wl_shm_buffer_get_format(buffer);
- if (!wlr_renderer_format_supported(renderer, fmt)) {
wl_resource_post_error(frame->resource,
- ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_FORMAT,
- "unsupported format %"PRIu32, fmt);
+ ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER,
+ "unsupported buffer type");
return;
}
- if (frame->buffer_box.width != wl_shm_buffer_get_width(buffer) ||
- frame->buffer_box.height != wl_shm_buffer_get_height(buffer)) {
+ enum wl_shm_format fmt = wl_shm_buffer_get_format(buffer);
+ int32_t width = wl_shm_buffer_get_width(buffer);
+ int32_t height = wl_shm_buffer_get_height(buffer);
+ int32_t stride = wl_shm_buffer_get_stride(buffer);
+ if (fmt != frame->format || width != frame->box.width ||
+ height != frame->box.height || stride != frame->stride) {
wl_resource_post_error(frame->resource,
- ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_DIMENSIONS,
- "invalid width or height");
+ ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER,
+ "invalid buffer attributes");
return;
}
@@ -165,7 +162,6 @@ static void capture_output(struct wl_client *client,
return;
}
frame->manager = manager;
-
frame->output = output;
frame->resource = wl_resource_create(client,
@@ -182,10 +178,11 @@ static void capture_output(struct wl_client *client,
wl_list_init(&frame->output_swap_buffers.link);
- frame->buffer_box = buffer_box;
- zwlr_screencopy_frame_v1_send_buffer(frame->resource,
- frame->buffer_box.width, frame->buffer_box.height,
- WL_SHM_FORMAT_XRGB8888, 4 * frame->buffer_box.width);
+ frame->format = WL_SHM_FORMAT_XRGB8888;
+ frame->box = buffer_box;
+ frame->stride = 4 * buffer_box.width;
+ zwlr_screencopy_frame_v1_send_buffer(frame->resource, frame->format,
+ buffer_box.width, buffer_box.height, frame->stride);
}
static void manager_handle_capture_output(struct wl_client *client,