wayland-client.c 13.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * Copyright © 2008 Kristian Høgsberg
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting documentation, and
 * that the name of the copyright holders not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  The copyright holders make no representations
 * about the suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 * OF THIS SOFTWARE.
 */

23 24 25 26
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
27
#include <stdbool.h>
28 29 30 31 32 33
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <ctype.h>
34
#include <assert.h>
35
#include <fcntl.h>
36 37
#include <sys/poll.h>

38
#include "wayland-util.h"
39
#include "wayland-client.h"
40
#include "wayland-private.h"
41

42 43 44 45
struct wl_global_listener {
	wl_display_global_func_t handler;
	void *data;
	struct wl_list link;
46 47
};

48
struct wl_proxy {
49
	struct wl_object object;
50
	struct wl_display *display;
51
	void *user_data;
52 53
};

54 55 56 57 58 59 60
struct wl_global {
	uint32_t id;
	char *interface;
	uint32_t version;
	struct wl_list link;
};

61 62 63 64 65
struct wl_display {
	struct wl_proxy proxy;
	struct wl_connection *connection;
	int fd;
	uint32_t mask;
66
	struct wl_map objects;
67
	struct wl_list global_listener_list;
68
	struct wl_list global_list;
69 70 71 72 73 74 75 76

	wl_display_update_func_t update;
	void *update_data;

	wl_display_global_func_t global_handler;
	void *global_handler_data;
};

77 78
static int wl_debug = 0;

79 80 81 82 83 84 85 86 87 88 89 90 91 92
static int
connection_update(struct wl_connection *connection,
		  uint32_t mask, void *data)
{
	struct wl_display *display = data;

	display->mask = mask;
	if (display->update)
		return display->update(display->mask,
				       display->update_data);

	return 0;
}

93 94 95 96 97
WL_EXPORT struct wl_global_listener *
wl_display_add_global_listener(struct wl_display *display,
			       wl_display_global_func_t handler, void *data)
{
	struct wl_global_listener *listener;
98
	struct wl_global *global;
99

100 101 102
	listener = malloc(sizeof *listener);
	if (listener == NULL)
		return NULL;
103

104 105 106
	listener->handler = handler;
	listener->data = data;
	wl_list_insert(display->global_listener_list.prev, &listener->link);
107

108 109 110 111
	wl_list_for_each(global, &display->global_list, link)
		(*listener->handler)(display, global->id, global->interface,
				     global->version, listener->data);

112
	return listener;
113 114
}

115
WL_EXPORT void
116 117 118 119 120 121 122
wl_display_remove_global_listener(struct wl_display *display,
				  struct wl_global_listener *listener)
{
	wl_list_remove(&listener->link);
	free(listener);
}

123
WL_EXPORT struct wl_proxy *
124
wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)
125 126
{
	struct wl_proxy *proxy;
127
	struct wl_display *display = factory->display;
128 129 130 131 132

	proxy = malloc(sizeof *proxy);
	if (proxy == NULL)
		return NULL;

133
	proxy->object.interface = interface;
134
	proxy->object.implementation = NULL;
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
	proxy->object.id = wl_map_insert_new(&display->objects,
					     WL_MAP_CLIENT_SIDE, proxy);
	proxy->display = display;

	return proxy;
}

WL_EXPORT struct wl_proxy *
wl_proxy_create_for_id(struct wl_proxy *factory,
		       uint32_t id, const struct wl_interface *interface)
{
	struct wl_proxy *proxy;
	struct wl_display *display = factory->display;

	proxy = malloc(sizeof *proxy);
	if (proxy == NULL)
		return NULL;

	proxy->object.interface = interface;
	proxy->object.implementation = NULL;
155
	proxy->object.id = id;
156
	proxy->display = display;
157
	wl_map_insert_at(&display->objects, id, proxy);
158 159 160 161

	return proxy;
}

162 163 164
WL_EXPORT void
wl_proxy_destroy(struct wl_proxy *proxy)
{
165 166 167 168 169 170
	if (proxy->object.id < WL_SERVER_ID_START)
		wl_map_insert_at(&proxy->display->objects,
				 proxy->object.id, WL_ZOMBIE_OBJECT);
	else
		wl_map_insert_at(&proxy->display->objects,
				 proxy->object.id, NULL);
171 172 173
	free(proxy);
}

