blob: 766dc0ae497a3421b433c35820c1e82e6343f4e2 [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øgsberg97f1ebe2008-09-30 09:46:10 -040016struct wl_client {
Kristian Høgsberg680f1c72008-10-08 12:48:46 -040017 struct wl_connection *connection;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040018 struct wl_event_source *source;
19 struct wl_display *display;
Kristian Høgsberg94a2e862008-10-11 21:37:55 -040020 struct wl_list object_list;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050021 struct wl_list link;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040022};
23
24struct wl_display {
25 struct wl_object base;
26 struct wl_event_loop *loop;
27 struct wl_hash objects;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040028
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050029 struct wl_object *pointer;
30
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040031 struct wl_compositor *compositor;
32 struct wl_compositor_interface *compositor_interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040033
34 struct wl_list surface_list;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050035 struct wl_list client_list;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040036 uint32_t client_id_range;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -050037 uint32_t id;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050038
Kristian Høgsberg14fcff72008-11-23 19:10:23 -050039 struct wl_list global_list;
40
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050041 int32_t pointer_x;
42 int32_t pointer_y;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040043};
44
45struct wl_surface {
46 struct wl_object base;
47
48 /* provided by client */
49 int width, height;
50 int buffer;
51 int stride;
52
Kristian Høgsberg05eff512008-10-07 10:10:36 -040053 struct wl_map map;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040054 struct wl_list link;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040055
56 /* how to convert buffer contents to pixels in screen format;
57 * yuv->rgb, indexed->rgb, svg->rgb, but mostly just rgb->rgb. */
58
59 /* how to transform/render rectangular contents to polygons. */
Kristian Høgsberg05eff512008-10-07 10:10:36 -040060
61 void *compositor_data;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040062};
63
Kristian Høgsberg94a2e862008-10-11 21:37:55 -040064struct wl_object_ref {
65 struct wl_object *object;
66 struct wl_list link;
67};
Kristian Høgsberg05eff512008-10-07 10:10:36 -040068
69static void
70wl_surface_destroy(struct wl_client *client,
71 struct wl_surface *surface)
72{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -050073 const struct wl_compositor_interface *interface;
Kristian Høgsberg05eff512008-10-07 10:10:36 -040074
75 interface = client->display->compositor->interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040076 interface->notify_surface_destroy(client->display->compositor,
77 surface);
78 wl_list_remove(&surface->link);
Kristian Høgsberg05eff512008-10-07 10:10:36 -040079}
80
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040081static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040082wl_surface_attach(struct wl_client *client,
83 struct wl_surface *surface, uint32_t name,
84 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040085{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -050086 const struct wl_compositor_interface *interface;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040087
88 interface = client->display->compositor->interface;
89 interface->notify_surface_attach(client->display->compositor,
90 surface, name, width, height, stride);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040091}
92
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040093static const struct wl_argument attach_arguments[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040094 { WL_ARGUMENT_UINT32 },
95 { WL_ARGUMENT_UINT32 },
96 { WL_ARGUMENT_UINT32 },
97 { WL_ARGUMENT_UINT32 },
98};
99
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500100static void
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400101wl_surface_map(struct wl_client *client, struct wl_surface *surface,
102 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400103{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500104 const struct wl_compositor_interface *interface;
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400105
106 /* FIXME: This needs to take a tri-mesh argument... - count
107 * and a list of tris. 0 tris means unmap. */
108
109 surface->map.x = x;
110 surface->map.y = y;
111 surface->map.width = width;
112 surface->map.height = height;
113
114 interface = client->display->compositor->interface;
115 interface->notify_surface_map(client->display->compositor,
116 surface, &surface->map);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400117}
118
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400119static const struct wl_argument map_arguments[] = {
120 { WL_ARGUMENT_UINT32 },
121 { WL_ARGUMENT_UINT32 },
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400122 { WL_ARGUMENT_UINT32 },
123 { WL_ARGUMENT_UINT32 },
124};
125
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500126static void
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500127wl_surface_copy(struct wl_client *client, struct wl_surface *surface,
128 int32_t dst_x, int32_t dst_y, uint32_t name, uint32_t stride,
129 int32_t x, int32_t y, int32_t width, int32_t height)
130{
131 const struct wl_compositor_interface *interface;
132
133 interface = client->display->compositor->interface;
134 interface->notify_surface_copy(client->display->compositor,
135 surface, dst_x, dst_y,
136 name, stride, x, y, width, height);
137}
138
139static const struct wl_argument copy_arguments[] = {
140 { WL_ARGUMENT_UINT32 },
141 { WL_ARGUMENT_UINT32 },
142 { WL_ARGUMENT_UINT32 },
143 { WL_ARGUMENT_UINT32 },
144 { WL_ARGUMENT_UINT32 },
145 { WL_ARGUMENT_UINT32 },
146 { WL_ARGUMENT_UINT32 },
147 { WL_ARGUMENT_UINT32 },
148 { WL_ARGUMENT_UINT32 },
149 { WL_ARGUMENT_UINT32 },
150};
151
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500152static void
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500153wl_surface_damage(struct wl_client *client, struct wl_surface *surface,
154 int32_t x, int32_t y, int32_t width, int32_t height)
155{
156 const struct wl_compositor_interface *interface;
157
158 interface = client->display->compositor->interface;
159 interface->notify_surface_damage(client->display->compositor,
160 surface, x, y, width, height);
161}
162
163static const struct wl_argument damage_arguments[] = {
164 { WL_ARGUMENT_UINT32 },
165 { WL_ARGUMENT_UINT32 },
166 { WL_ARGUMENT_UINT32 },
167 { WL_ARGUMENT_UINT32 },
168};
169
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400170static const struct wl_method surface_methods[] = {
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400171 { "destroy", wl_surface_destroy,
172 0, NULL },
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400173 { "attach", wl_surface_attach,
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400174 ARRAY_LENGTH(attach_arguments), attach_arguments },
175 { "map", wl_surface_map,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500176 ARRAY_LENGTH(map_arguments), map_arguments },
177 { "copy", wl_surface_copy,
178 ARRAY_LENGTH(copy_arguments), copy_arguments },
179 { "damage", wl_surface_damage,
180 ARRAY_LENGTH(damage_arguments), damage_arguments }
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400181};
182
183static const struct wl_interface surface_interface = {
184 "surface", 1,
185 ARRAY_LENGTH(surface_methods),
186 surface_methods,
187};
188
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500189static struct wl_surface *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400190wl_surface_create(struct wl_display *display, uint32_t id)
191{
192 struct wl_surface *surface;
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500193 const struct wl_compositor_interface *interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400194
195 surface = malloc(sizeof *surface);
196 if (surface == NULL)
197 return NULL;
198
199 surface->base.id = id;
200 surface->base.interface = &surface_interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400201
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400202 wl_list_insert(display->surface_list.prev, &surface->link);
203
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400204 interface = display->compositor->interface;
205 interface->notify_surface_create(display->compositor, surface);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400206
207 return surface;
208}
209
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500210WL_EXPORT void
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400211wl_surface_set_data(struct wl_surface *surface, void *data)
212{
213 surface->compositor_data = data;
214}
215
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500216WL_EXPORT void *
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400217wl_surface_get_data(struct wl_surface *surface)
218{
219 return surface->compositor_data;
220}
221
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400222void
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400223wl_client_destroy(struct wl_client *client);
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400224
225static void
226wl_client_demarshal(struct wl_client *client, struct wl_object *target,
227 const struct wl_method *method, size_t size)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400228{
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500229 ffi_type *types[20];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400230 ffi_cif cif;
231 uint32_t *p, result;
232 int i;
233 union {
234 uint32_t uint32;
235 const char *string;
236 void *object;
237 uint32_t new_id;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500238 } values[20];
239 void *args[20];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400240 struct wl_object *object;
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400241 uint32_t data[64];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400242
243 if (method->argument_count > ARRAY_LENGTH(types)) {
244 printf("too many args (%d)\n", method->argument_count);
245 return;
246 }
247
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400248 if (sizeof data < size) {
249 printf("request too big, should malloc tmp buffer here\n");
250 return;
251 }
252
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400253 types[0] = &ffi_type_pointer;
254 values[0].object = client;
255 args[0] = &values[0];
256
257 types[1] = &ffi_type_pointer;
258 values[1].object = target;
259 args[1] = &values[1];
260
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400261 wl_connection_copy(client->connection, data, size);
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400262 p = &data[2];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400263 for (i = 0; i < method->argument_count; i++) {
264 switch (method->arguments[i].type) {
265 case WL_ARGUMENT_UINT32:
266 types[i + 2] = &ffi_type_uint32;
267 values[i + 2].uint32 = *p;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400268 p++;
269 break;
270 case WL_ARGUMENT_STRING:
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400271 types[i + 2] = &ffi_type_pointer;
272 /* FIXME */
273 values[i + 2].uint32 = *p++;
274 break;
275 case WL_ARGUMENT_OBJECT:
276 types[i + 2] = &ffi_type_pointer;
277 object = wl_hash_lookup(&client->display->objects, *p);
278 if (object == NULL)
279 printf("unknown object (%d)\n", *p);
280 if (object->interface != method->arguments[i].data)
281 printf("wrong object type\n");
282 values[i + 2].object = object;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400283 p++;
284 break;
285 case WL_ARGUMENT_NEW_ID:
286 types[i + 2] = &ffi_type_uint32;
287 values[i + 2].new_id = *p;
288 object = wl_hash_lookup(&client->display->objects, *p);
289 if (object != NULL)
290 printf("object already exists (%d)\n", *p);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400291 p++;
292 break;
293 default:
294 printf("unknown type\n");
295 break;
296 }
297 args[i + 2] = &values[i + 2];
298 }
299
300 ffi_prep_cif(&cif, FFI_DEFAULT_ABI, method->argument_count + 2,
301 &ffi_type_uint32, types);
302 ffi_call(&cif, FFI_FN(method->func), &result, args);
303}
304
305static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400306wl_client_event(struct wl_client *client, struct wl_object *object, uint32_t event)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400307{
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400308 uint32_t p[2];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400309
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400310 p[0] = object->id;
311 p[1] = event | (8 << 16);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400312 wl_connection_write(client->connection, p, sizeof p);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400313}
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400314
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400315#define WL_DISPLAY_INVALID_OBJECT 0
316#define WL_DISPLAY_INVALID_METHOD 1
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400317#define WL_DISPLAY_NO_MEMORY 2
Kristian Høgsberg40979232008-11-25 22:40:39 -0500318#define WL_DISPLAY_ACKNOWLEDGE 3
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400319
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400320static void
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400321wl_client_connection_data(int fd, uint32_t mask, void *data)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400322{
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400323 struct wl_client *client = data;
324 struct wl_connection *connection = client->connection;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400325 const struct wl_method *method;
326 struct wl_object *object;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400327 uint32_t p[2], opcode, size;
328 uint32_t cmask = 0;
329 int len;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400330
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400331 if (mask & WL_EVENT_READABLE)
332 cmask |= WL_CONNECTION_READABLE;
333 if (mask & WL_EVENT_WRITEABLE)
334 cmask |= WL_CONNECTION_WRITABLE;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400335
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400336 len = wl_connection_data(connection, cmask);
337 if (len < 0) {
338 wl_client_destroy(client);
339 return;
340 }
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400341
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500342 while (len >= sizeof p) {
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400343 wl_connection_copy(connection, p, sizeof p);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400344 opcode = p[1] & 0xffff;
345 size = p[1] >> 16;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400346 if (len < size)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400347 break;
348
349 object = wl_hash_lookup(&client->display->objects,
350 p[0]);
351 if (object == NULL) {
352 wl_client_event(client, &client->display->base,
353 WL_DISPLAY_INVALID_OBJECT);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400354 wl_connection_consume(connection, size);
355 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400356 continue;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400357 }
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400358
359 if (opcode >= object->interface->method_count) {
360 wl_client_event(client, &client->display->base,
361 WL_DISPLAY_INVALID_METHOD);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400362 wl_connection_consume(connection, size);
363 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400364 continue;
365 }
366
367 method = &object->interface->methods[opcode];
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400368 wl_client_demarshal(client, object, method, size);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400369 wl_connection_consume(connection, size);
370 len -= size;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400371 }
372}
373
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400374static int
375wl_client_connection_update(struct wl_connection *connection,
376 uint32_t mask, void *data)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400377{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400378 struct wl_client *client = data;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400379 uint32_t emask = 0;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400380
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400381 if (mask & WL_CONNECTION_READABLE)
382 emask |= WL_EVENT_READABLE;
383 if (mask & WL_CONNECTION_WRITABLE)
384 emask |= WL_EVENT_WRITEABLE;
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400385
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400386 return wl_event_loop_update_source(client->display->loop,
387 client->source, mask);
388}
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400389
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400390static void
391advertise_object(struct wl_client *client, struct wl_object *object)
392{
393 const struct wl_interface *interface;
394 static const char pad[4];
395 uint32_t length, p[2];
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400396
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400397 interface = object->interface;
398 length = strlen(interface->name);
399 p[0] = object->id;
400 p[1] = length;
401 wl_connection_write(client->connection, p, sizeof p);
402 wl_connection_write(client->connection, interface->name, length);
403 wl_connection_write(client->connection, pad, -length & 3);
404}
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400405
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500406static struct wl_client *
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400407wl_client_create(struct wl_display *display, int fd)
408{
409 struct wl_client *client;
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500410 struct wl_object_ref *ref;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500411 uint32_t count;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400412
413 client = malloc(sizeof *client);
414 if (client == NULL)
415 return NULL;
416
417 memset(client, 0, sizeof *client);
418 client->display = display;
419 client->source = wl_event_loop_add_fd(display->loop, fd,
420 WL_EVENT_READABLE,
421 wl_client_connection_data, client);
422 client->connection = wl_connection_create(fd,
423 wl_client_connection_update,
424 client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400425 wl_list_init(&client->object_list);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400426
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400427 wl_connection_write(client->connection,
428 &display->client_id_range,
429 sizeof display->client_id_range);
430 display->client_id_range += 256;
431
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500432 /* Write list of global objects to client. */
433 count = wl_list_length(&display->global_list);
434 wl_connection_write(client->connection, &count, sizeof count);
435
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500436 ref = container_of(display->global_list.next,
437 struct wl_object_ref, link);
438 while (&ref->link != &display->global_list) {
439 advertise_object(client, ref->object);
440
441 ref = container_of(ref->link.next,
442 struct wl_object_ref, link);
443 }
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400444
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500445 wl_list_insert(display->client_list.prev, &client->link);
446
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400447 return client;
448}
449
450void
451wl_client_destroy(struct wl_client *client)
452{
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400453 struct wl_object_ref *ref;
454
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400455 printf("disconnect from client %p\n", client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400456
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500457 wl_list_remove(&client->link);
458
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400459 while (client->object_list.next != &client->object_list) {
460 ref = container_of(client->object_list.next,
461 struct wl_object_ref, link);
462 wl_list_remove(&ref->link);
463 wl_surface_destroy(client, (struct wl_surface *) ref->object);
464 free(ref);
465 }
466
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400467 wl_event_loop_remove_source(client->display->loop, client->source);
468 wl_connection_destroy(client->connection);
469 free(client);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400470}
471
472static int
473wl_display_create_surface(struct wl_client *client,
474 struct wl_display *display, uint32_t id)
475{
476 struct wl_surface *surface;
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400477 struct wl_object_ref *ref;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400478
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400479 surface = wl_surface_create(display, id);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400480
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400481 ref = malloc(sizeof *ref);
482 if (ref == NULL) {
483 wl_client_event(client, &display->base,
484 WL_DISPLAY_NO_MEMORY);
485 return -1;
486 }
487
488 ref->object = &surface->base;
489 wl_hash_insert(&display->objects, &surface->base);
490 wl_list_insert(client->object_list.prev, &ref->link);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400491
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400492 return 0;
493}
494
495static const struct wl_argument create_surface_arguments[] = {
496 { WL_ARGUMENT_NEW_ID }
497};
498
Kristian Høgsberg40979232008-11-25 22:40:39 -0500499static int
500wl_display_commit(struct wl_client *client,
501 struct wl_display *display, uint32_t key)
502{
503 uint32_t event[3];
504
505 event[0] = display->base.id;
506 event[1] = WL_DISPLAY_ACKNOWLEDGE | ((sizeof event) << 16);
507 event[2] = key;
508 wl_connection_write(client->connection, event, sizeof event);
509
510 return 0;
511}
512
513static const struct wl_argument commit_arguments[] = {
514 { WL_ARGUMENT_UINT32 }
515};
516
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400517static const struct wl_method display_methods[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400518 { "create_surface", wl_display_create_surface,
519 ARRAY_LENGTH(create_surface_arguments), create_surface_arguments },
Kristian Høgsberg40979232008-11-25 22:40:39 -0500520 { "commit", wl_display_commit,
521 ARRAY_LENGTH(commit_arguments), commit_arguments },
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400522};
523
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400524static const struct wl_event display_events[] = {
525 { "invalid_object" },
526 { "invalid_method" },
Kristian Høgsberg40979232008-11-25 22:40:39 -0500527 { "no_memory" },
528 { "acknowledge" },
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400529};
530
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400531static const struct wl_interface display_interface = {
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400532 "display", 1,
533 ARRAY_LENGTH(display_methods), display_methods,
534 ARRAY_LENGTH(display_events), display_events,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400535};
536
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500537static struct wl_display *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400538wl_display_create(void)
539{
540 struct wl_display *display;
541
542 display = malloc(sizeof *display);
543 if (display == NULL)
544 return NULL;
545
546 display->loop = wl_event_loop_create();
547 if (display->loop == NULL) {
548 free(display);
549 return NULL;
550 }
551
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400552 wl_list_init(&display->surface_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500553 wl_list_init(&display->client_list);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500554 wl_list_init(&display->global_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500555
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500556 display->pointer_x = 100;
557 display->pointer_y = 100;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400558
559 display->client_id_range = 256; /* Gah, arbitrary... */
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400560
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500561 display->id = 1;
562 display->base.interface = &display_interface;
563 wl_display_add_object(display, &display->base);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500564 if (wl_display_add_global(display, &display->base)) {
565 wl_event_loop_destroy(display->loop);
566 free(display);
567 return NULL;
568 }
569
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400570 return display;
571}
572
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500573WL_EXPORT void
574wl_display_add_object(struct wl_display *display, struct wl_object *object)
575{
576 object->id = display->id++;
577 wl_hash_insert(&display->objects, object);
578}
579
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500580WL_EXPORT int
581wl_display_add_global(struct wl_display *display, struct wl_object *object)
582{
583 struct wl_object_ref *ref;
584
585 ref = malloc(sizeof *ref);
586 if (ref == NULL)
587 return -1;
588
589 ref->object = object;
590 wl_list_insert(display->global_list.prev, &ref->link);
591
592 return 0;
593}
594
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500595static void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500596wl_display_send_event(struct wl_display *display, uint32_t *data, size_t size)
597{
598 struct wl_client *client;
599
600 client = container_of(display->client_list.next,
601 struct wl_client, link);
602 while (&client->link != &display->client_list) {
603 wl_connection_write(client->connection, data, size);
604
605 client = container_of(client->link.next,
606 struct wl_client, link);
607 }
608}
609
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500610#define WL_INPUT_MOTION 0
611#define WL_INPUT_BUTTON 1
612#define WL_INPUT_KEY 2
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500613
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500614WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500615wl_display_post_relative_event(struct wl_display *display,
616 struct wl_object *source, int dx, int dy)
617{
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500618 const struct wl_compositor_interface *interface;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500619 uint32_t p[4];
620
621 display->pointer_x += dx;
622 display->pointer_y += dy;
623
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500624 interface = display->compositor->interface;
625 interface->notify_pointer_motion(display->compositor, source,
626 display->pointer_x, display->pointer_y);
627
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500628 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500629 p[1] = (sizeof p << 16) | WL_INPUT_MOTION;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500630 p[2] = display->pointer_x;
631 p[3] = display->pointer_y;
632
633 wl_display_send_event(display, p, sizeof p);
634}
635
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500636WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500637wl_display_post_absolute_event(struct wl_display *display,
638 struct wl_object *source, int x, int y)
639{
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500640 const struct wl_compositor_interface *interface;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500641 uint32_t p[4];
642
643 display->pointer_x = x;
644 display->pointer_y = y;
645
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500646 interface = display->compositor->interface;
647 interface->notify_pointer_motion(display->compositor, source,
648 display->pointer_x, display->pointer_y);
649
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500650 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500651 p[1] = (sizeof p << 16) | WL_INPUT_MOTION;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500652 p[2] = display->pointer_x;
653 p[3] = display->pointer_y;
654
655 wl_display_send_event(display, p, sizeof p);
656}
657
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500658WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500659wl_display_post_button_event(struct wl_display *display,
660 struct wl_object *source, int button, int state)
661{
662 uint32_t p[4];
663
664 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500665 p[1] = (sizeof p << 16) | WL_INPUT_BUTTON;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500666 p[2] = button;
667 p[3] = state;
668
669 wl_display_send_event(display, p, sizeof p);
670}
671
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500672WL_EXPORT void
673wl_display_post_key_event(struct wl_display *display,
674 struct wl_object *source, int key, int state)
675{
676 const struct wl_compositor_interface *interface;
677 uint32_t p[4];
678
679 interface = display->compositor->interface;
680 interface->notify_key(display->compositor, source, key, state);
681
682 p[0] = source->id;
683 p[1] = (sizeof p << 16) | WL_INPUT_KEY;
684 p[2] = key;
685 p[3] = state;
686
687 wl_display_send_event(display, p, sizeof p);
688}
689
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500690void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400691wl_display_set_compositor(struct wl_display *display,
692 struct wl_compositor *compositor)
693{
694 display->compositor = compositor;
695}
696
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500697WL_EXPORT struct wl_event_loop *
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400698wl_display_get_event_loop(struct wl_display *display)
699{
700 return display->loop;
701}
702
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500703static void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400704wl_display_run(struct wl_display *display)
705{
706 while (1)
707 wl_event_loop_wait(display->loop);
708}
709
710/* The plan here is to generate a random anonymous socket name and
711 * advertise that through a service on the session dbus.
712 */
713static const char socket_name[] = "\0wayland";
714
715static void
716socket_data(int fd, uint32_t mask, void *data)
717{
718 struct wl_display *display = data;
719 struct sockaddr_un name;
720 socklen_t length;
721 int client_fd;
722
723 length = sizeof name;
724 client_fd = accept (fd, (struct sockaddr *) &name, &length);
725 if (client_fd < 0)
726 fprintf(stderr, "failed to accept\n");
727
728 wl_client_create(display, client_fd);
729}
730
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500731static int
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400732wl_display_add_socket(struct wl_display *display)
733{
734 struct sockaddr_un name;
735 int sock;
736 socklen_t size;
737
738 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
739 if (sock < 0)
740 return -1;
741
742 name.sun_family = AF_LOCAL;
743 memcpy(name.sun_path, socket_name, sizeof socket_name);
744
745 size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
746 if (bind(sock, (struct sockaddr *) &name, size) < 0)
747 return -1;
748
749 if (listen(sock, 1) < 0)
750 return -1;
751
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400752 wl_event_loop_add_fd(display->loop, sock,
753 WL_EVENT_READABLE,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400754 socket_data, display);
755
756 return 0;
757}
758
759
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400760struct wl_surface_iterator {
761 struct wl_list *head;
762 struct wl_surface *surface;
763 uint32_t mask;
764};
765
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500766WL_EXPORT struct wl_surface_iterator *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400767wl_surface_iterator_create(struct wl_display *display, uint32_t mask)
768{
769 struct wl_surface_iterator *iterator;
770
771 iterator = malloc(sizeof *iterator);
772 if (iterator == NULL)
773 return NULL;
774
775 iterator->head = &display->surface_list;
776 iterator->surface = container_of(display->surface_list.next,
777 struct wl_surface, link);
778 iterator->mask = mask;
779
780 return iterator;
781}
782
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500783WL_EXPORT int
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400784wl_surface_iterator_next(struct wl_surface_iterator *iterator,
785 struct wl_surface **surface)
786{
787 if (&iterator->surface->link == iterator->head)
788 return 0;
789
790 *surface = iterator->surface;
791 iterator->surface = container_of(iterator->surface->link.next,
792 struct wl_surface, link);
793
794 return 1;
795}
796
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500797WL_EXPORT void
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400798wl_surface_iterator_destroy(struct wl_surface_iterator *iterator)
799{
800 free(iterator);
801}
802
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500803static int
804load_compositor(struct wl_display *display, const char *path)
805{
806 struct wl_compositor *(*create)(struct wl_display *display);
807 struct wl_compositor *compositor;
808 void *p;
809
810 p = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
811 if (p == NULL) {
812 fprintf(stderr, "failed to open compositor %s: %s\n",
813 path, dlerror());
814 return -1;
815 }
816
817 create = dlsym(p, "wl_compositor_create");
818 if (create == NULL) {
819 fprintf(stderr, "failed to look up compositor constructor\n");
820 return -1;
821 }
822
823 compositor = create(display);
824 if (compositor == NULL) {
825 fprintf(stderr, "couldn't create compositor\n");
826 return -1;
827 }
828
829 wl_display_set_compositor(display, compositor);
830
831 return 0;
832}
833
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400834int main(int argc, char *argv[])
835{
836 struct wl_display *display;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500837 const char *compositor = "./egl-compositor.so";
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400838
839 display = wl_display_create();
840
841 if (wl_display_add_socket(display)) {
842 fprintf(stderr, "failed to add socket: %m\n");
843 exit(EXIT_FAILURE);
844 }
845
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500846 if (argc == 2)
847 compositor = argv[1];
848 load_compositor(display, compositor);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400849
850 wl_display_run(display);
851
852 return 0;
853}