Drop libdrm CFLAGS where no longer necessary.
[profile/ivi/wayland.git] / wayland.c
1 /*
2  * Copyright © 2008 Kristian Høgsberg
3  *
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.
13  *
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
20  * OF THIS SOFTWARE.
21  */
22
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <dlfcn.h>
34 #include <assert.h>
35 #include <ffi.h>
36
37 #include "wayland-protocol.h"
38 #include "wayland.h"
39 #include "connection.h"
40
41 struct wl_client {
42         struct wl_connection *connection;
43         struct wl_event_source *source;
44         struct wl_display *display;
45         struct wl_list object_list;
46         struct wl_list link;
47         uint32_t id_count;
48 };
49
50 struct wl_display {
51         struct wl_object base;
52         struct wl_event_loop *loop;
53         struct wl_hash *objects;
54
55         struct wl_list pending_frame_list;
56         uint32_t client_id_range;
57         uint32_t id;
58
59         struct wl_list global_list;
60 };
61
62 struct wl_object_ref {
63         struct wl_object *object;
64         struct wl_list link;
65 };
66
67 struct wl_global {
68         struct wl_object *object;
69         wl_client_connect_func_t func;  
70         struct wl_list link;
71 };
72
73 void
74 wl_client_destroy(struct wl_client *client);
75
76 WL_EXPORT void
77 wl_client_post_event(struct wl_client *client, struct wl_object *sender,
78                      uint32_t opcode, ...)
79 {
80         va_list ap;
81
82         va_start(ap, opcode);
83         wl_connection_vmarshal(client->connection,
84                                sender, opcode, ap,
85                                &sender->interface->events[opcode]);
86         va_end(ap);
87 }
88
89 static void
90 wl_client_connection_data(int fd, uint32_t mask, void *data)
91 {
92         struct wl_client *client = data;
93         struct wl_connection *connection = client->connection;
94         struct wl_object *object;
95         uint32_t p[2], opcode, size;
96         uint32_t cmask = 0;
97         int len;
98
99         if (mask & WL_EVENT_READABLE)
100                 cmask |= WL_CONNECTION_READABLE;
101         if (mask & WL_EVENT_WRITEABLE)
102                 cmask |= WL_CONNECTION_WRITABLE;
103
104         len = wl_connection_data(connection, cmask);
105         if (len < 0) {
106                 wl_client_destroy(client);
107                 return;
108         }
109
110         while (len >= sizeof p) {
111                 wl_connection_copy(connection, p, sizeof p);
112                 opcode = p[1] & 0xffff;
113                 size = p[1] >> 16;
114                 if (len < size)
115                         break;
116
117                 object = wl_hash_lookup(client->display->objects, p[0]);
118                 if (object == NULL) {
119                         wl_client_post_event(client, &client->display->base,
120                                              WL_DISPLAY_INVALID_OBJECT, p[0]);
121                         wl_connection_consume(connection, size);
122                         len -= size;
123                         continue;
124                 }
125                                 
126                 if (opcode >= object->interface->method_count) {
127                         wl_client_post_event(client, &client->display->base,
128                                              WL_DISPLAY_INVALID_METHOD, p[0], opcode);
129                         wl_connection_consume(connection, size);
130                         len -= size;
131                         continue;
132                 }
133                                 
134                 wl_connection_demarshal(client->connection,
135                                         size,
136                                         client->display->objects,
137                                         object->implementation[opcode],
138                                         client,
139                                         object, 
140                                         &object->interface->methods[opcode]);
141
142                 wl_connection_consume(connection, size);
143                 len -= size;
144         }
145 }
146
147 static int
148 wl_client_connection_update(struct wl_connection *connection,
149                             uint32_t mask, void *data)
150 {
151         struct wl_client *client = data;
152         uint32_t emask = 0;
153
154         if (mask & WL_CONNECTION_READABLE)
155                 emask |= WL_EVENT_READABLE;
156         if (mask & WL_CONNECTION_WRITABLE)
157                 emask |= WL_EVENT_WRITEABLE;
158
159         return wl_event_source_fd_update(client->source, mask);
160 }
161
162 static void
163 wl_display_post_range(struct wl_display *display, struct wl_client *client)
164 {
165         wl_client_post_event(client, &client->display->base,
166                              WL_DISPLAY_RANGE, display->client_id_range);
167         display->client_id_range += 256;
168         client->id_count += 256;
169 }
170
171 static struct wl_client *
172 wl_client_create(struct wl_display *display, int fd)
173 {
174         struct wl_client *client;
175         struct wl_global *global;
176
177         client = malloc(sizeof *client);
178         if (client == NULL)
179                 return NULL;
180
181         memset(client, 0, sizeof *client);
182         client->display = display;
183         client->source = wl_event_loop_add_fd(display->loop, fd,
184                                               WL_EVENT_READABLE,
185                                               wl_client_connection_data, client);
186         client->connection =
187                 wl_connection_create(fd, wl_client_connection_update, client);
188
189         wl_list_init(&client->object_list);
190         wl_list_init(&client->link);
191
192         wl_display_post_range(display, client);
193
194         global = container_of(display->global_list.next,
195                               struct wl_global, link);
196         while (&global->link != &display->global_list) {
197                 wl_client_post_event(client, &client->display->base,
198                                      WL_DISPLAY_GLOBAL,
199                                      global->object,
200                                      global->object->interface->name,
201                                      global->object->interface->version);
202                 global = container_of(global->link.next,
203                                       struct wl_global, link);
204         }
205
206         global = container_of(display->global_list.next,
207                               struct wl_global, link);
208         while (&global->link != &display->global_list) {
209                 if (global->func)
210                         global->func(client, global->object);
211                 global = container_of(global->link.next,
212                                       struct wl_global, link);
213         }
214
215         return client;
216 }
217
218 static void
219 wl_object_destroy(struct wl_object *object)
220 {
221         const struct wl_surface_interface *interface =
222                 (const struct wl_surface_interface *) object->implementation;
223
224         /* FIXME: Need generic object destructor. */
225         interface->destroy(NULL, (struct wl_surface *) object);
226 }
227
228 void
229 wl_client_destroy(struct wl_client *client)
230 {
231         struct wl_object_ref *ref;
232
233         printf("disconnect from client %p\n", client);
234
235         wl_list_remove(&client->link);
236
237         while (client->object_list.next != &client->object_list) {
238                 ref = container_of(client->object_list.next,
239                                    struct wl_object_ref, link);
240                 wl_list_remove(&ref->link);
241                 wl_object_destroy(ref->object);
242                 free(ref);
243         }
244
245         wl_event_source_remove(client->source);
246         wl_connection_destroy(client->connection);
247         free(client);
248 }
249
250 WL_EXPORT int
251 wl_client_add_surface(struct wl_client *client,
252                       struct wl_surface *surface,
253                       const struct wl_surface_interface *implementation, 
254                       uint32_t id)
255 {
256         struct wl_display *display = client->display;
257         struct wl_object_ref *ref;
258
259         if (client->id_count-- < 64)
260                 wl_display_post_range(display, client);
261
262         surface->base.id = id;
263         surface->base.interface = &wl_surface_interface;
264         surface->base.implementation = (void (**)(void)) implementation;
265         surface->client = client;
266
267         ref = malloc(sizeof *ref);
268         if (ref == NULL) {
269                 wl_client_post_event(client, &display->base,
270                                      WL_DISPLAY_NO_MEMORY);
271                 return -1;
272         }
273
274         ref->object = &surface->base;
275         wl_hash_insert(display->objects, &surface->base);
276         wl_list_insert(client->object_list.prev, &ref->link);
277
278         return 0;
279 }
280
281 WL_EXPORT void
282 wl_client_send_acknowledge(struct wl_client *client,
283                            struct wl_compositor *compositor,
284                            uint32_t key, uint32_t frame)
285 {
286         wl_list_remove(&client->link);
287         wl_list_insert(client->display->pending_frame_list.prev,
288                        &client->link);
289         wl_client_post_event(client, &compositor->base,
290                              WL_COMPOSITOR_ACKNOWLEDGE, key, frame);
291 }
292
293 WL_EXPORT int
294 wl_display_set_compositor(struct wl_display *display,
295                           struct wl_compositor *compositor,
296                           const struct wl_compositor_interface *implementation)
297 {
298         compositor->base.interface = &wl_compositor_interface;
299         compositor->base.implementation = (void (**)(void)) implementation;
300
301         wl_display_add_object(display, &compositor->base);
302         if (wl_display_add_global(display, &compositor->base, NULL))
303                 return -1;
304
305         return 0;
306 }
307
308 WL_EXPORT struct wl_display *
309 wl_display_create(void)
310 {
311         struct wl_display *display;
312
313         display = malloc(sizeof *display);
314         if (display == NULL)
315                 return NULL;
316
317         display->loop = wl_event_loop_create();
318         if (display->loop == NULL) {
319                 free(display);
320                 return NULL;
321         }
322
323         display->objects = wl_hash_create();
324         if (display->objects == NULL) {
325                 free(display);
326                 return NULL;
327         }
328
329         wl_list_init(&display->pending_frame_list);
330         wl_list_init(&display->global_list);
331
332         display->client_id_range = 256; /* Gah, arbitrary... */
333
334         display->id = 1;
335         display->base.interface = &wl_display_interface;
336         display->base.implementation = NULL;
337         wl_display_add_object(display, &display->base);
338         if (wl_display_add_global(display, &display->base, NULL)) {
339                 wl_event_loop_destroy(display->loop);
340                 free(display);
341                 return NULL;
342         }               
343
344         return display;         
345 }
346
347 WL_EXPORT void
348 wl_display_add_object(struct wl_display *display, struct wl_object *object)
349 {
350         object->id = display->id++;
351         wl_hash_insert(display->objects, object);
352 }
353
354 WL_EXPORT int
355 wl_display_add_global(struct wl_display *display,
356                       struct wl_object *object, wl_client_connect_func_t func)
357 {
358         struct wl_global *global;
359
360         global = malloc(sizeof *global);
361         if (global == NULL)
362                 return -1;
363
364         global->object = object;
365         global->func = func;
366         wl_list_insert(display->global_list.prev, &global->link);
367
368         return 0;       
369 }
370
371 WL_EXPORT void
372 wl_surface_post_event(struct wl_surface *surface,
373                       struct wl_object *sender,
374                       uint32_t event, ...)
375 {
376         va_list ap;
377
378         va_start(ap, event);
379         wl_connection_vmarshal(surface->client->connection,
380                                sender, event, ap,
381                                &sender->interface->events[event]);
382         va_end(ap);
383 }
384
385 WL_EXPORT void
386 wl_display_post_frame(struct wl_display *display,
387                       struct wl_compositor *compositor,
388                       uint32_t frame, uint32_t msecs)
389 {
390         struct wl_client *client;
391
392         client = container_of(display->pending_frame_list.next,
393                               struct wl_client, link);
394
395         while (&client->link != &display->pending_frame_list) {
396                 wl_client_post_event(client, &compositor->base,
397                                      WL_COMPOSITOR_FRAME, frame, msecs);
398                 client = container_of(client->link.next,
399                                       struct wl_client, link);
400         }
401
402         wl_list_remove(&display->pending_frame_list);
403         wl_list_init(&display->pending_frame_list);
404 }
405
406 WL_EXPORT struct wl_event_loop *
407 wl_display_get_event_loop(struct wl_display *display)
408 {
409         return display->loop;
410 }
411
412 WL_EXPORT void
413 wl_display_run(struct wl_display *display)
414 {
415         while (1)
416                 wl_event_loop_wait(display->loop);
417 }
418
419 static void
420 socket_data(int fd, uint32_t mask, void *data)
421 {
422         struct wl_display *display = data;
423         struct sockaddr_un name;
424         socklen_t length;
425         int client_fd;
426
427         length = sizeof name;
428         client_fd = accept (fd, (struct sockaddr *) &name, &length);
429         if (client_fd < 0)
430                 fprintf(stderr, "failed to accept\n");
431
432         wl_client_create(display, client_fd);
433 }
434
435 WL_EXPORT int
436 wl_display_add_socket(struct wl_display *display,
437                       const char *name, size_t name_size)
438 {
439         struct sockaddr_un addr;
440         int sock;
441         socklen_t size;
442
443         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
444         if (sock < 0)
445                 return -1;
446
447         addr.sun_family = AF_LOCAL;
448         memcpy(addr.sun_path, name, name_size);
449
450         size = offsetof (struct sockaddr_un, sun_path) + name_size;
451         if (bind(sock, (struct sockaddr *) &addr, size) < 0)
452                 return -1;
453
454         if (listen(sock, 1) < 0)
455                 return -1;
456
457         wl_event_loop_add_fd(display->loop, sock,
458                              WL_EVENT_READABLE,
459                              socket_data, display);
460
461         return 0;
462 }