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