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}