2 * Copyright © 2008 Kristian Høgsberg
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
31 #include <sys/socket.h>
37 #include "wayland-server.h"
38 #include "wayland-server-protocol.h"
39 #include "connection.h"
42 struct wl_connection *connection;
43 struct wl_event_source *source;
44 struct wl_display *display;
45 struct wl_list resource_list;
50 struct wl_object base;
51 struct wl_event_loop *loop;
52 struct wl_hash_table *objects;
54 struct wl_list frame_list;
55 uint32_t client_id_range;
58 struct wl_list global_list;
61 struct wl_frame_listener {
62 struct wl_resource resource;
63 struct wl_client *client;
69 struct wl_object *object;
70 wl_client_connect_func_t func;
74 WL_EXPORT struct wl_surface wl_grab_surface;
77 wl_client_post_event(struct wl_client *client, struct wl_object *sender,
83 wl_connection_vmarshal(client->connection,
85 &sender->interface->events[opcode]);
90 wl_client_connection_data(int fd, uint32_t mask, void *data)
92 struct wl_client *client = data;
93 struct wl_connection *connection = client->connection;
94 struct wl_object *object;
95 struct wl_closure *closure;
96 const struct wl_message *message;
97 uint32_t p[2], opcode, size;
101 if (mask & WL_EVENT_READABLE)
102 cmask |= WL_CONNECTION_READABLE;
103 if (mask & WL_EVENT_WRITEABLE)
104 cmask |= WL_CONNECTION_WRITABLE;
106 len = wl_connection_data(connection, cmask);
108 wl_client_destroy(client);
112 while (len >= sizeof p) {
113 wl_connection_copy(connection, p, sizeof p);
114 opcode = p[1] & 0xffff;
119 object = wl_hash_table_lookup(client->display->objects, p[0]);
120 if (object == NULL) {
121 wl_client_post_event(client, &client->display->base,
122 WL_DISPLAY_INVALID_OBJECT, p[0]);
123 wl_connection_consume(connection, size);
128 if (opcode >= object->interface->method_count) {
129 wl_client_post_event(client, &client->display->base,
130 WL_DISPLAY_INVALID_METHOD, p[0], opcode);
131 wl_connection_consume(connection, size);
136 message = &object->interface->methods[opcode];
137 closure = wl_connection_demarshal(client->connection, size,
138 client->display->objects,
142 if (closure == NULL && errno == EINVAL) {
143 wl_client_post_event(client, &client->display->base,
144 WL_DISPLAY_INVALID_METHOD,
147 } else if (closure == NULL && errno == ENOMEM) {
148 wl_client_post_no_memory(client);
152 wl_closure_invoke(closure, object,
153 object->implementation[opcode], client);
155 wl_closure_destroy(closure);
161 wl_client_connection_update(struct wl_connection *connection,
162 uint32_t mask, void *data)
164 struct wl_client *client = data;
167 if (mask & WL_CONNECTION_READABLE)
168 emask |= WL_EVENT_READABLE;
169 if (mask & WL_CONNECTION_WRITABLE)
170 emask |= WL_EVENT_WRITEABLE;
172 return wl_event_source_fd_update(client->source, mask);
175 WL_EXPORT struct wl_display *
176 wl_client_get_display(struct wl_client *client)
178 return client->display;
182 wl_display_post_range(struct wl_display *display, struct wl_client *client)
184 wl_client_post_event(client, &client->display->base,
185 WL_DISPLAY_RANGE, display->client_id_range);
186 display->client_id_range += 256;
187 client->id_count += 256;
190 static struct wl_client *
191 wl_client_create(struct wl_display *display, int fd)
193 struct wl_client *client;
194 struct wl_global *global;
196 client = malloc(sizeof *client);
200 memset(client, 0, sizeof *client);
201 client->display = display;
202 client->source = wl_event_loop_add_fd(display->loop, fd,
204 wl_client_connection_data, client);
206 wl_connection_create(fd, wl_client_connection_update, client);
208 wl_list_init(&client->resource_list);
210 wl_display_post_range(display, client);
212 wl_list_for_each(global, &display->global_list, link)
213 wl_client_post_event(client, &client->display->base,
216 global->object->interface->name,
217 global->object->interface->version);
219 wl_list_for_each(global, &display->global_list, link)
221 global->func(client, global->object);
227 wl_client_add_resource(struct wl_client *client,
228 struct wl_resource *resource)
230 struct wl_display *display = client->display;
232 if (client->id_count-- < 64)
233 wl_display_post_range(display, client);
235 wl_hash_table_insert(client->display->objects,
236 resource->base.id, resource);
237 wl_list_insert(client->resource_list.prev, &resource->link);
241 wl_client_post_no_memory(struct wl_client *client)
243 wl_client_post_event(client,
244 &client->display->base,
245 WL_DISPLAY_NO_MEMORY);
249 wl_client_post_global(struct wl_client *client, struct wl_object *object)
251 wl_client_post_event(client,
252 &client->display->base,
255 object->interface->name,
256 object->interface->version);
260 wl_resource_destroy(struct wl_resource *resource, struct wl_client *client)
262 struct wl_display *display = client->display;
264 wl_list_remove(&resource->link);
265 if (resource->base.id > 0)
266 wl_hash_table_remove(display->objects, resource->base.id);
267 resource->destroy(resource, client);
271 wl_client_destroy(struct wl_client *client)
273 struct wl_resource *resource, *tmp;
275 printf("disconnect from client %p\n", client);
277 wl_list_for_each_safe(resource, tmp, &client->resource_list, link)
278 wl_resource_destroy(resource, client);
280 wl_event_source_remove(client->source);
281 wl_connection_destroy(client->connection);
286 wl_display_set_compositor(struct wl_display *display,
287 struct wl_compositor *compositor,
288 const struct wl_compositor_interface *implementation)
290 compositor->base.interface = &wl_compositor_interface;
291 compositor->base.implementation = (void (**)(void)) implementation;
293 wl_display_add_object(display, &compositor->base);
294 if (wl_display_add_global(display, &compositor->base, NULL))
301 display_sync(struct wl_client *client,
302 struct wl_display *display, uint32_t key)
304 wl_client_post_event(client, &display->base, WL_DISPLAY_SYNC, key);
308 destroy_frame_listener(struct wl_resource *resource, struct wl_client *client)
310 struct wl_frame_listener *listener =
311 container_of(resource, struct wl_frame_listener, resource);
313 wl_list_remove(&listener->link);
318 display_frame(struct wl_client *client,
319 struct wl_display *display, uint32_t key)
321 struct wl_frame_listener *listener;
323 listener = malloc(sizeof *listener);
324 if (listener == NULL) {
325 wl_client_post_no_memory(client);
329 /* The listener is a resource so we destroy it when the client
331 listener->resource.destroy = destroy_frame_listener;
332 listener->resource.base.id = 0;
333 listener->client = client;
335 wl_list_insert(client->resource_list.prev, &listener->resource.link);
336 wl_list_insert(display->frame_list.prev, &listener->link);
339 struct wl_display_interface display_interface = {
345 WL_EXPORT struct wl_display *
346 wl_display_create(void)
348 struct wl_display *display;
350 display = malloc(sizeof *display);
354 display->loop = wl_event_loop_create();
355 if (display->loop == NULL) {
360 display->objects = wl_hash_table_create();
361 if (display->objects == NULL) {
366 wl_list_init(&display->frame_list);
367 wl_list_init(&display->global_list);
369 display->client_id_range = 256; /* Gah, arbitrary... */
372 display->base.interface = &wl_display_interface;
373 display->base.implementation = (void (**)(void)) &display_interface;
374 wl_display_add_object(display, &display->base);
375 if (wl_display_add_global(display, &display->base, NULL)) {
376 wl_event_loop_destroy(display->loop);
385 wl_display_add_object(struct wl_display *display, struct wl_object *object)
387 object->id = display->id++;
388 wl_hash_table_insert(display->objects, object->id, object);
392 wl_display_add_global(struct wl_display *display,
393 struct wl_object *object, wl_client_connect_func_t func)
395 struct wl_global *global;
397 global = malloc(sizeof *global);
401 global->object = object;
403 wl_list_insert(display->global_list.prev, &global->link);
409 wl_surface_post_event(struct wl_surface *surface,
410 struct wl_object *sender,
415 if (surface == &wl_grab_surface)
419 wl_connection_vmarshal(surface->client->connection,
421 &sender->interface->events[event]);
426 wl_display_post_frame(struct wl_display *display, uint32_t time)
428 struct wl_frame_listener *listener, *next;
430 wl_list_for_each_safe(listener, next, &display->frame_list, link) {
431 wl_client_post_event(listener->client, &display->base,
432 WL_DISPLAY_FRAME, listener->key, time);
433 wl_resource_destroy(&listener->resource, listener->client);
437 WL_EXPORT struct wl_event_loop *
438 wl_display_get_event_loop(struct wl_display *display)
440 return display->loop;
444 wl_display_run(struct wl_display *display)
447 wl_event_loop_wait(display->loop);
451 socket_data(int fd, uint32_t mask, void *data)
453 struct wl_display *display = data;
454 struct sockaddr_un name;
458 length = sizeof name;
459 client_fd = accept (fd, (struct sockaddr *) &name, &length);
461 fprintf(stderr, "failed to accept\n");
463 wl_client_create(display, client_fd);
467 wl_display_add_socket(struct wl_display *display,
468 const char *name, size_t name_size)
470 struct sockaddr_un addr;
474 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
478 addr.sun_family = AF_LOCAL;
479 memcpy(addr.sun_path, name, name_size);
481 size = offsetof (struct sockaddr_un, sun_path) + name_size;
482 if (bind(sock, (struct sockaddr *) &addr, size) < 0)
485 if (listen(sock, 1) < 0)
488 wl_event_loop_add_fd(display->loop, sock,
490 socket_data, display);