174
WL_EXPORT int
175 176
wl_proxy_add_listener(struct wl_proxy *proxy,
		      void (**implementation)(void), void *data)
177
{
178 179
	if (proxy->object.implementation) {
		fprintf(stderr, "proxy already has listener\n");
180
		return -1;
181
	}
182

183 184
	proxy->object.implementation = implementation;
	proxy->user_data = data;
185 186 187 188

	return 0;
}

189
WL_EXPORT void
190 191
wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
{
192
	struct wl_closure *closure;
193 194 195
	va_list ap;

	va_start(ap, opcode);
196
	closure = wl_connection_vmarshal(proxy->display->connection,
197 198
					 &proxy->object, opcode, ap,
					 &proxy->object.interface->methods[opcode]);
199
	va_end(ap);
200

201 202 203 204 205
	if (closure == NULL) {
		fprintf(stderr, "Error marshalling request\n");
		abort();
	}

206
	wl_closure_send(closure, proxy->display->connection);
207

208 209
	if (wl_debug)
		wl_closure_print(closure, &proxy->object, true);
210

211
	wl_closure_destroy(closure);
212 213
}

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
/* Can't do this, there may be more than one instance of an
 * interface... */
WL_EXPORT uint32_t
wl_display_get_global(struct wl_display *display,
		      const char *interface, uint32_t version)
{
	struct wl_global *global;

	wl_list_for_each(global, &display->global_list, link)
		if (strcmp(interface, global->interface) == 0 &&
		    version <= global->version)
			return global->id;

	return 0;
}

230
static void
Kristian Høgsberg's avatar
Kristian Høgsberg committed
231 232 233
display_handle_error(void *data,
		     struct wl_display *display, struct wl_object *object,
		     uint32_t code, const char *message)
234
{
Kristian Høgsberg's avatar
Kristian Høgsberg committed
235 236
	fprintf(stderr, "%s@%d: error %d: %s\n",
		object->interface->name, object->id, code, message);
237
	abort();
238 239 240
}

static void
241 242
display_handle_global(void *data,
		      struct wl_display *display,
243 244
		      uint32_t id, const char *interface, uint32_t version)
{
245
	struct wl_global_listener *listener;
246
	struct wl_global *global;
247

248 249 250 251 252 253
	global = malloc(sizeof *global);
	global->id = id;
	global->interface = strdup(interface);
	global->version = version;
	wl_list_insert(display->global_list.prev, &global->link);

254 255 256
	wl_list_for_each(listener, &display->global_listener_list, link)
		(*listener->handler)(display,
				     id, interface, version, listener->data);
257 258
}

259 260 261 262 263 264 265 266
static void
wl_global_destroy(struct wl_global *global)
{
	wl_list_remove(&global->link);
	free(global->interface);
	free(global);
}

Laszlo Agocs's avatar
Laszlo Agocs committed
267 268 269 270 271 272 273 274
static void
display_handle_global_remove(void *data,
                             struct wl_display *display, uint32_t id)
{
	struct wl_global *global;

	wl_list_for_each(global, &display->global_list, link)
		if (global->id == id) {
275
			wl_global_destroy(global);
Laszlo Agocs's avatar
Laszlo Agocs committed
276 277 278 279
			break;
		}
}

280 281 282 283 284 285 286 287 288 289 290 291
static void
display_handle_delete_id(void *data, struct wl_display *display, uint32_t id)
{
	struct wl_proxy *proxy;

	proxy = wl_map_lookup(&display->objects, id);
	if (proxy != WL_ZOMBIE_OBJECT)
		fprintf(stderr, "server sent delete_id for live object\n");
	else
		wl_map_remove(&display->objects, id);
}

292
static const struct wl_display_listener display_listener = {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
293
	display_handle_error,
294
	display_handle_global,
Laszlo Agocs's avatar
Laszlo Agocs committed
295
	display_handle_global_remove,
296
	display_handle_delete_id
297 298
};

