blob: 2d7e226fd7e0d36120fc983edc7696ebdfa393a5 [file] [log] [blame]
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -04001#include <stdlib.h>
2#include <stdint.h>
3#include <stddef.h>
4#include <stdio.h>
5#include <errno.h>
6#include <string.h>
7#include <unistd.h>
8#include <sys/socket.h>
9#include <sys/un.h>
10#include <ffi.h>
11#include "wayland.h"
12
13#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
14
15struct wl_region {
16};
17
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040018struct wl_buffer {
19 char data[4096];
20 int head, tail;
21};
22
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040023struct wl_client {
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040024 struct wl_buffer input, output;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040025 struct wl_event_source *source;
26 struct wl_display *display;
27};
28
29struct wl_display {
30 struct wl_object base;
31 struct wl_event_loop *loop;
32 struct wl_hash objects;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040033
34 struct wl_compositor *compositor;
35 struct wl_compositor_interface *compositor_interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040036};
37
38struct wl_surface {
39 struct wl_object base;
40
41 /* provided by client */
42 int width, height;
43 int buffer;
44 int stride;
45
Kristian Høgsberg05eff512008-10-07 10:10:36 -040046 struct wl_map map;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040047
48 /* how to convert buffer contents to pixels in screen format;
49 * yuv->rgb, indexed->rgb, svg->rgb, but mostly just rgb->rgb. */
50
51 /* how to transform/render rectangular contents to polygons. */
Kristian Høgsberg05eff512008-10-07 10:10:36 -040052
53 void *compositor_data;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040054};
55
Kristian Høgsberg05eff512008-10-07 10:10:36 -040056
57static void
58wl_surface_destroy(struct wl_client *client,
59 struct wl_surface *surface)
60{
61 struct wl_compositor_interface *interface;
62
63 interface = client->display->compositor->interface;
64 interface->notify_surface_destroy(client->display->compositor, surface);
65}
66
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040067static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040068wl_surface_attach(struct wl_client *client,
69 struct wl_surface *surface, uint32_t name,
70 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040071{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040072 struct wl_compositor_interface *interface;
73
74 interface = client->display->compositor->interface;
75 interface->notify_surface_attach(client->display->compositor,
76 surface, name, width, height, stride);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040077}
78
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040079static const struct wl_argument attach_arguments[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040080 { WL_ARGUMENT_UINT32 },
81 { WL_ARGUMENT_UINT32 },
82 { WL_ARGUMENT_UINT32 },
83 { WL_ARGUMENT_UINT32 },
84};
85
86void
Kristian Høgsberg05eff512008-10-07 10:10:36 -040087wl_surface_map(struct wl_client *client, struct wl_surface *surface,
88 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040089{
Kristian Høgsberg05eff512008-10-07 10:10:36 -040090 struct wl_compositor_interface *interface;
91
92 /* FIXME: This needs to take a tri-mesh argument... - count
93 * and a list of tris. 0 tris means unmap. */
94
95 surface->map.x = x;
96 surface->map.y = y;
97 surface->map.width = width;
98 surface->map.height = height;
99
100 interface = client->display->compositor->interface;
101 interface->notify_surface_map(client->display->compositor,
102 surface, &surface->map);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400103}
104
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400105static const struct wl_argument map_arguments[] = {
106 { WL_ARGUMENT_UINT32 },
107 { WL_ARGUMENT_UINT32 },
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400108 { WL_ARGUMENT_UINT32 },
109 { WL_ARGUMENT_UINT32 },
110};
111
112static const struct wl_method surface_methods[] = {
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400113 { "destroy", wl_surface_destroy,
114 0, NULL },
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400115 { "attach", wl_surface_attach,
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400116 ARRAY_LENGTH(attach_arguments), attach_arguments },
117 { "map", wl_surface_map,
118 ARRAY_LENGTH(map_arguments), map_arguments }
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400119};
120
121static const struct wl_interface surface_interface = {
122 "surface", 1,
123 ARRAY_LENGTH(surface_methods),
124 surface_methods,
125};
126
127struct wl_surface *
128wl_surface_create(struct wl_display *display, uint32_t id)
129{
130 struct wl_surface *surface;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400131 struct wl_compositor_interface *interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400132
133 surface = malloc(sizeof *surface);
134 if (surface == NULL)
135 return NULL;
136
137 surface->base.id = id;
138 surface->base.interface = &surface_interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400139
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400140 interface = display->compositor->interface;
141 interface->notify_surface_create(display->compositor, surface);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400142
143 return surface;
144}
145
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400146void
147wl_surface_set_data(struct wl_surface *surface, void *data)
148{
149 surface->compositor_data = data;
150}
151
152void *
153wl_surface_get_data(struct wl_surface *surface)
154{
155 return surface->compositor_data;
156}
157
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400158static void
159wl_client_data(int fd, uint32_t mask, void *data);
160
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400161static int
162advertise_object(struct wl_client *client, struct wl_object *object)
163{
164 const struct wl_interface *interface;
165 uint32_t length, *p;
166
167 interface = object->interface;
168 p = (uint32_t *) (client->output.data + client->output.head);
169 length = strlen(interface->name);
170 *p++ = object->id;
171 *p++ = length;
172 memcpy(p, interface->name, length);
173 memset((char *) p + length, 0, -length & 3);
174 client->output.head += 8 + ((length + 3) & ~3);
175
176 wl_event_loop_update_source(client->display->loop, client->source,
177 WL_EVENT_READABLE | WL_EVENT_WRITEABLE);
178
179
180 return 0;
181}
182
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400183struct wl_client *
184wl_client_create(struct wl_display *display, int fd)
185{
186 struct wl_client *client;
187
188 client = malloc(sizeof *client);
189 if (client == NULL)
190 return NULL;
191
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400192 memset(client, 0, sizeof *client);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400193 client->display = display;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400194 client->source = wl_event_loop_add_fd(display->loop, fd,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400195 WL_EVENT_READABLE,
196 wl_client_data, client);
197
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400198 advertise_object(client, &display->base);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400199
200 return client;
201}
202
203void
204wl_client_destroy(struct wl_client *client)
205{
206 printf("disconnect from client %p\n", client);
207 wl_event_loop_remove_source(client->display->loop, client->source);
208 free(client);
209}
210
211static void
212demarshal(struct wl_client *client, struct wl_object *target,
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400213 const struct wl_method *method, uint32_t *data)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400214{
215 ffi_type *types[10];
216 ffi_cif cif;
217 uint32_t *p, result;
218 int i;
219 union {
220 uint32_t uint32;
221 const char *string;
222 void *object;
223 uint32_t new_id;
224 } values[10];
225 void *args[10];
226 struct wl_object *object;
227
228 if (method->argument_count > ARRAY_LENGTH(types)) {
229 printf("too many args (%d)\n", method->argument_count);
230 return;
231 }
232
233 types[0] = &ffi_type_pointer;
234 values[0].object = client;
235 args[0] = &values[0];
236
237 types[1] = &ffi_type_pointer;
238 values[1].object = target;
239 args[1] = &values[1];
240
241 p = data;
242 for (i = 0; i < method->argument_count; i++) {
243 switch (method->arguments[i].type) {
244 case WL_ARGUMENT_UINT32:
245 types[i + 2] = &ffi_type_uint32;
246 values[i + 2].uint32 = *p;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400247 p++;
248 break;
249 case WL_ARGUMENT_STRING:
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400250 types[i + 2] = &ffi_type_pointer;
251 /* FIXME */
252 values[i + 2].uint32 = *p++;
253 break;
254 case WL_ARGUMENT_OBJECT:
255 types[i + 2] = &ffi_type_pointer;
256 object = wl_hash_lookup(&client->display->objects, *p);
257 if (object == NULL)
258 printf("unknown object (%d)\n", *p);
259 if (object->interface != method->arguments[i].data)
260 printf("wrong object type\n");
261 values[i + 2].object = object;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400262 p++;
263 break;
264 case WL_ARGUMENT_NEW_ID:
265 types[i + 2] = &ffi_type_uint32;
266 values[i + 2].new_id = *p;
267 object = wl_hash_lookup(&client->display->objects, *p);
268 if (object != NULL)
269 printf("object already exists (%d)\n", *p);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400270 p++;
271 break;
272 default:
273 printf("unknown type\n");
274 break;
275 }
276 args[i + 2] = &values[i + 2];
277 }
278
279 ffi_prep_cif(&cif, FFI_DEFAULT_ABI, method->argument_count + 2,
280 &ffi_type_uint32, types);
281 ffi_call(&cif, FFI_FN(method->func), &result, args);
282}
283
284static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400285wl_client_event(struct wl_client *client, struct wl_object *object, uint32_t event)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400286{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400287 const struct wl_interface *interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400288 uint32_t *p;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400289
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400290 interface = object->interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400291
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400292 p = (void *) client->output.data + client->output.head;
293 p[0] = object->id;
294 p[1] = event | (8 << 16);
295 client->output.head += 8;
296 wl_event_loop_update_source(client->display->loop, client->source,
297 WL_EVENT_READABLE | WL_EVENT_WRITEABLE);
298}
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400299
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400300#define WL_DISPLAY_INVALID_OBJECT 0
301#define WL_DISPLAY_INVALID_METHOD 1
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400302
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400303static void
304wl_client_process_input(struct wl_client *client)
305{
306 const struct wl_method *method;
307 struct wl_object *object;
308 uint32_t *p, opcode, size;
309
310 while (1) {
311 if (client->input.head - client->input.tail < 2 * sizeof *p)
312 break;
313
314 p = (uint32_t *) (client->input.data + client->input.tail);
315 opcode = p[1] & 0xffff;
316 size = p[1] >> 16;
317 if (client->input.head - client->input.tail < size)
318 break;
319
320 object = wl_hash_lookup(&client->display->objects,
321 p[0]);
322 if (object == NULL) {
323 wl_client_event(client, &client->display->base,
324 WL_DISPLAY_INVALID_OBJECT);
325 client->input.tail += size;
326 continue;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400327 }
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400328
329 if (opcode >= object->interface->method_count) {
330 wl_client_event(client, &client->display->base,
331 WL_DISPLAY_INVALID_METHOD);
332 client->input.tail += size;
333 continue;
334 }
335
336 method = &object->interface->methods[opcode];
337 demarshal(client, object, method, p + 2);
338 client->input.tail += size;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400339 }
340}
341
342static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400343wl_client_data(int fd, uint32_t mask, void *data)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400344{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400345 struct wl_client *client = data;
346 int len;
347
348 if (mask & WL_EVENT_READABLE) {
349 len = read(fd, client->input.data, sizeof client->input.data);
350 if (len > 0) {
351 client->input.head += len;
352 wl_client_process_input(client);
353 } else if (len == 0 && errno == ECONNRESET) {
354 fprintf(stderr,
355 "read from client %p: %m (%d)\n",
356 client, errno);
357 } else {
358 wl_client_destroy(client);
359 }
360 }
361
362 if (mask & WL_EVENT_WRITEABLE) {
363 len = write(fd, client->output.data + client->output.tail,
364 client->output.head - client->output.tail);
365 client->output.tail += len;
366
367 if (client->output.tail == client->output.head)
368 wl_event_loop_update_source(client->display->loop,
369 client->source,
370 WL_EVENT_READABLE);
371 }
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400372}
373
374static int
375wl_display_create_surface(struct wl_client *client,
376 struct wl_display *display, uint32_t id)
377{
378 struct wl_surface *surface;
379
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400380 surface = wl_surface_create(display, id);
381 wl_hash_insert(&display->objects, &surface->base);
382
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400383 /* FIXME: garbage collect client resources when client exits. */
384
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400385 return 0;
386}
387
388static const struct wl_argument create_surface_arguments[] = {
389 { WL_ARGUMENT_NEW_ID }
390};
391
392static const struct wl_method display_methods[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400393 { "create_surface", wl_display_create_surface,
394 ARRAY_LENGTH(create_surface_arguments), create_surface_arguments },
395};
396
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400397static const struct wl_event display_events[] = {
398 { "invalid_object" },
399 { "invalid_method" },
400};
401
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400402static const struct wl_interface display_interface = {
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400403 "display", 1,
404 ARRAY_LENGTH(display_methods), display_methods,
405 ARRAY_LENGTH(display_events), display_events,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400406};
407
408struct wl_display *
409wl_display_create(void)
410{
411 struct wl_display *display;
412
413 display = malloc(sizeof *display);
414 if (display == NULL)
415 return NULL;
416
417 display->loop = wl_event_loop_create();
418 if (display->loop == NULL) {
419 free(display);
420 return NULL;
421 }
422
423 display->base.id = 0;
424 display->base.interface = &display_interface;
425 wl_hash_insert(&display->objects, &display->base);
426
427 return display;
428}
429
430void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400431wl_display_set_compositor(struct wl_display *display,
432 struct wl_compositor *compositor)
433{
434 display->compositor = compositor;
435}
436
437void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400438wl_display_run(struct wl_display *display)
439{
440 while (1)
441 wl_event_loop_wait(display->loop);
442}
443
444/* The plan here is to generate a random anonymous socket name and
445 * advertise that through a service on the session dbus.
446 */
447static const char socket_name[] = "\0wayland";
448
449static void
450socket_data(int fd, uint32_t mask, void *data)
451{
452 struct wl_display *display = data;
453 struct sockaddr_un name;
454 socklen_t length;
455 int client_fd;
456
457 length = sizeof name;
458 client_fd = accept (fd, (struct sockaddr *) &name, &length);
459 if (client_fd < 0)
460 fprintf(stderr, "failed to accept\n");
461
462 wl_client_create(display, client_fd);
463}
464
465int
466wl_display_add_socket(struct wl_display *display)
467{
468 struct sockaddr_un name;
469 int sock;
470 socklen_t size;
471
472 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
473 if (sock < 0)
474 return -1;
475
476 name.sun_family = AF_LOCAL;
477 memcpy(name.sun_path, socket_name, sizeof socket_name);
478
479 size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
480 if (bind(sock, (struct sockaddr *) &name, size) < 0)
481 return -1;
482
483 if (listen(sock, 1) < 0)
484 return -1;
485
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400486 wl_event_loop_add_fd(display->loop, sock,
487 WL_EVENT_READABLE,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400488 socket_data, display);
489
490 return 0;
491}
492
493
494int main(int argc, char *argv[])
495{
496 struct wl_display *display;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400497 struct wl_compositor *compositor;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400498
499 display = wl_display_create();
500
501 if (wl_display_add_socket(display)) {
502 fprintf(stderr, "failed to add socket: %m\n");
503 exit(EXIT_FAILURE);
504 }
505
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400506 compositor = wl_compositor_create();
507 wl_display_set_compositor(display, compositor);
508
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400509 printf("wayland online, display is %p\n", display);
510
511 wl_display_run(display);
512
513 return 0;
514}