diff options
-rw-r--r-- | examples/screencopy.c | 56 | ||||
-rw-r--r-- | include/wlr/types/wlr_screencopy_v1.h | 4 | ||||
-rw-r--r-- | protocol/wlr-screencopy-unstable-v1.xml | 29 | ||||
-rw-r--r-- | types/wlr_screencopy_v1.c | 37 |
4 files changed, 72 insertions, 54 deletions
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. </description> - <enum name="error"> - <entry name="invalid_output_region" value="0" - summary="tried to capture an invalid output region"/> - </enum> - <request name="capture_output"> <description summary="capture an output"> 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. </description> <arg name="frame" type="new_id" interface="zwlr_screencopy_frame_v1"/> <arg name="overlay_cursor" type="int" @@ -90,7 +85,7 @@ When created, a "buffer" event will be sent. The client will then be able to send a "copy" request. If the capture is successful, the compositor - will finally a "ready" event. + will send a "flags" followed by a "ready" event. If the capture failed, the "failed" event is sent. This can happen anytime before the "ready" event. @@ -104,14 +99,13 @@ Provides information about the frame's buffer. This event is sent once as soon as the frame is created. - The client should then create a buffer with the provided width and - height, and send a copy request. It can optionally create a buffer with - the preferred format and stride. + The client should then create a buffer with the provided attributes, and + send a "copy" request. </description> + <arg name="format" type="uint" summary="buffer format"/> <arg name="width" type="uint" summary="buffer width"/> <arg name="height" type="uint" summary="buffer height"/> - <arg name="format" type="uint" summary="preferred DRM_FORMAT"/> - <arg name="stride" type="uint" summary="preferred stride"/> + <arg name="stride" type="uint" summary="buffer stride"/> </event> <request name="copy"> @@ -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. </description> <arg name="buffer" type="object" interface="wl_buffer"/> </request> @@ -129,9 +123,8 @@ <enum name="error"> <entry name="already_used" value="0" summary="the object has already been used to copy a wl_buffer"/> - <entry name="invalid_format" value="1" summary="format not supported"/> - <entry name="invalid_dimensions" value="2" - summary="invalid width or height"/> + <entry name="invalid_buffer" value="1" + summary="buffer attributes are invalid"/> </enum> <enum name="flags" bitfield="true"> 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, |