blob: a9eaf4974067f4eab2289ca69c1045d7e665dbc3 [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
46 /* these are used by the wayland server, not set from client */
47 void (*screen_to_surface)(int sx, int sy, int *wx, int *wy);
48 void (*surface_to_screen)(int sx, int sy, int *wx, int *wy);
49
50 /* how to convert buffer contents to pixels in screen format;
51 * yuv->rgb, indexed->rgb, svg->rgb, but mostly just rgb->rgb. */
52
53 /* how to transform/render rectangular contents to polygons. */
54};
55
56static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040057wl_surface_attach(struct wl_client *client,
58 struct wl_surface *surface, uint32_t name,
59 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040060{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040061 struct wl_compositor_interface *interface;
62
63 interface = client->display->compositor->interface;
64 interface->notify_surface_attach(client->display->compositor,
65 surface, name, width, height, stride);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040066}
67
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040068static const struct wl_argument attach_arguments[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040069 { WL_ARGUMENT_UINT32 },
70 { WL_ARGUMENT_UINT32 },
71 { WL_ARGUMENT_UINT32 },
72 { WL_ARGUMENT_UINT32 },
73};
74
75void
76wl_surface_update(struct wl_surface *surface,
77 uint32_t source_name, struct wl_region *region)
78{
79 /* FIXME: how to demarshal region? */
80 /* copy region from buffer into current window contents. */
81}
82
83static const struct wl_argument update_arguments[] = {
84 { WL_ARGUMENT_UINT32 },
85 { WL_ARGUMENT_UINT32 },
86};
87
88static const struct wl_method surface_methods[] = {
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040089 { "attach", wl_surface_attach,
90 ARRAY_LENGTH(attach_arguments), attach_arguments }
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040091};
92
93static const struct wl_interface surface_interface = {
94 "surface", 1,
95 ARRAY_LENGTH(surface_methods),
96 surface_methods,
97};
98
99struct wl_surface *
100wl_surface_create(struct wl_display *display, uint32_t id)
101{
102 struct wl_surface *surface;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400103 struct wl_compositor_interface *interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400104
105 surface = malloc(sizeof *surface);
106 if (surface == NULL)
107 return NULL;
108
109 surface->base.id = id;
110 surface->base.interface = &surface_interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400111
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400112 interface = display->compositor->interface;
113 interface->notify_surface_create(display->compositor, surface);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400114
115 return surface;
116}
117
118static void
119wl_client_data(int fd, uint32_t mask, void *data);
120
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400121static int
122advertise_object(struct wl_client *client, struct wl_object *object)
123{
124 const struct wl_interface *interface;
125 uint32_t length, *p;
126
127 interface = object->interface;
128 p = (uint32_t *) (client->output.data + client->output.head);
129 length = strlen(interface->name);
130 *p++ = object->id;
131 *p++ = length;
132 memcpy(p, interface->name, length);
133 memset((char *) p + length, 0, -length & 3);
134 client->output.head += 8 + ((length + 3) & ~3);
135
136 wl_event_loop_update_source(client->display->loop, client->source,
137 WL_EVENT_READABLE | WL_EVENT_WRITEABLE);
138
139
140 return 0;
141}
142
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400143struct wl_client *
144wl_client_create(struct wl_display *display, int fd)
145{
146 struct wl_client *client;
147
148 client = malloc(sizeof *client);
149 if (client == NULL)
150 return NULL;
151
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400152 memset(client, 0, sizeof *client);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400153 client->display = display;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400154 client->source = wl_event_loop_add_fd(display->loop, fd,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400155 WL_EVENT_READABLE,
156 wl_client_data, client);
157
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400158 advertise_object(client, &display->base);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400159
160 return client;
161}
162
163void
164wl_client_destroy(struct wl_client *client)
165{
166 printf("disconnect from client %p\n", client);
167 wl_event_loop_remove_source(client->display->loop, client->source);
168 free(client);
169}
170
171static void
172demarshal(struct wl_client *client, struct wl_object *target,
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400173 const struct wl_method *method, uint32_t *data)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400174{
175 ffi_type *types[10];
176 ffi_cif cif;
177 uint32_t *p, result;
178 int i;
179 union {
180 uint32_t uint32;
181 const char *string;
182 void *object;
183 uint32_t new_id;
184 } values[10];
185 void *args[10];
186 struct wl_object *object;
187
188 if (method->argument_count > ARRAY_LENGTH(types)) {
189 printf("too many args (%d)\n", method->argument_count);
190 return;
191 }
192
193 types[0] = &ffi_type_pointer;
194 values[0].object = client;
195 args[0] = &values[0];
196
197 types[1] = &ffi_type_pointer;
198 values[1].object = target;
199 args[1] = &values[1];
200
201 p = data;
202 for (i = 0; i < method->argument_count; i++) {
203 switch (method->arguments[i].type) {
204 case WL_ARGUMENT_UINT32:
205 types[i + 2] = &ffi_type_uint32;
206 values[i + 2].uint32 = *p;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400207 p++;
208 break;
209 case WL_ARGUMENT_STRING:
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400210 types[i + 2] = &ffi_type_pointer;
211 /* FIXME */
212 values[i + 2].uint32 = *p++;
213 break;
214 case WL_ARGUMENT_OBJECT:
215 types[i + 2] = &ffi_type_pointer;
216 object = wl_hash_lookup(&client->display->objects, *p);
217 if (object == NULL)
218 printf("unknown object (%d)\n", *p);
219 if (object->interface != method->arguments[i].data)
220 printf("wrong object type\n");
221 values[i + 2].object = object;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400222 p++;
223 break;
224 case WL_ARGUMENT_NEW_ID:
225 types[i + 2] = &ffi_type_uint32;
226 values[i + 2].new_id = *p;
227 object = wl_hash_lookup(&client->display->objects, *p);
228 if (object != NULL)
229 printf("object already exists (%d)\n", *p);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400230 p++;
231 break;
232 default:
233 printf("unknown type\n");
234 break;
235 }
236 args[i + 2] = &values[i + 2];
237 }
238
239 ffi_prep_cif(&cif, FFI_DEFAULT_ABI, method->argument_count + 2,
240 &ffi_type_uint32, types);
241 ffi_call(&cif, FFI_FN(method->func), &result, args);
242}
243
244static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400245wl_client_event(struct wl_client *client, struct wl_object *object, uint32_t event)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400246{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400247 const struct wl_interface *interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400248 uint32_t *p;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400249
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400250 interface = object->interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400251
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400252 p = (void *) client->output.data + client->output.head;
253 p[0] = object->id;
254 p[1] = event | (8 << 16);
255 client->output.head += 8;
256 wl_event_loop_update_source(client->display->loop, client->source,
257 WL_EVENT_READABLE | WL_EVENT_WRITEABLE);
258}
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400259
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400260#define WL_DISPLAY_INVALID_OBJECT 0
261#define WL_DISPLAY_INVALID_METHOD 1
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400262
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400263static void
264wl_client_process_input(struct wl_client *client)
265{
266 const struct wl_method *method;
267 struct wl_object *object;
268 uint32_t *p, opcode, size;
269
270 while (1) {
271 if (client->input.head - client->input.tail < 2 * sizeof *p)
272 break;
273
274 p = (uint32_t *) (client->input.data + client->input.tail);
275 opcode = p[1] & 0xffff;
276 size = p[1] >> 16;
277 if (client->input.head - client->input.tail < size)
278 break;
279
280 object = wl_hash_lookup(&client->display->objects,
281 p[0]);
282 if (object == NULL) {
283 wl_client_event(client, &client->display->base,
284 WL_DISPLAY_INVALID_OBJECT);
285 client->input.tail += size;
286 continue;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400287 }
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400288
289 if (opcode >= object->interface->method_count) {
290 wl_client_event(client, &client->display->base,
291 WL_DISPLAY_INVALID_METHOD);
292 client->input.tail += size;
293 continue;
294 }
295
296 method = &object->interface->methods[opcode];
297 demarshal(client, object, method, p + 2);
298 client->input.tail += size;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400299 }
300}
301
302static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400303wl_client_data(int fd, uint32_t mask, void *data)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400304{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400305 struct wl_client *client = data;
306 int len;
307
308 if (mask & WL_EVENT_READABLE) {
309 len = read(fd, client->input.data, sizeof client->input.data);
310 if (len > 0) {
311 client->input.head += len;
312 wl_client_process_input(client);
313 } else if (len == 0 && errno == ECONNRESET) {
314 fprintf(stderr,
315 "read from client %p: %m (%d)\n",
316 client, errno);
317 } else {
318 wl_client_destroy(client);
319 }
320 }
321
322 if (mask & WL_EVENT_WRITEABLE) {
323 len = write(fd, client->output.data + client->output.tail,
324 client->output.head - client->output.tail);
325 client->output.tail += len;
326
327 if (client->output.tail == client->output.head)
328 wl_event_loop_update_source(client->display->loop,
329 client->source,
330 WL_EVENT_READABLE);
331 }
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400332}
333
334static int
335wl_display_create_surface(struct wl_client *client,
336 struct wl_display *display, uint32_t id)
337{
338 struct wl_surface *surface;
339
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400340 surface = wl_surface_create(display, id);
341 wl_hash_insert(&display->objects, &surface->base);
342
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400343 /* FIXME: garbage collect client resources when client exits. */
344
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400345 return 0;
346}
347
348static const struct wl_argument create_surface_arguments[] = {
349 { WL_ARGUMENT_NEW_ID }
350};
351
352static const struct wl_method display_methods[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400353 { "create_surface", wl_display_create_surface,
354 ARRAY_LENGTH(create_surface_arguments), create_surface_arguments },
355};
356
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400357static const struct wl_event display_events[] = {
358 { "invalid_object" },
359 { "invalid_method" },
360};
361
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400362static const struct wl_interface display_interface = {
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400363 "display", 1,
364 ARRAY_LENGTH(display_methods), display_methods,
365 ARRAY_LENGTH(display_events), display_events,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400366};
367
368struct wl_display *
369wl_display_create(void)
370{
371 struct wl_display *display;
372
373 display = malloc(sizeof *display);
374 if (display == NULL)
375 return NULL;
376
377 display->loop = wl_event_loop_create();
378 if (display->loop == NULL) {
379 free(display);
380 return NULL;
381 }
382
383 display->base.id = 0;
384 display->base.interface = &display_interface;
385 wl_hash_insert(&display->objects, &display->base);
386
387 return display;
388}
389
390void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400391wl_display_set_compositor(struct wl_display *display,
392 struct wl_compositor *compositor)
393{
394 display->compositor = compositor;
395}
396
397void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400398wl_display_run(struct wl_display *display)
399{
400 while (1)
401 wl_event_loop_wait(display->loop);
402}
403
404/* The plan here is to generate a random anonymous socket name and
405 * advertise that through a service on the session dbus.
406 */
407static const char socket_name[] = "\0wayland";
408
409static void
410socket_data(int fd, uint32_t mask, void *data)
411{
412 struct wl_display *display = data;
413 struct sockaddr_un name;
414 socklen_t length;
415 int client_fd;
416
417 length = sizeof name;
418 client_fd = accept (fd, (struct sockaddr *) &name, &length);
419 if (client_fd < 0)
420 fprintf(stderr, "failed to accept\n");
421
422 wl_client_create(display, client_fd);
423}
424
425int
426wl_display_add_socket(struct wl_display *display)
427{
428 struct sockaddr_un name;
429 int sock;
430 socklen_t size;
431
432 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
433 if (sock < 0)
434 return -1;
435
436 name.sun_family = AF_LOCAL;
437 memcpy(name.sun_path, socket_name, sizeof socket_name);
438
439 size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
440 if (bind(sock, (struct sockaddr *) &name, size) < 0)
441 return -1;
442
443 if (listen(sock, 1) < 0)
444 return -1;
445
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400446 wl_event_loop_add_fd(display->loop, sock,
447 WL_EVENT_READABLE,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400448 socket_data, display);
449
450 return 0;
451}
452
453
454int main(int argc, char *argv[])
455{
456 struct wl_display *display;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400457 struct wl_compositor *compositor;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400458
459 display = wl_display_create();
460
461 if (wl_display_add_socket(display)) {
462 fprintf(stderr, "failed to add socket: %m\n");
463 exit(EXIT_FAILURE);
464 }
465
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400466 compositor = wl_compositor_create();
467 wl_display_set_compositor(display, compositor);
468
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400469 printf("wayland online, display is %p\n", display);
470
471 wl_display_run(display);
472
473 return 0;
474}