|  |  | @ -44,11 +44,24 @@ static struct wl_output *output = NULL; | 
			
		
	
		
		
			
				
					
					|  |  |  | static struct { |  |  |  | static struct { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	struct wl_buffer *wl_buffer; |  |  |  | 	struct wl_buffer *wl_buffer; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	void *data; |  |  |  | 	void *data; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	enum wl_shm_format format; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	int width, height, stride; |  |  |  | 	int width, height, stride; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	bool y_invert; |  |  |  | 	bool y_invert; | 
			
		
	
		
		
			
				
					
					|  |  |  | } buffer; |  |  |  | } buffer; | 
			
		
	
		
		
			
				
					
					|  |  |  | bool buffer_copy_done = false; |  |  |  | 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) { |  |  |  | static int backingfile(off_t size) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	char template[] = "/tmp/wlroots-shared-XXXXXX"; |  |  |  | 	char template[] = "/tmp/wlroots-shared-XXXXXX"; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	int fd = mkstemp(template); |  |  |  | 	int fd = mkstemp(template); | 
			
		
	
	
		
		
			
				
					|  |  | @ -69,9 +82,8 @@ static int backingfile(off_t size) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return fd; |  |  |  | 	return fd; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | static struct wl_buffer *create_shm_buffer(int width, int height, |  |  |  | static struct wl_buffer *create_shm_buffer(enum wl_shm_format fmt, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		int *stride_out, void **data_out) { |  |  |  | 		int width, int height, int stride, void **data_out) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	int stride = width * 4; |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	int size = stride * height; |  |  |  | 	int size = stride * height; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	int fd = backingfile(size); |  |  |  | 	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); |  |  |  | 	struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); | 
			
		
	
		
		
			
				
					
					|  |  |  | 	close(fd); |  |  |  | 	close(fd); | 
			
		
	
		
		
			
				
					
					|  |  |  | 	struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, width, height, |  |  |  | 	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); |  |  |  | 	wl_shm_pool_destroy(pool); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	*data_out = data; |  |  |  | 	*data_out = data; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	*stride_out = stride; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return buffer; |  |  |  | 	return buffer; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | static void frame_handle_buffer(void *data, |  |  |  | static void frame_handle_buffer(void *data, | 
			
		
	
		
		
			
				
					
					|  |  |  | 		struct zwlr_screencopy_frame_v1 *frame, uint32_t width, uint32_t height, |  |  |  | 		struct zwlr_screencopy_frame_v1 *frame, uint32_t format, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		uint32_t format, uint32_t stride) { |  |  |  | 		uint32_t width, uint32_t height, uint32_t stride) { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	buffer.format = format; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	buffer.width = width; |  |  |  | 	buffer.width = width; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	buffer.height = height; |  |  |  | 	buffer.height = height; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	buffer.stride = stride; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	buffer.wl_buffer = |  |  |  | 	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) { |  |  |  | 	if (buffer.wl_buffer == NULL) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		fprintf(stderr, "failed to create buffer\n"); |  |  |  | 		fprintf(stderr, "failed to create buffer\n"); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		exit(EXIT_FAILURE); |  |  |  | 		exit(EXIT_FAILURE); | 
			
		
	
	
		
		
			
				
					|  |  | @ -160,11 +173,26 @@ static const struct wl_registry_listener registry_listener = { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	.global_remove = handle_global_remove, |  |  |  | 	.global_remove = handle_global_remove, | 
			
		
	
		
		
			
				
					
					|  |  |  | }; |  |  |  | }; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | static void write_image(char *filename, int width, int height, int stride, |  |  |  | static void write_image(char *filename, enum wl_shm_format wl_fmt, int width, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		bool y_invert, void *data) { |  |  |  | 		int height, int stride, bool y_invert, void *data) { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits
 |  |  |  | 	char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	sprintf(size, "%dx%d+0", width, height); |  |  |  | 	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]; |  |  |  | 	int fd[2]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 	if (pipe(fd) != 0) { |  |  |  | 	if (pipe(fd) != 0) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		fprintf(stderr, "cannot create pipe: %s\n", strerror(errno)); |  |  |  | 		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]); |  |  |  | 		close(fd[0]); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 		// We requested WL_SHM_FORMAT_XRGB8888 in little endian, so that's BGRA
 |  |  |  | 		char *argv[11] = {"convert", "-depth", "8", "-size", size, convert, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		// in big endian.
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		char *argv[11] = {"convert", "-depth", "8", "-size", size, "bgra:-", |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			"-alpha", "opaque", filename, NULL}; |  |  |  | 			"-alpha", "opaque", filename, NULL}; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (y_invert) { |  |  |  | 		if (y_invert) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			argv[8] = "-flip"; |  |  |  | 			argv[8] = "-flip"; | 
			
		
	
	
		
		
			
				
					|  |  | @ -241,8 +267,8 @@ int main(int argc, char *argv[]) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		// This space is intentionally left blank
 |  |  |  | 		// This space is intentionally left blank
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	write_image("wayland-screenshot.png", buffer.width, buffer.height, |  |  |  | 	write_image("wayland-screenshot.png", buffer.format, buffer.width, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		buffer.stride, buffer.y_invert, buffer.data); |  |  |  | 		buffer.height, buffer.stride, buffer.y_invert, buffer.data); | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	wl_buffer_destroy(buffer.wl_buffer); |  |  |  | 	wl_buffer_destroy(buffer.wl_buffer); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return EXIT_SUCCESS; |  |  |  | 	return EXIT_SUCCESS; | 
			
		
	
	
		
		
			
				
					|  |  | 
 |