299 300
static int
connect_to_socket(struct wl_display *display, const char *name)
301
{
302
	struct sockaddr_un addr;
303
	socklen_t size;
304 305
	const char *runtime_dir;
	size_t name_size;
306

307
	display->fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
308 309
	if (display->fd < 0)
		return -1;
310

311 312 313 314 315 316 317 318 319 320 321 322 323 324
	runtime_dir = getenv("XDG_RUNTIME_DIR");
	if (runtime_dir == NULL) {
		runtime_dir = ".";
		fprintf(stderr,
			"XDG_RUNTIME_DIR not set, falling back to %s\n",
			runtime_dir);
	}

	if (name == NULL)
		name = getenv("WAYLAND_DISPLAY");
	if (name == NULL)
		name = "wayland-0";

	memset(&addr, 0, sizeof addr);
325
	addr.sun_family = AF_LOCAL;
326 327 328
	name_size =
		snprintf(addr.sun_path, sizeof addr.sun_path,
			 "%s/%s", runtime_dir, name) + 1;
329

330
	size = offsetof (struct sockaddr_un, sun_path) + name_size;
331

332
	if (connect(display->fd, (struct sockaddr *) &addr, size) < 0) {
333
		close(display->fd);
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
		return -1;
	}

	return 0;
}

WL_EXPORT struct wl_display *
wl_display_connect(const char *name)
{
	struct wl_display *display;
	const char *debug;
	char *connection, *end;
	int flags;

	debug = getenv("WAYLAND_DEBUG");
	if (debug)
		wl_debug = 1;

	display = malloc(sizeof *display);
	if (display == NULL)
		return NULL;

	memset(display, 0, sizeof *display);
	connection = getenv("WAYLAND_SOCKET");
	if (connection) {
		display->fd = strtol(connection, &end, 0);
		if (*end != '\0') {
			free(display);
			return NULL;
		}
		flags = fcntl(display->fd, F_GETFD);
		if (flags != -1)
			fcntl(display->fd, F_SETFD, flags | FD_CLOEXEC);
367
		unsetenv("WAYLAND_SOCKET");
368
	} else if (connect_to_socket(display, name) < 0) {
369
		free(display);
370 371 372
		return NULL;
	}

373
	wl_map_init(&display->objects);
374
	wl_list_init(&display->global_listener_list);
375
	wl_list_init(&display->global_list);
376

377
	wl_map_insert_new(&display->objects, WL_MAP_CLIENT_SIDE, NULL);
378

379
	display->proxy.object.interface = &wl_display_interface;
380 381 382
	display->proxy.object.id =
		wl_map_insert_new(&display->objects,
				  WL_MAP_CLIENT_SIDE, display);
383
	display->proxy.display = display;
384
	display->proxy.object.implementation = (void(**)(void)) &display_listener;
385
	display->proxy.user_data = display;
386

387
	display->connection = wl_connection_create(display->fd,
388
						   connection_update, display);
389
	if (display->connection == NULL) {
390
		wl_map_release(&display->objects);
391 392 393 394
		close(display->fd);
		free(display);
		return NULL;
	}
395

396
	return display;
397 398
}

399
WL_EXPORT void
400
wl_display_disconnect(struct wl_display *display)
401
{
402 403 404
	struct wl_global *global, *gnext;
	struct wl_global_listener *listener, *lnext;

405
	wl_connection_destroy(display->connection);
406
	wl_map_release(&display->objects);
407 408
	wl_list_for_each_safe(global, gnext,
			      &display->global_list, link)
409
		wl_global_destroy(global);
410 411 412 413
	wl_list_for_each_safe(listener, lnext,
			      &display->global_listener_list, link)
		free(listener);

414 415
	close(display->fd);
	free(display);
416 417
}

418
WL_EXPORT int
419 420
wl_display_get_fd(struct wl_display *display,
		  wl_display_update_func_t update, void *data)
421
{
422 423 424 425 426
	display->update = update;
	display->update_data = data;

	display->update(display->mask, display->update_data);

427
	return display->fd;
428 429
}

430 431
static void
sync_callback(void *data, struct wl_callback *callback, uint32_t time)
432
{
433
   int *done = data;
434

435 436
   *done = 1;
   wl_callback_destroy(callback);
437 438
}

