main
wayland.c
1/* wld: wayland.c
2 *
3 * Copyright (c) 2013, 2014 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "wayland.h"
25#include "wayland-private.h"
26#include "wld-private.h"
27
28#include <stdlib.h>
29#include <wayland-client.h>
30
31struct wayland_buffer {
32 struct wld_exporter exporter;
33 struct wld_destructor destructor;
34 struct wl_buffer *wl;
35};
36
37struct wayland_buffer_socket {
38 struct buffer_socket base;
39 struct wl_buffer_listener listener;
40 struct wld_surface *surface;
41 struct wl_surface *wl;
42 struct wl_display *display;
43 struct wl_event_queue *queue;
44};
45
46static bool buffer_socket_attach(struct buffer_socket *socket,
47 struct buffer *buffer);
48static void buffer_socket_process(struct buffer_socket *socket);
49static void buffer_socket_destroy(struct buffer_socket *socket);
50
51static const struct buffer_socket_impl buffer_socket_impl = {
52 .attach = &buffer_socket_attach,
53 .process = &buffer_socket_process,
54 .destroy = &buffer_socket_destroy
55};
56
57IMPL(wayland_buffer_socket, buffer_socket)
58
59static void buffer_release(void *data, struct wl_buffer *buffer);
60
61const static struct wayland_impl *impls[] = {
62#if WITH_WAYLAND_DRM
63 [WLD_DRM] = &drm_wayland_impl,
64#endif
65
66#if WITH_WAYLAND_SHM
67 [WLD_SHM] = &shm_wayland_impl,
68#endif
69};
70
71enum wld_wayland_interface_id
72interface_id(const char *string)
73{
74 if (strcmp(string, "drm") == 0)
75 return WLD_DRM;
76 if (strcmp(string, "shm") == 0)
77 return WLD_SHM;
78
79 fprintf(stderr, "Unknown Wayland interface specified: '%s'\n", string);
80
81 return WLD_NONE;
82}
83
84EXPORT
85struct wld_context *
86wld_wayland_create_context(struct wl_display *display, enum wld_wayland_interface_id id, ...)
87{
88 struct wayland_context *context = NULL;
89 struct wl_event_queue *queue;
90 va_list requested_impls;
91 bool impls_tried[ARRAY_LENGTH(impls)] = { 0 };
92 const char *interface_string;
93
94 if (!(queue = wl_display_create_queue(display)))
95 return NULL;
96
97 if ((interface_string = getenv("WLD_WAYLAND_INTERFACE"))) {
98 id = interface_id(interface_string);
99
100 if ((context = impls[id]->create_context(display, queue)))
101 return &context->base;
102
103 fprintf(stderr, "Could not create context for Wayland interface '%s'\n",
104 interface_string);
105
106 return NULL;
107 }
108
109 va_start(requested_impls, id);
110
111 while (id >= 0) {
112 if (impls_tried[id] || !impls[id])
113 continue;
114
115 if ((context = impls[id]->create_context(display, queue)))
116 goto done;
117
118 impls_tried[id] = true;
119 id = va_arg(requested_impls, enum wld_wayland_interface_id);
120 }
121
122 va_end(requested_impls);
123
124 /* If the user specified WLD_ANY, try any remaining implementations. */
125 if (!context && id == WLD_ANY) {
126 for (id = 0; id < ARRAY_LENGTH(impls); ++id) {
127 if (impls_tried[id] || !impls[id])
128 continue;
129
130 if ((context = impls[id]->create_context(display, queue)))
131 break;
132 }
133 }
134
135 if (!context) {
136 DEBUG("Could not initialize any of the specified implementations\n");
137 return NULL;
138 }
139
140done:
141 context->impl = impls[id];
142 context->display = display;
143 context->queue = queue;
144
145 return &context->base;
146}
147
148EXPORT
149struct wld_surface *
150wld_wayland_create_surface(struct wld_context *context,
151 uint32_t width, uint32_t height,
152 uint32_t format, uint32_t flags,
153 struct wl_surface *wl)
154{
155 struct wayland_buffer_socket *socket;
156
157 if (!(socket = malloc(sizeof *socket)))
158 goto error0;
159
160 socket->base.impl = &buffer_socket_impl;
161 socket->listener.release = &buffer_release;
162 socket->wl = wl;
163 socket->queue = ((struct wayland_context *)context)->queue;
164 socket->display = ((struct wayland_context *)context)->display;
165 socket->surface = buffered_surface_create(context, width, height, format,
166 flags, &socket->base);
167
168 if (!socket->surface)
169 goto error1;
170
171 return socket->surface;
172
173error1:
174 free(socket);
175error0:
176 return NULL;
177}
178
179EXPORT
180bool
181wld_wayland_has_format(struct wld_context *base, uint32_t format)
182{
183 struct wayland_context *context = (void *)base;
184
185 return context->impl->has_format(base, format);
186}
187
188static bool
189buffer_export(struct wld_exporter *exporter,
190 struct wld_buffer *buffer,
191 uint32_t type, union wld_object *object)
192{
193 struct wayland_buffer *wayland_buffer = CONTAINER_OF(exporter, struct wayland_buffer, exporter);
194
195 switch (type) {
196 case WLD_WAYLAND_OBJECT_BUFFER:
197 object->ptr = wayland_buffer->wl;
198 return true;
199 default:
200 return false;
201 }
202}
203
204static void
205buffer_destroy(struct wld_destructor *destructor)
206{
207 struct wayland_buffer *wayland_buffer = CONTAINER_OF(destructor, struct wayland_buffer, destructor);
208
209 wl_buffer_destroy(wayland_buffer->wl);
210 free(wayland_buffer);
211}
212
213bool
214wayland_buffer_add_exporter(struct buffer *buffer, struct wl_buffer *wl)
215{
216 struct wayland_buffer *wayland_buffer;
217
218 if (!(wayland_buffer = malloc(sizeof *wayland_buffer)))
219 return false;
220
221 wayland_buffer->wl = wl;
222 wayland_buffer->exporter.export = &buffer_export;
223 wld_buffer_add_exporter(&buffer->base, &wayland_buffer->exporter);
224 wayland_buffer->destructor.destroy = &buffer_destroy;
225 wld_buffer_add_destructor(&buffer->base, &wayland_buffer->destructor);
226
227 return true;
228}
229
230bool
231buffer_socket_attach(struct buffer_socket *base, struct buffer *buffer)
232{
233 struct wayland_buffer_socket *socket = wayland_buffer_socket(base);
234 struct wl_buffer *wl;
235 union wld_object object;
236
237 if (!wld_export(&buffer->base, WLD_WAYLAND_OBJECT_BUFFER, &object))
238 return false;
239
240 wl = object.ptr;
241
242 if (!wl_proxy_get_listener((struct wl_proxy *)wl))
243 wl_buffer_add_listener(wl, &socket->listener, buffer);
244
245 wl_surface_attach(socket->wl, wl, 0, 0);
246
247 if (pixman_region32_not_empty(&buffer->base.damage)) {
248 pixman_box32_t *box;
249 int num_boxes;
250
251 box = pixman_region32_rectangles(&buffer->base.damage, &num_boxes);
252
253 while (num_boxes--) {
254 wl_surface_damage(socket->wl, box->x1, box->y1,
255 box->x2 - box->x1, box->y2 - box->y1);
256 }
257 }
258
259 wl_surface_commit(socket->wl);
260
261 return true;
262}
263
264void
265buffer_socket_process(struct buffer_socket *base)
266{
267 struct wayland_buffer_socket *socket = wayland_buffer_socket(base);
268
269 /* Since events for our wl_buffers lie in a special queue used by WLD, we
270 * must dispatch these events here so that we see any release events before
271 * the next back buffer is chosen. */
272 wl_display_dispatch_queue_pending(socket->display, socket->queue);
273}
274
275void
276buffer_socket_destroy(struct buffer_socket *socket)
277{
278 free(socket);
279}
280
281void
282buffer_release(void *data, struct wl_buffer *wl)
283{
284 struct wld_buffer *buffer = data;
285 const struct wl_buffer_listener *listener = wl_proxy_get_listener((struct wl_proxy *)wl);
286 struct wayland_buffer_socket *socket = CONTAINER_OF(listener, struct wayland_buffer_socket, listener);
287
288 wld_surface_release(socket->surface, buffer);
289}