diff options
Diffstat (limited to 'wayland/buffers.c')
-rw-r--r-- | wayland/buffers.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/wayland/buffers.c b/wayland/buffers.c new file mode 100644 index 00000000..13193423 --- /dev/null +++ b/wayland/buffers.c | |||
@@ -0,0 +1,116 @@ | |||
1 | #include <wayland-client.h> | ||
2 | #include <cairo/cairo.h> | ||
3 | #include <pango/pangocairo.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <string.h> | ||
6 | #include <stdio.h> | ||
7 | #include <unistd.h> | ||
8 | #include <errno.h> | ||
9 | #include <sys/mman.h> | ||
10 | #include "client/buffer.h" | ||
11 | #include "list.h" | ||
12 | #include "log.h" | ||
13 | |||
14 | static int create_pool_file(size_t size) { | ||
15 | static const char template[] = "/sway-client-XXXXXX"; | ||
16 | const char *path = getenv("XDG_RUNTIME_DIR"); | ||
17 | if (!path) { | ||
18 | return -1; | ||
19 | } | ||
20 | |||
21 | int ts = (path[strlen(path) - 1] == '/'); | ||
22 | |||
23 | char *name = malloc( | ||
24 | strlen(template) + | ||
25 | strlen(path) + | ||
26 | (ts ? 1 : 0) + 1); | ||
27 | sprintf(name, "%s%s%s", path, ts ? "" : "/", template); | ||
28 | |||
29 | int fd = mkstemp(name); | ||
30 | free(name); | ||
31 | |||
32 | if (fd < 0) { | ||
33 | return -1; | ||
34 | } | ||
35 | |||
36 | if (ftruncate(fd, size) < 0) { | ||
37 | close(fd); | ||
38 | return -1; | ||
39 | } | ||
40 | |||
41 | return fd; | ||
42 | } | ||
43 | |||
44 | static void buffer_release(void *data, struct wl_buffer *wl_buffer) { | ||
45 | struct buffer *buffer = data; | ||
46 | buffer->busy = false; | ||
47 | } | ||
48 | |||
49 | static const struct wl_buffer_listener buffer_listener = { | ||
50 | .release = buffer_release | ||
51 | }; | ||
52 | |||
53 | static struct buffer *create_buffer(struct client_state *state, struct buffer *buf, | ||
54 | int32_t width, int32_t height, uint32_t format) { | ||
55 | |||
56 | uint32_t stride = width * 4; | ||
57 | uint32_t size = stride * height; | ||
58 | |||
59 | int fd = create_pool_file(size); | ||
60 | void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | ||
61 | struct wl_shm_pool *pool = wl_shm_create_pool(state->shm, fd, size); | ||
62 | buf->buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, format); | ||
63 | wl_shm_pool_destroy(pool); | ||
64 | close(fd); | ||
65 | fd = -1; | ||
66 | |||
67 | buf->surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, stride); | ||
68 | buf->cairo = cairo_create(buf->surface); | ||
69 | buf->pango = pango_cairo_create_context(buf->cairo); | ||
70 | |||
71 | wl_buffer_add_listener(buf->buffer, &buffer_listener, state); | ||
72 | return buf; | ||
73 | } | ||
74 | |||
75 | static void destroy_buffer(struct buffer *buffer) { | ||
76 | if (buffer->buffer) { | ||
77 | wl_buffer_destroy(buffer->buffer); | ||
78 | } | ||
79 | if (buffer->cairo) { | ||
80 | cairo_destroy(buffer->cairo); | ||
81 | } | ||
82 | if (buffer->surface) { | ||
83 | cairo_surface_destroy(buffer->surface); | ||
84 | } | ||
85 | memset(buffer, 0, sizeof(struct buffer)); | ||
86 | } | ||
87 | |||
88 | struct buffer *get_next_buffer(struct client_state *state) { | ||
89 | struct buffer *buffer = NULL; | ||
90 | |||
91 | int i; | ||
92 | for (i = 0; i < 2; ++i) { | ||
93 | if (state->buffers[i].busy) { | ||
94 | continue; | ||
95 | } | ||
96 | buffer = &state->buffers[i]; | ||
97 | } | ||
98 | |||
99 | if (!buffer) { | ||
100 | return NULL; | ||
101 | } | ||
102 | |||
103 | if (buffer->width != state->width || buffer->height != state->height) { | ||
104 | destroy_buffer(buffer); | ||
105 | } | ||
106 | |||
107 | if (!buffer->buffer) { | ||
108 | if (!create_buffer(state, buffer, state->width, state->height, WL_SHM_FORMAT_ARGB8888)) { | ||
109 | return NULL; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | state->cairo = buffer->cairo; | ||
114 | state->buffer = buffer; | ||
115 | return buffer; | ||
116 | } | ||