439 440 441
static const struct wl_callback_listener sync_listener = {
	sync_callback
};
442

443 444 445 446 447 448 449 450 451 452 453 454
WL_EXPORT void
wl_display_roundtrip(struct wl_display *display)
{
	struct wl_callback *callback;
	int done;

	done = 0;
	callback = wl_display_sync(display);
	wl_callback_add_listener(callback, &sync_listener, &done);
	wl_display_flush(display);
	while (!done)
		wl_display_iterate(display, WL_DISPLAY_READABLE);
455 456
}

457
static void
458
handle_event(struct wl_display *display,
459
	     uint32_t id, uint32_t opcode, uint32_t size)
460
{
461
	struct wl_proxy *proxy;
462
	struct wl_closure *closure;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
463
	const struct wl_message *message;
464

465
	proxy = wl_map_lookup(&display->objects, id);
466

467 468 469 470
	if (proxy == WL_ZOMBIE_OBJECT) {
		wl_connection_consume(display->connection, size);
		return;
	} else if (proxy == NULL || proxy->object.implementation == NULL) {
471 472 473 474
		wl_connection_consume(display->connection, size);
		return;
	}

475
	message = &proxy->object.interface->events[opcode];
476
	closure = wl_connection_demarshal(display->connection,
477
					  size, &display->objects, message);
478

479
	if (closure == NULL) {
480
		fprintf(stderr, "Error demarshalling event\n");
481 482 483
		abort();
	}

484
	if (wl_debug)
485
		wl_closure_print(closure, &proxy->object, false);
486

487 488 489
	wl_closure_invoke(closure, &proxy->object,
			  proxy->object.implementation[opcode],
			  proxy->user_data);
490 491

	wl_closure_destroy(closure);
492 493
}

494
WL_EXPORT void
495
wl_display_iterate(struct wl_display *display, uint32_t mask)
496
{
497
	uint32_t p[2], object, opcode, size;
498 499
	int len;

500 501 502 503 504 505 506
	mask &= display->mask;
	if (mask == 0) {
		fprintf(stderr,
			"wl_display_iterate called with unsolicited flags");
		return;
	}

507
	len = wl_connection_data(display->connection, mask);
508

509
	while (len > 0) {
510
		if (len < sizeof p)
511 512
			break;
		
513
		wl_connection_copy(display->connection, p, sizeof p);
514
		object = p[0];
515 516
		opcode = p[1] & 0xffff;
		size = p[1] >> 16;
517
		if (len < size)
518 519
			break;

520
		handle_event(display, object, opcode, size);
521
		len -= size;
522 523 524 525 526 527 528 529
	}

	if (len < 0) {
		fprintf(stderr, "read error: %m\n");
		exit(EXIT_FAILURE);
	}
}

530 531 532 533 534 535 536
WL_EXPORT void
wl_display_flush(struct wl_display *display)
{
	while (display->mask & WL_DISPLAY_WRITABLE)
		wl_display_iterate (display, WL_DISPLAY_WRITABLE);
}

537
WL_EXPORT void *
538
wl_display_bind(struct wl_display *display,
539
		uint32_t name, const struct wl_interface *interface)
540
{
541 542 543 544 545 546 547 548 549 550
	struct wl_proxy *proxy;

	proxy = wl_proxy_create(&display->proxy, interface);
	if (proxy == NULL)
		return NULL;

	wl_proxy_marshal(&display->proxy, WL_DISPLAY_BIND,
			 name, interface->name, interface->version, proxy);

	return proxy;
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
}

WL_EXPORT struct wl_callback *
wl_display_sync(struct wl_display *display)
{
	struct wl_proxy *proxy;

	proxy = wl_proxy_create(&display->proxy, &wl_callback_interface);

	if (!proxy)
		return NULL;

	wl_proxy_marshal(&display->proxy, WL_DISPLAY_SYNC, proxy);

	return (struct wl_callback *) proxy;
}

568
WL_EXPORT void
569
wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data)
570
{
571
	proxy->user_data = user_data;
572 573 574
}

WL_EXPORT void *
575
wl_proxy_get_user_data(struct wl_proxy *proxy)
576
{
577
	return proxy->user_data;
578
}