blob: d2b003662449fdaefb542fa6efb0b0a4b5cd2cd5 [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>
Kristian Høgsberg5503bf82008-11-06 10:38:17 -050010#include <dlfcn.h>
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040011#include <ffi.h>
Kristian Høgsberg680f1c72008-10-08 12:48:46 -040012
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040013#include "wayland.h"
Kristian Høgsberg680f1c72008-10-08 12:48:46 -040014#include "connection.h"
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040015
Kristian Høgsbergf9212892008-10-11 18:40:23 -040016void wl_list_init(struct wl_list *list)
17{
18 list->prev = list;
19 list->next = list;
20}
21
22void
23wl_list_insert(struct wl_list *list, struct wl_list *elm)
24{
25 elm->prev = list;
26 elm->next = list->next;
27 list->next = elm;
28 elm->next->prev = elm;
29}
30
31void
32wl_list_remove(struct wl_list *elm)
33{
34 elm->prev->next = elm->next;
35 elm->next->prev = elm->prev;
36}
37
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040038struct wl_client {
Kristian Høgsberg680f1c72008-10-08 12:48:46 -040039 struct wl_connection *connection;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040040 struct wl_event_source *source;
41 struct wl_display *display;
Kristian Høgsberg94a2e862008-10-11 21:37:55 -040042 struct wl_list object_list;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050043 struct wl_list link;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040044};
45
46struct wl_display {
47 struct wl_object base;
48 struct wl_event_loop *loop;
49 struct wl_hash objects;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040050
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050051 struct wl_object *pointer;
52
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040053 struct wl_compositor *compositor;
54 struct wl_compositor_interface *compositor_interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040055
56 struct wl_list surface_list;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050057 struct wl_list client_list;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040058 uint32_t client_id_range;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050059
60 int32_t pointer_x;
61 int32_t pointer_y;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040062};
63
64struct wl_surface {
65 struct wl_object base;
66
67 /* provided by client */
68 int width, height;
69 int buffer;
70 int stride;
71
Kristian Høgsberg05eff512008-10-07 10:10:36 -040072 struct wl_map map;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040073 struct wl_list link;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040074
75 /* how to convert buffer contents to pixels in screen format;
76 * yuv->rgb, indexed->rgb, svg->rgb, but mostly just rgb->rgb. */
77
78 /* how to transform/render rectangular contents to polygons. */
Kristian Høgsberg05eff512008-10-07 10:10:36 -040079
80 void *compositor_data;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040081};
82
Kristian Høgsberg94a2e862008-10-11 21:37:55 -040083struct wl_object_ref {
84 struct wl_object *object;
85 struct wl_list link;
86};
Kristian Høgsberg05eff512008-10-07 10:10:36 -040087
88static void
89wl_surface_destroy(struct wl_client *client,
90 struct wl_surface *surface)
91{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -050092 const struct wl_compositor_interface *interface;
Kristian Høgsberg05eff512008-10-07 10:10:36 -040093
94 interface = client->display->compositor->interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040095 interface->notify_surface_destroy(client->display->compositor,
96 surface);
97 wl_list_remove(&surface->link);
Kristian Høgsberg05eff512008-10-07 10:10:36 -040098}
99
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400100static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400101wl_surface_attach(struct wl_client *client,
102 struct wl_surface *surface, uint32_t name,
103 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400104{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500105 const struct wl_compositor_interface *interface;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400106
107 interface = client->display->compositor->interface;
108 interface->notify_surface_attach(client->display->compositor,
109 surface, name, width, height, stride);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400110}
111
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400112static const struct wl_argument attach_arguments[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400113 { WL_ARGUMENT_UINT32 },
114 { WL_ARGUMENT_UINT32 },
115 { WL_ARGUMENT_UINT32 },
116 { WL_ARGUMENT_UINT32 },
117};
118
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500119static void
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400120wl_surface_map(struct wl_client *client, struct wl_surface *surface,
121 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400122{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500123 const struct wl_compositor_interface *interface;
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400124
125 /* FIXME: This needs to take a tri-mesh argument... - count
126 * and a list of tris. 0 tris means unmap. */
127
128 surface->map.x = x;
129 surface->map.y = y;
130 surface->map.width = width;
131 surface->map.height = height;
132
133 interface = client->display->compositor->interface;
134 interface->notify_surface_map(client->display->compositor,
135 surface, &surface->map);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400136}
137
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400138static const struct wl_argument map_arguments[] = {
139 { WL_ARGUMENT_UINT32 },
140 { WL_ARGUMENT_UINT32 },
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400141 { WL_ARGUMENT_UINT32 },
142 { WL_ARGUMENT_UINT32 },
143};
144
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500145static void
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500146wl_surface_copy(struct wl_client *client, struct wl_surface *surface,
147 int32_t dst_x, int32_t dst_y, uint32_t name, uint32_t stride,
148 int32_t x, int32_t y, int32_t width, int32_t height)
149{
150 const struct wl_compositor_interface *interface;
151
152 interface = client->display->compositor->interface;
153 interface->notify_surface_copy(client->display->compositor,
154 surface, dst_x, dst_y,
155 name, stride, x, y, width, height);
156}
157
158static const struct wl_argument copy_arguments[] = {
159 { WL_ARGUMENT_UINT32 },
160 { WL_ARGUMENT_UINT32 },
161 { WL_ARGUMENT_UINT32 },
162 { WL_ARGUMENT_UINT32 },
163 { WL_ARGUMENT_UINT32 },
164 { WL_ARGUMENT_UINT32 },
165 { WL_ARGUMENT_UINT32 },
166 { WL_ARGUMENT_UINT32 },
167 { WL_ARGUMENT_UINT32 },
168 { WL_ARGUMENT_UINT32 },
169};
170
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500171static void
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500172wl_surface_damage(struct wl_client *client, struct wl_surface *surface,
173 int32_t x, int32_t y, int32_t width, int32_t height)
174{
175 const struct wl_compositor_interface *interface;
176
177 interface = client->display->compositor->interface;
178 interface->notify_surface_damage(client->display->compositor,
179 surface, x, y, width, height);
180}
181
182static const struct wl_argument damage_arguments[] = {
183 { WL_ARGUMENT_UINT32 },
184 { WL_ARGUMENT_UINT32 },
185 { WL_ARGUMENT_UINT32 },
186 { WL_ARGUMENT_UINT32 },
187};
188
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400189static const struct wl_method surface_methods[] = {
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400190 { "destroy", wl_surface_destroy,
191 0, NULL },
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400192 { "attach", wl_surface_attach,
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400193 ARRAY_LENGTH(attach_arguments), attach_arguments },
194 { "map", wl_surface_map,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500195 ARRAY_LENGTH(map_arguments), map_arguments },
196 { "copy", wl_surface_copy,
197 ARRAY_LENGTH(copy_arguments), copy_arguments },
198 { "damage", wl_surface_damage,
199 ARRAY_LENGTH(damage_arguments), damage_arguments }
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400200};
201
202static const struct wl_interface surface_interface = {
203 "surface", 1,
204 ARRAY_LENGTH(surface_methods),
205 surface_methods,
206};
207
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500208static struct wl_surface *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400209wl_surface_create(struct wl_display *display, uint32_t id)
210{
211 struct wl_surface *surface;
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500212 const struct wl_compositor_interface *interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400213
214 surface = malloc(sizeof *surface);
215 if (surface == NULL)
216 return NULL;
217
218 surface->base.id = id;
219 surface->base.interface = &surface_interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400220
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400221 wl_list_insert(display->surface_list.prev, &surface->link);
222
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400223 interface = display->compositor->interface;
224 interface->notify_surface_create(display->compositor, surface);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400225
226 return surface;
227}
228
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500229WL_EXPORT void
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400230wl_surface_set_data(struct wl_surface *surface, void *data)
231{
232 surface->compositor_data = data;
233}
234
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500235WL_EXPORT void *
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400236wl_surface_get_data(struct wl_surface *surface)
237{
238 return surface->compositor_data;
239}
240
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400241void
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400242wl_client_destroy(struct wl_client *client);
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400243
244static void
245wl_client_demarshal(struct wl_client *client, struct wl_object *target,
246 const struct wl_method *method, size_t size)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400247{
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500248 ffi_type *types[20];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400249 ffi_cif cif;
250 uint32_t *p, result;
251 int i;
252 union {
253 uint32_t uint32;
254 const char *string;
255 void *object;
256 uint32_t new_id;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500257 } values[20];
258 void *args[20];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400259 struct wl_object *object;
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400260 uint32_t data[64];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400261
262 if (method->argument_count > ARRAY_LENGTH(types)) {
263 printf("too many args (%d)\n", method->argument_count);
264 return;
265 }
266
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400267 if (sizeof data < size) {
268 printf("request too big, should malloc tmp buffer here\n");
269 return;
270 }
271
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400272 types[0] = &ffi_type_pointer;
273 values[0].object = client;
274 args[0] = &values[0];
275
276 types[1] = &ffi_type_pointer;
277 values[1].object = target;
278 args[1] = &values[1];
279
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400280 wl_connection_copy(client->connection, data, size);
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400281 p = &data[2];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400282 for (i = 0; i < method->argument_count; i++) {
283 switch (method->arguments[i].type) {
284 case WL_ARGUMENT_UINT32:
285 types[i + 2] = &ffi_type_uint32;
286 values[i + 2].uint32 = *p;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400287 p++;
288 break;
289 case WL_ARGUMENT_STRING:
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400290 types[i + 2] = &ffi_type_pointer;
291 /* FIXME */
292 values[i + 2].uint32 = *p++;
293 break;
294 case WL_ARGUMENT_OBJECT:
295 types[i + 2] = &ffi_type_pointer;
296 object = wl_hash_lookup(&client->display->objects, *p);
297 if (object == NULL)
298 printf("unknown object (%d)\n", *p);
299 if (object->interface != method->arguments[i].data)
300 printf("wrong object type\n");
301 values[i + 2].object = object;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400302 p++;
303 break;
304 case WL_ARGUMENT_NEW_ID:
305 types[i + 2] = &ffi_type_uint32;
306 values[i + 2].new_id = *p;
307 object = wl_hash_lookup(&client->display->objects, *p);
308 if (object != NULL)
309 printf("object already exists (%d)\n", *p);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400310 p++;
311 break;
312 default:
313 printf("unknown type\n");
314 break;
315 }
316 args[i + 2] = &values[i + 2];
317 }
318
319 ffi_prep_cif(&cif, FFI_DEFAULT_ABI, method->argument_count + 2,
320 &ffi_type_uint32, types);
321 ffi_call(&cif, FFI_FN(method->func), &result, args);
322}
323
324static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400325wl_client_event(struct wl_client *client, struct wl_object *object, uint32_t event)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400326{
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400327 uint32_t p[2];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400328
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400329 p[0] = object->id;
330 p[1] = event | (8 << 16);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400331 wl_connection_write(client->connection, p, sizeof p);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400332}
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400333
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400334#define WL_DISPLAY_INVALID_OBJECT 0
335#define WL_DISPLAY_INVALID_METHOD 1
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400336#define WL_DISPLAY_NO_MEMORY 2
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400337
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400338static void
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400339wl_client_connection_data(int fd, uint32_t mask, void *data)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400340{
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400341 struct wl_client *client = data;
342 struct wl_connection *connection = client->connection;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400343 const struct wl_method *method;
344 struct wl_object *object;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400345 uint32_t p[2], opcode, size;
346 uint32_t cmask = 0;
347 int len;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400348
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400349 if (mask & WL_EVENT_READABLE)
350 cmask |= WL_CONNECTION_READABLE;
351 if (mask & WL_EVENT_WRITEABLE)
352 cmask |= WL_CONNECTION_WRITABLE;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400353
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400354 len = wl_connection_data(connection, cmask);
355 if (len < 0) {
356 wl_client_destroy(client);
357 return;
358 }
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400359
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400360 while (len > sizeof p) {
361 wl_connection_copy(connection, p, sizeof p);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400362 opcode = p[1] & 0xffff;
363 size = p[1] >> 16;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400364 if (len < size)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400365 break;
366
367 object = wl_hash_lookup(&client->display->objects,
368 p[0]);
369 if (object == NULL) {
370 wl_client_event(client, &client->display->base,
371 WL_DISPLAY_INVALID_OBJECT);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400372 wl_connection_consume(connection, size);
373 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400374 continue;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400375 }
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400376
377 if (opcode >= object->interface->method_count) {
378 wl_client_event(client, &client->display->base,
379 WL_DISPLAY_INVALID_METHOD);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400380 wl_connection_consume(connection, size);
381 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400382 continue;
383 }
384
385 method = &object->interface->methods[opcode];
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400386 wl_client_demarshal(client, object, method, size);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400387 wl_connection_consume(connection, size);
388 len -= size;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400389 }
390}
391
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400392static int
393wl_client_connection_update(struct wl_connection *connection,
394 uint32_t mask, void *data)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400395{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400396 struct wl_client *client = data;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400397 uint32_t emask = 0;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400398
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400399 if (mask & WL_CONNECTION_READABLE)
400 emask |= WL_EVENT_READABLE;
401 if (mask & WL_CONNECTION_WRITABLE)
402 emask |= WL_EVENT_WRITEABLE;
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400403
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400404 return wl_event_loop_update_source(client->display->loop,
405 client->source, mask);
406}
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400407
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400408static void
409advertise_object(struct wl_client *client, struct wl_object *object)
410{
411 const struct wl_interface *interface;
412 static const char pad[4];
413 uint32_t length, p[2];
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400414
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400415 interface = object->interface;
416 length = strlen(interface->name);
417 p[0] = object->id;
418 p[1] = length;
419 wl_connection_write(client->connection, p, sizeof p);
420 wl_connection_write(client->connection, interface->name, length);
421 wl_connection_write(client->connection, pad, -length & 3);
422}
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400423
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500424static struct wl_client *
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400425wl_client_create(struct wl_display *display, int fd)
426{
427 struct wl_client *client;
428
429 client = malloc(sizeof *client);
430 if (client == NULL)
431 return NULL;
432
433 memset(client, 0, sizeof *client);
434 client->display = display;
435 client->source = wl_event_loop_add_fd(display->loop, fd,
436 WL_EVENT_READABLE,
437 wl_client_connection_data, client);
438 client->connection = wl_connection_create(fd,
439 wl_client_connection_update,
440 client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400441 wl_list_init(&client->object_list);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400442
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400443 wl_connection_write(client->connection,
444 &display->client_id_range,
445 sizeof display->client_id_range);
446 display->client_id_range += 256;
447
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400448 advertise_object(client, &display->base);
449
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500450 wl_list_insert(display->client_list.prev, &client->link);
451
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400452 return client;
453}
454
455void
456wl_client_destroy(struct wl_client *client)
457{
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400458 struct wl_object_ref *ref;
459
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400460 printf("disconnect from client %p\n", client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400461
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500462 wl_list_remove(&client->link);
463
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400464 while (client->object_list.next != &client->object_list) {
465 ref = container_of(client->object_list.next,
466 struct wl_object_ref, link);
467 wl_list_remove(&ref->link);
468 wl_surface_destroy(client, (struct wl_surface *) ref->object);
469 free(ref);
470 }
471
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400472 wl_event_loop_remove_source(client->display->loop, client->source);
473 wl_connection_destroy(client->connection);
474 free(client);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400475}
476
477static int
478wl_display_create_surface(struct wl_client *client,
479 struct wl_display *display, uint32_t id)
480{
481 struct wl_surface *surface;
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400482 struct wl_object_ref *ref;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400483
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400484 surface = wl_surface_create(display, id);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400485
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400486 ref = malloc(sizeof *ref);
487 if (ref == NULL) {
488 wl_client_event(client, &display->base,
489 WL_DISPLAY_NO_MEMORY);
490 return -1;
491 }
492
493 ref->object = &surface->base;
494 wl_hash_insert(&display->objects, &surface->base);
495 wl_list_insert(client->object_list.prev, &ref->link);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400496
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400497 return 0;
498}
499
500static const struct wl_argument create_surface_arguments[] = {
501 { WL_ARGUMENT_NEW_ID }
502};
503
504static const struct wl_method display_methods[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400505 { "create_surface", wl_display_create_surface,
506 ARRAY_LENGTH(create_surface_arguments), create_surface_arguments },
507};
508
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400509static const struct wl_event display_events[] = {
510 { "invalid_object" },
511 { "invalid_method" },
512};
513
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400514static const struct wl_interface display_interface = {
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400515 "display", 1,
516 ARRAY_LENGTH(display_methods), display_methods,
517 ARRAY_LENGTH(display_events), display_events,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400518};
519
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500520static const char input_device_file[] =
521 "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-mouse";
522
523static void
524wl_display_create_input_devices(struct wl_display *display)
525{
Kristian Høgsberg33a52bd2008-11-03 15:31:30 -0500526 const char *path;
527
528 path = getenv("WAYLAND_POINTER");
529 if (path == NULL)
530 path = input_device_file;
531
532 display->pointer = wl_input_device_create(display, path, 1);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500533
534 if (display->pointer != NULL)
535 wl_hash_insert(&display->objects, display->pointer);
536
537 display->pointer_x = 100;
538 display->pointer_y = 100;
539}
540
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500541static struct wl_display *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400542wl_display_create(void)
543{
544 struct wl_display *display;
545
546 display = malloc(sizeof *display);
547 if (display == NULL)
548 return NULL;
549
550 display->loop = wl_event_loop_create();
551 if (display->loop == NULL) {
552 free(display);
553 return NULL;
554 }
555
556 display->base.id = 0;
557 display->base.interface = &display_interface;
558 wl_hash_insert(&display->objects, &display->base);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400559 wl_list_init(&display->surface_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500560 wl_list_init(&display->client_list);
561
562 wl_display_create_input_devices(display);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400563
564 display->client_id_range = 256; /* Gah, arbitrary... */
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400565
566 return display;
567}
568
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500569static void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500570wl_display_send_event(struct wl_display *display, uint32_t *data, size_t size)
571{
572 struct wl_client *client;
573
574 client = container_of(display->client_list.next,
575 struct wl_client, link);
576 while (&client->link != &display->client_list) {
577 wl_connection_write(client->connection, data, size);
578
579 client = container_of(client->link.next,
580 struct wl_client, link);
581 }
582}
583
584#define WL_POINTER_MOTION 0
585#define WL_POINTER_BUTTON 1
586
587void
588wl_display_post_relative_event(struct wl_display *display,
589 struct wl_object *source, int dx, int dy)
590{
591 uint32_t p[4];
592
593 display->pointer_x += dx;
594 display->pointer_y += dy;
595
596 p[0] = source->id;
597 p[1] = (sizeof p << 16) | WL_POINTER_MOTION;
598 p[2] = display->pointer_x;
599 p[3] = display->pointer_y;
600
601 wl_display_send_event(display, p, sizeof p);
602}
603
604void
605wl_display_post_absolute_event(struct wl_display *display,
606 struct wl_object *source, int x, int y)
607{
608 uint32_t p[4];
609
610 display->pointer_x = x;
611 display->pointer_y = y;
612
613 p[0] = source->id;
614 p[1] = (sizeof p << 16) | WL_POINTER_MOTION;
615 p[2] = display->pointer_x;
616 p[3] = display->pointer_y;
617
618 wl_display_send_event(display, p, sizeof p);
619}
620
621void
622wl_display_post_button_event(struct wl_display *display,
623 struct wl_object *source, int button, int state)
624{
625 uint32_t p[4];
626
627 p[0] = source->id;
628 p[1] = (sizeof p << 16) | WL_POINTER_BUTTON;
629 p[2] = button;
630 p[3] = state;
631
632 wl_display_send_event(display, p, sizeof p);
633}
634
635void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400636wl_display_set_compositor(struct wl_display *display,
637 struct wl_compositor *compositor)
638{
639 display->compositor = compositor;
640}
641
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500642WL_EXPORT struct wl_event_loop *
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400643wl_display_get_event_loop(struct wl_display *display)
644{
645 return display->loop;
646}
647
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500648static void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400649wl_display_run(struct wl_display *display)
650{
651 while (1)
652 wl_event_loop_wait(display->loop);
653}
654
655/* The plan here is to generate a random anonymous socket name and
656 * advertise that through a service on the session dbus.
657 */
658static const char socket_name[] = "\0wayland";
659
660static void
661socket_data(int fd, uint32_t mask, void *data)
662{
663 struct wl_display *display = data;
664 struct sockaddr_un name;
665 socklen_t length;
666 int client_fd;
667
668 length = sizeof name;
669 client_fd = accept (fd, (struct sockaddr *) &name, &length);
670 if (client_fd < 0)
671 fprintf(stderr, "failed to accept\n");
672
673 wl_client_create(display, client_fd);
674}
675
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500676static int
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400677wl_display_add_socket(struct wl_display *display)
678{
679 struct sockaddr_un name;
680 int sock;
681 socklen_t size;
682
683 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
684 if (sock < 0)
685 return -1;
686
687 name.sun_family = AF_LOCAL;
688 memcpy(name.sun_path, socket_name, sizeof socket_name);
689
690 size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
691 if (bind(sock, (struct sockaddr *) &name, size) < 0)
692 return -1;
693
694 if (listen(sock, 1) < 0)
695 return -1;
696
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400697 wl_event_loop_add_fd(display->loop, sock,
698 WL_EVENT_READABLE,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400699 socket_data, display);
700
701 return 0;
702}
703
704
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400705struct wl_surface_iterator {
706 struct wl_list *head;
707 struct wl_surface *surface;
708 uint32_t mask;
709};
710
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500711WL_EXPORT struct wl_surface_iterator *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400712wl_surface_iterator_create(struct wl_display *display, uint32_t mask)
713{
714 struct wl_surface_iterator *iterator;
715
716 iterator = malloc(sizeof *iterator);
717 if (iterator == NULL)
718 return NULL;
719
720 iterator->head = &display->surface_list;
721 iterator->surface = container_of(display->surface_list.next,
722 struct wl_surface, link);
723 iterator->mask = mask;
724
725 return iterator;
726}
727
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500728WL_EXPORT int
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400729wl_surface_iterator_next(struct wl_surface_iterator *iterator,
730 struct wl_surface **surface)
731{
732 if (&iterator->surface->link == iterator->head)
733 return 0;
734
735 *surface = iterator->surface;
736 iterator->surface = container_of(iterator->surface->link.next,
737 struct wl_surface, link);
738
739 return 1;
740}
741
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500742WL_EXPORT void
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400743wl_surface_iterator_destroy(struct wl_surface_iterator *iterator)
744{
745 free(iterator);
746}
747
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500748static int
749load_compositor(struct wl_display *display, const char *path)
750{
751 struct wl_compositor *(*create)(struct wl_display *display);
752 struct wl_compositor *compositor;
753 void *p;
754
755 p = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
756 if (p == NULL) {
757 fprintf(stderr, "failed to open compositor %s: %s\n",
758 path, dlerror());
759 return -1;
760 }
761
762 create = dlsym(p, "wl_compositor_create");
763 if (create == NULL) {
764 fprintf(stderr, "failed to look up compositor constructor\n");
765 return -1;
766 }
767
768 compositor = create(display);
769 if (compositor == NULL) {
770 fprintf(stderr, "couldn't create compositor\n");
771 return -1;
772 }
773
774 wl_display_set_compositor(display, compositor);
775
776 return 0;
777}
778
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400779int main(int argc, char *argv[])
780{
781 struct wl_display *display;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500782 const char *compositor = "./egl-compositor.so";
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400783
784 display = wl_display_create();
785
786 if (wl_display_add_socket(display)) {
787 fprintf(stderr, "failed to add socket: %m\n");
788 exit(EXIT_FAILURE);
789 }
790
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500791 if (argc == 2)
792 compositor = argv[1];
793 load_compositor(display, compositor);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400794
795 wl_display_run(display);
796
797 return 0;
798}