| 
									
										
										
										
											2018-09-03 09:08:49 +02:00
										 |  |  | #define _POSIX_C_SOURCE 200809
 | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | #include <assert.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-07 16:57:51 -04:00
										 |  |  | #include <cairo.h>
 | 
					
						
							| 
									
										
										
										
											2022-11-24 17:56:01 -05:00
										 |  |  | #include <errno.h>
 | 
					
						
							| 
									
										
										
										
											2018-05-25 19:39:17 +01:00
										 |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <pango/pangocairo.h>
 | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <sys/mman.h>
 | 
					
						
							| 
									
										
										
										
											2022-11-24 17:56:01 -05:00
										 |  |  | #include <time.h>
 | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #include <wayland-client.h>
 | 
					
						
							| 
									
										
										
										
											2018-03-28 12:21:50 -04:00
										 |  |  | #include "config.h"
 | 
					
						
							|  |  |  | #include "pool-buffer.h"
 | 
					
						
							| 
									
										
										
										
											2019-10-28 22:54:16 -07:00
										 |  |  | #include "util.h"
 | 
					
						
							| 
									
										
										
										
											2018-05-25 19:39:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-24 17:56:01 -05:00
										 |  |  | static int anonymous_shm_open(void) { | 
					
						
							|  |  |  | 	int retries = 100; | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-24 17:56:01 -05:00
										 |  |  | 	do { | 
					
						
							|  |  |  | 		// try a probably-unique name
 | 
					
						
							|  |  |  | 		struct timespec ts; | 
					
						
							|  |  |  | 		clock_gettime(CLOCK_MONOTONIC, &ts); | 
					
						
							|  |  |  | 		pid_t pid = getpid(); | 
					
						
							|  |  |  | 		char name[50]; | 
					
						
							|  |  |  | 		snprintf(name, sizeof(name), "/sway-%x-%x", | 
					
						
							|  |  |  | 			(unsigned int)pid, (unsigned int)ts.tv_nsec); | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-24 17:56:01 -05:00
										 |  |  | 		// shm_open guarantees that O_CLOEXEC is set
 | 
					
						
							|  |  |  | 		int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); | 
					
						
							|  |  |  | 		if (fd >= 0) { | 
					
						
							|  |  |  | 			shm_unlink(name); | 
					
						
							|  |  |  | 			return fd; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-24 17:56:01 -05:00
										 |  |  | 		--retries; | 
					
						
							|  |  |  | 	} while (retries > 0 && errno == EEXIST); | 
					
						
							| 
									
										
										
										
											2018-05-25 19:39:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-24 17:56:01 -05:00
										 |  |  | 	return -1; | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void buffer_release(void *data, struct wl_buffer *wl_buffer) { | 
					
						
							|  |  |  | 	struct pool_buffer *buffer = data; | 
					
						
							|  |  |  | 	buffer->busy = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct wl_buffer_listener buffer_listener = { | 
					
						
							|  |  |  | 	.release = buffer_release | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct pool_buffer *create_buffer(struct wl_shm *shm, | 
					
						
							|  |  |  | 		struct pool_buffer *buf, int32_t width, int32_t height, | 
					
						
							|  |  |  | 		uint32_t format) { | 
					
						
							|  |  |  | 	uint32_t stride = width * 4; | 
					
						
							| 
									
										
										
										
											2018-05-25 19:42:23 +01:00
										 |  |  | 	size_t size = stride * height; | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-24 17:56:01 -05:00
										 |  |  | 	int fd = anonymous_shm_open(); | 
					
						
							|  |  |  | 	if (fd == -1) { | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (ftruncate(fd, size) < 0) { | 
					
						
							|  |  |  | 		close(fd); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | 	void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | 
					
						
							|  |  |  | 	struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); | 
					
						
							|  |  |  | 	buf->buffer = wl_shm_pool_create_buffer(pool, 0, | 
					
						
							|  |  |  | 			width, height, stride, format); | 
					
						
							|  |  |  | 	wl_shm_pool_destroy(pool); | 
					
						
							|  |  |  | 	close(fd); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-25 19:42:23 +01:00
										 |  |  | 	buf->size = size; | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | 	buf->width = width; | 
					
						
							|  |  |  | 	buf->height = height; | 
					
						
							| 
									
										
										
										
											2018-05-25 19:42:23 +01:00
										 |  |  | 	buf->data = data; | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | 	buf->surface = cairo_image_surface_create_for_data(data, | 
					
						
							|  |  |  | 			CAIRO_FORMAT_ARGB32, width, height, stride); | 
					
						
							|  |  |  | 	buf->cairo = cairo_create(buf->surface); | 
					
						
							|  |  |  | 	buf->pango = pango_cairo_create_context(buf->cairo); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wl_buffer_add_listener(buf->buffer, &buffer_listener, buf); | 
					
						
							|  |  |  | 	return buf; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-05 15:39:57 -04:00
										 |  |  | void destroy_buffer(struct pool_buffer *buffer) { | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | 	if (buffer->buffer) { | 
					
						
							|  |  |  | 		wl_buffer_destroy(buffer->buffer); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (buffer->cairo) { | 
					
						
							|  |  |  | 		cairo_destroy(buffer->cairo); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (buffer->surface) { | 
					
						
							|  |  |  | 		cairo_surface_destroy(buffer->surface); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (buffer->pango) { | 
					
						
							|  |  |  | 		g_object_unref(buffer->pango); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-25 19:42:23 +01:00
										 |  |  | 	if (buffer->data) { | 
					
						
							|  |  |  | 		munmap(buffer->data, buffer->size); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | 	memset(buffer, 0, sizeof(struct pool_buffer)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct pool_buffer *get_next_buffer(struct wl_shm *shm, | 
					
						
							|  |  |  | 		struct pool_buffer pool[static 2], uint32_t width, uint32_t height) { | 
					
						
							|  |  |  | 	struct pool_buffer *buffer = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (size_t i = 0; i < 2; ++i) { | 
					
						
							|  |  |  | 		if (pool[i].busy) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		buffer = &pool[i]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!buffer) { | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (buffer->width != width || buffer->height != height) { | 
					
						
							|  |  |  | 		destroy_buffer(buffer); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!buffer->buffer) { | 
					
						
							|  |  |  | 		if (!create_buffer(shm, buffer, width, height, | 
					
						
							|  |  |  | 					WL_SHM_FORMAT_ARGB8888)) { | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-17 17:34:12 -04:00
										 |  |  | 	buffer->busy = true; | 
					
						
							| 
									
										
										
										
											2018-03-27 15:25:25 -04:00
										 |  |  | 	return buffer; | 
					
						
							|  |  |  | } |