blob: 7803f3d09aaa370a9523972b459d247d85ef4fbd [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øgsbergfbdbbdc2008-11-28 17:06:06 -050022 uint32_t pending_frame;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040023};
24
25struct wl_display {
26 struct wl_object base;
27 struct wl_event_loop *loop;
28 struct wl_hash objects;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040029
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050030 struct wl_object *pointer;
31
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040032 struct wl_compositor *compositor;
33 struct wl_compositor_interface *compositor_interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040034
35 struct wl_list surface_list;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050036 struct wl_list client_list;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040037 uint32_t client_id_range;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -050038 uint32_t id;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050039
Kristian Høgsberg14fcff72008-11-23 19:10:23 -050040 struct wl_list global_list;
41
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050042 int32_t pointer_x;
43 int32_t pointer_y;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040044};
45
46struct wl_surface {
47 struct wl_object base;
48
49 /* provided by client */
50 int width, height;
51 int buffer;
52 int stride;
53
Kristian Høgsberg05eff512008-10-07 10:10:36 -040054 struct wl_map map;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040055 struct wl_list link;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040056
57 /* how to convert buffer contents to pixels in screen format;
58 * yuv->rgb, indexed->rgb, svg->rgb, but mostly just rgb->rgb. */
59
60 /* how to transform/render rectangular contents to polygons. */
Kristian Høgsberg05eff512008-10-07 10:10:36 -040061
62 void *compositor_data;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040063};
64
Kristian Høgsberg94a2e862008-10-11 21:37:55 -040065struct wl_object_ref {
66 struct wl_object *object;
67 struct wl_list link;
68};
Kristian Høgsberg05eff512008-10-07 10:10:36 -040069
70static void
71wl_surface_destroy(struct wl_client *client,
72 struct wl_surface *surface)
73{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -050074 const struct wl_compositor_interface *interface;
Kristian Høgsberg05eff512008-10-07 10:10:36 -040075
76 interface = client->display->compositor->interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040077 interface->notify_surface_destroy(client->display->compositor,
78 surface);
79 wl_list_remove(&surface->link);
Kristian Høgsberg05eff512008-10-07 10:10:36 -040080}
81
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040082static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040083wl_surface_attach(struct wl_client *client,
84 struct wl_surface *surface, uint32_t name,
85 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040086{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -050087 const struct wl_compositor_interface *interface;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040088
89 interface = client->display->compositor->interface;
90 interface->notify_surface_attach(client->display->compositor,
91 surface, name, width, height, stride);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040092}
93
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040094static const struct wl_argument attach_arguments[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040095 { WL_ARGUMENT_UINT32 },
96 { WL_ARGUMENT_UINT32 },
97 { WL_ARGUMENT_UINT32 },
98 { WL_ARGUMENT_UINT32 },
99};
100
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500101static void
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400102wl_surface_map(struct wl_client *client, struct wl_surface *surface,
103 int32_t x, int32_t y, int32_t width, int32_t height)
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øgsberg05eff512008-10-07 10:10:36 -0400106
107 /* FIXME: This needs to take a tri-mesh argument... - count
108 * and a list of tris. 0 tris means unmap. */
109
110 surface->map.x = x;
111 surface->map.y = y;
112 surface->map.width = width;
113 surface->map.height = height;
114
115 interface = client->display->compositor->interface;
116 interface->notify_surface_map(client->display->compositor,
117 surface, &surface->map);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400118}
119
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400120static const struct wl_argument map_arguments[] = {
121 { WL_ARGUMENT_UINT32 },
122 { WL_ARGUMENT_UINT32 },
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400123 { WL_ARGUMENT_UINT32 },
124 { WL_ARGUMENT_UINT32 },
125};
126
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500127static void
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500128wl_surface_copy(struct wl_client *client, struct wl_surface *surface,
129 int32_t dst_x, int32_t dst_y, uint32_t name, uint32_t stride,
130 int32_t x, int32_t y, int32_t width, int32_t height)
131{
132 const struct wl_compositor_interface *interface;
133
134 interface = client->display->compositor->interface;
135 interface->notify_surface_copy(client->display->compositor,
136 surface, dst_x, dst_y,
137 name, stride, x, y, width, height);
138}
139
140static const struct wl_argument copy_arguments[] = {
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 { WL_ARGUMENT_UINT32 },
151};
152
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500153static void
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500154wl_surface_damage(struct wl_client *client, struct wl_surface *surface,
155 int32_t x, int32_t y, int32_t width, int32_t height)
156{
157 const struct wl_compositor_interface *interface;
158
159 interface = client->display->compositor->interface;
160 interface->notify_surface_damage(client->display->compositor,
161 surface, x, y, width, height);
162}
163
164static const struct wl_argument damage_arguments[] = {
165 { WL_ARGUMENT_UINT32 },
166 { WL_ARGUMENT_UINT32 },
167 { WL_ARGUMENT_UINT32 },
168 { WL_ARGUMENT_UINT32 },
169};
170
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400171static const struct wl_method surface_methods[] = {
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400172 { "destroy", wl_surface_destroy,
173 0, NULL },
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400174 { "attach", wl_surface_attach,
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400175 ARRAY_LENGTH(attach_arguments), attach_arguments },
176 { "map", wl_surface_map,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500177 ARRAY_LENGTH(map_arguments), map_arguments },
178 { "copy", wl_surface_copy,
179 ARRAY_LENGTH(copy_arguments), copy_arguments },
180 { "damage", wl_surface_damage,
181 ARRAY_LENGTH(damage_arguments), damage_arguments }
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400182};
183
184static const struct wl_interface surface_interface = {
185 "surface", 1,
186 ARRAY_LENGTH(surface_methods),
187 surface_methods,
188};
189
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500190static struct wl_surface *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400191wl_surface_create(struct wl_display *display, uint32_t id)
192{
193 struct wl_surface *surface;
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500194 const struct wl_compositor_interface *interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400195
196 surface = malloc(sizeof *surface);
197 if (surface == NULL)
198 return NULL;
199
200 surface->base.id = id;
201 surface->base.interface = &surface_interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400202
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400203 wl_list_insert(display->surface_list.prev, &surface->link);
204
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400205 interface = display->compositor->interface;
206 interface->notify_surface_create(display->compositor, surface);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400207
208 return surface;
209}
210
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500211WL_EXPORT void
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400212wl_surface_set_data(struct wl_surface *surface, void *data)
213{
214 surface->compositor_data = data;
215}
216
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500217WL_EXPORT void *
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400218wl_surface_get_data(struct wl_surface *surface)
219{
220 return surface->compositor_data;
221}
222
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400223void
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400224wl_client_destroy(struct wl_client *client);
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400225
226static void
227wl_client_demarshal(struct wl_client *client, struct wl_object *target,
228 const struct wl_method *method, size_t size)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400229{
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500230 ffi_type *types[20];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400231 ffi_cif cif;
232 uint32_t *p, result;
233 int i;
234 union {
235 uint32_t uint32;
236 const char *string;
237 void *object;
238 uint32_t new_id;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500239 } values[20];
240 void *args[20];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400241 struct wl_object *object;
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400242 uint32_t data[64];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400243
244 if (method->argument_count > ARRAY_LENGTH(types)) {
245 printf("too many args (%d)\n", method->argument_count);
246 return;
247 }
248
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400249 if (sizeof data < size) {
250 printf("request too big, should malloc tmp buffer here\n");
251 return;
252 }
253
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400254 types[0] = &ffi_type_pointer;
255 values[0].object = client;
256 args[0] = &values[0];
257
258 types[1] = &ffi_type_pointer;
259 values[1].object = target;
260 args[1] = &values[1];
261
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400262 wl_connection_copy(client->connection, data, size);
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400263 p = &data[2];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400264 for (i = 0; i < method->argument_count; i++) {
265 switch (method->arguments[i].type) {
266 case WL_ARGUMENT_UINT32:
267 types[i + 2] = &ffi_type_uint32;
268 values[i + 2].uint32 = *p;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400269 p++;
270 break;
271 case WL_ARGUMENT_STRING:
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400272 types[i + 2] = &ffi_type_pointer;
273 /* FIXME */
274 values[i + 2].uint32 = *p++;
275 break;
276 case WL_ARGUMENT_OBJECT:
277 types[i + 2] = &ffi_type_pointer;
278 object = wl_hash_lookup(&client->display->objects, *p);
279 if (object == NULL)
280 printf("unknown object (%d)\n", *p);
281 if (object->interface != method->arguments[i].data)
282 printf("wrong object type\n");
283 values[i + 2].object = object;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400284 p++;
285 break;
286 case WL_ARGUMENT_NEW_ID:
287 types[i + 2] = &ffi_type_uint32;
288 values[i + 2].new_id = *p;
289 object = wl_hash_lookup(&client->display->objects, *p);
290 if (object != NULL)
291 printf("object already exists (%d)\n", *p);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400292 p++;
293 break;
294 default:
295 printf("unknown type\n");
296 break;
297 }
298 args[i + 2] = &values[i + 2];
299 }
300
301 ffi_prep_cif(&cif, FFI_DEFAULT_ABI, method->argument_count + 2,
302 &ffi_type_uint32, types);
303 ffi_call(&cif, FFI_FN(method->func), &result, args);
304}
305
306static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400307wl_client_event(struct wl_client *client, struct wl_object *object, uint32_t event)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400308{
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400309 uint32_t p[2];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400310
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400311 p[0] = object->id;
312 p[1] = event | (8 << 16);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400313 wl_connection_write(client->connection, p, sizeof p);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400314}
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400315
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400316#define WL_DISPLAY_INVALID_OBJECT 0
317#define WL_DISPLAY_INVALID_METHOD 1
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400318#define WL_DISPLAY_NO_MEMORY 2
Kristian Høgsberg40979232008-11-25 22:40:39 -0500319#define WL_DISPLAY_ACKNOWLEDGE 3
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500320#define WL_DISPLAY_FRAME 4
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400321
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400322static void
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400323wl_client_connection_data(int fd, uint32_t mask, void *data)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400324{
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400325 struct wl_client *client = data;
326 struct wl_connection *connection = client->connection;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400327 const struct wl_method *method;
328 struct wl_object *object;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400329 uint32_t p[2], opcode, size;
330 uint32_t cmask = 0;
331 int len;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400332
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400333 if (mask & WL_EVENT_READABLE)
334 cmask |= WL_CONNECTION_READABLE;
335 if (mask & WL_EVENT_WRITEABLE)
336 cmask |= WL_CONNECTION_WRITABLE;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400337
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400338 len = wl_connection_data(connection, cmask);
339 if (len < 0) {
340 wl_client_destroy(client);
341 return;
342 }
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400343
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500344 while (len >= sizeof p) {
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400345 wl_connection_copy(connection, p, sizeof p);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400346 opcode = p[1] & 0xffff;
347 size = p[1] >> 16;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400348 if (len < size)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400349 break;
350
351 object = wl_hash_lookup(&client->display->objects,
352 p[0]);
353 if (object == NULL) {
354 wl_client_event(client, &client->display->base,
355 WL_DISPLAY_INVALID_OBJECT);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400356 wl_connection_consume(connection, size);
357 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400358 continue;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400359 }
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400360
361 if (opcode >= object->interface->method_count) {
362 wl_client_event(client, &client->display->base,
363 WL_DISPLAY_INVALID_METHOD);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400364 wl_connection_consume(connection, size);
365 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400366 continue;
367 }
368
369 method = &object->interface->methods[opcode];
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400370 wl_client_demarshal(client, object, method, size);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400371 wl_connection_consume(connection, size);
372 len -= size;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400373 }
374}
375
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400376static int
377wl_client_connection_update(struct wl_connection *connection,
378 uint32_t mask, void *data)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400379{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400380 struct wl_client *client = data;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400381 uint32_t emask = 0;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400382
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400383 if (mask & WL_CONNECTION_READABLE)
384 emask |= WL_EVENT_READABLE;
385 if (mask & WL_CONNECTION_WRITABLE)
386 emask |= WL_EVENT_WRITEABLE;
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400387
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400388 return wl_event_loop_update_source(client->display->loop,
389 client->source, mask);
390}
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400391
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400392static void
393advertise_object(struct wl_client *client, struct wl_object *object)
394{
395 const struct wl_interface *interface;
396 static const char pad[4];
397 uint32_t length, p[2];
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400398
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400399 interface = object->interface;
400 length = strlen(interface->name);
401 p[0] = object->id;
402 p[1] = length;
403 wl_connection_write(client->connection, p, sizeof p);
404 wl_connection_write(client->connection, interface->name, length);
405 wl_connection_write(client->connection, pad, -length & 3);
406}
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400407
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500408static struct wl_client *
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400409wl_client_create(struct wl_display *display, int fd)
410{
411 struct wl_client *client;
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500412 struct wl_object_ref *ref;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500413 uint32_t count;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400414
415 client = malloc(sizeof *client);
416 if (client == NULL)
417 return NULL;
418
419 memset(client, 0, sizeof *client);
420 client->display = display;
421 client->source = wl_event_loop_add_fd(display->loop, fd,
422 WL_EVENT_READABLE,
423 wl_client_connection_data, client);
424 client->connection = wl_connection_create(fd,
425 wl_client_connection_update,
426 client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400427 wl_list_init(&client->object_list);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400428
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400429 wl_connection_write(client->connection,
430 &display->client_id_range,
431 sizeof display->client_id_range);
432 display->client_id_range += 256;
433
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500434 /* Write list of global objects to client. */
435 count = wl_list_length(&display->global_list);
436 wl_connection_write(client->connection, &count, sizeof count);
437
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500438 ref = container_of(display->global_list.next,
439 struct wl_object_ref, link);
440 while (&ref->link != &display->global_list) {
441 advertise_object(client, ref->object);
442
443 ref = container_of(ref->link.next,
444 struct wl_object_ref, link);
445 }
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400446
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500447 wl_list_insert(display->client_list.prev, &client->link);
448
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400449 return client;
450}
451
452void
453wl_client_destroy(struct wl_client *client)
454{
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400455 struct wl_object_ref *ref;
456
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400457 printf("disconnect from client %p\n", client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400458
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500459 wl_list_remove(&client->link);
460
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400461 while (client->object_list.next != &client->object_list) {
462 ref = container_of(client->object_list.next,
463 struct wl_object_ref, link);
464 wl_list_remove(&ref->link);
465 wl_surface_destroy(client, (struct wl_surface *) ref->object);
466 free(ref);
467 }
468
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400469 wl_event_loop_remove_source(client->display->loop, client->source);
470 wl_connection_destroy(client->connection);
471 free(client);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400472}
473
474static int
475wl_display_create_surface(struct wl_client *client,
476 struct wl_display *display, uint32_t id)
477{
478 struct wl_surface *surface;
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400479 struct wl_object_ref *ref;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400480
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400481 surface = wl_surface_create(display, id);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400482
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400483 ref = malloc(sizeof *ref);
484 if (ref == NULL) {
485 wl_client_event(client, &display->base,
486 WL_DISPLAY_NO_MEMORY);
487 return -1;
488 }
489
490 ref->object = &surface->base;
491 wl_hash_insert(&display->objects, &surface->base);
492 wl_list_insert(client->object_list.prev, &ref->link);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400493
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400494 return 0;
495}
496
497static const struct wl_argument create_surface_arguments[] = {
498 { WL_ARGUMENT_NEW_ID }
499};
500
Kristian Høgsberg40979232008-11-25 22:40:39 -0500501static int
502wl_display_commit(struct wl_client *client,
503 struct wl_display *display, uint32_t key)
504{
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500505 const struct wl_compositor_interface *interface;
506 uint32_t frame, event[4];
507
508 client->pending_frame = 1;
509
510 interface = display->compositor->interface;
511 frame = interface->notify_commit(display->compositor);
512
513 event[0] = display->base.id;
514 event[1] = WL_DISPLAY_ACKNOWLEDGE | ((sizeof event) << 16);
515 event[2] = key;
516 event[3] = frame;
517
518 wl_connection_write(client->connection, event, sizeof event);
Kristian Høgsberg40979232008-11-25 22:40:39 -0500519
520 return 0;
521}
522
523static const struct wl_argument commit_arguments[] = {
524 { WL_ARGUMENT_UINT32 }
525};
526
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400527static const struct wl_method display_methods[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400528 { "create_surface", wl_display_create_surface,
529 ARRAY_LENGTH(create_surface_arguments), create_surface_arguments },
Kristian Høgsberg40979232008-11-25 22:40:39 -0500530 { "commit", wl_display_commit,
531 ARRAY_LENGTH(commit_arguments), commit_arguments },
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400532};
533
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400534static const struct wl_event display_events[] = {
535 { "invalid_object" },
536 { "invalid_method" },
Kristian Høgsberg40979232008-11-25 22:40:39 -0500537 { "no_memory" },
538 { "acknowledge" },
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400539};
540
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400541static const struct wl_interface display_interface = {
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400542 "display", 1,
543 ARRAY_LENGTH(display_methods), display_methods,
544 ARRAY_LENGTH(display_events), display_events,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400545};
546
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500547static struct wl_display *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400548wl_display_create(void)
549{
550 struct wl_display *display;
551
552 display = malloc(sizeof *display);
553 if (display == NULL)
554 return NULL;
555
556 display->loop = wl_event_loop_create();
557 if (display->loop == NULL) {
558 free(display);
559 return NULL;
560 }
561
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400562 wl_list_init(&display->surface_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500563 wl_list_init(&display->client_list);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500564 wl_list_init(&display->global_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500565
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500566 display->pointer_x = 100;
567 display->pointer_y = 100;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400568
569 display->client_id_range = 256; /* Gah, arbitrary... */
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400570
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500571 display->id = 1;
572 display->base.interface = &display_interface;
573 wl_display_add_object(display, &display->base);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500574 if (wl_display_add_global(display, &display->base)) {
575 wl_event_loop_destroy(display->loop);
576 free(display);
577 return NULL;
578 }
579
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400580 return display;
581}
582
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500583WL_EXPORT void
584wl_display_add_object(struct wl_display *display, struct wl_object *object)
585{
586 object->id = display->id++;
587 wl_hash_insert(&display->objects, object);
588}
589
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500590WL_EXPORT int
591wl_display_add_global(struct wl_display *display, struct wl_object *object)
592{
593 struct wl_object_ref *ref;
594
595 ref = malloc(sizeof *ref);
596 if (ref == NULL)
597 return -1;
598
599 ref->object = object;
600 wl_list_insert(display->global_list.prev, &ref->link);
601
602 return 0;
603}
604
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500605static void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500606wl_display_send_event(struct wl_display *display, uint32_t *data, size_t size)
607{
608 struct wl_client *client;
609
610 client = container_of(display->client_list.next,
611 struct wl_client, link);
612 while (&client->link != &display->client_list) {
613 wl_connection_write(client->connection, data, size);
614
615 client = container_of(client->link.next,
616 struct wl_client, link);
617 }
618}
619
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500620#define WL_INPUT_MOTION 0
621#define WL_INPUT_BUTTON 1
622#define WL_INPUT_KEY 2
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500623
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500624WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500625wl_display_post_relative_event(struct wl_display *display,
626 struct wl_object *source, int dx, int dy)
627{
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500628 const struct wl_compositor_interface *interface;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500629 uint32_t p[4];
630
631 display->pointer_x += dx;
632 display->pointer_y += dy;
633
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500634 interface = display->compositor->interface;
635 interface->notify_pointer_motion(display->compositor, source,
636 display->pointer_x, display->pointer_y);
637
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500638 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500639 p[1] = (sizeof p << 16) | WL_INPUT_MOTION;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500640 p[2] = display->pointer_x;
641 p[3] = display->pointer_y;
642
643 wl_display_send_event(display, p, sizeof p);
644}
645
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500646WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500647wl_display_post_absolute_event(struct wl_display *display,
648 struct wl_object *source, int x, int y)
649{
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500650 const struct wl_compositor_interface *interface;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500651 uint32_t p[4];
652
653 display->pointer_x = x;
654 display->pointer_y = y;
655
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500656 interface = display->compositor->interface;
657 interface->notify_pointer_motion(display->compositor, source,
658 display->pointer_x, display->pointer_y);
659
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500660 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500661 p[1] = (sizeof p << 16) | WL_INPUT_MOTION;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500662 p[2] = display->pointer_x;
663 p[3] = display->pointer_y;
664
665 wl_display_send_event(display, p, sizeof p);
666}
667
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500668WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500669wl_display_post_button_event(struct wl_display *display,
670 struct wl_object *source, int button, int state)
671{
672 uint32_t p[4];
673
674 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500675 p[1] = (sizeof p << 16) | WL_INPUT_BUTTON;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500676 p[2] = button;
677 p[3] = state;
678
679 wl_display_send_event(display, p, sizeof p);
680}
681
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500682WL_EXPORT void
683wl_display_post_key_event(struct wl_display *display,
684 struct wl_object *source, int key, int state)
685{
686 const struct wl_compositor_interface *interface;
687 uint32_t p[4];
688
689 interface = display->compositor->interface;
690 interface->notify_key(display->compositor, source, key, state);
691
692 p[0] = source->id;
693 p[1] = (sizeof p << 16) | WL_INPUT_KEY;
694 p[2] = key;
695 p[3] = state;
696
697 wl_display_send_event(display, p, sizeof p);
698}
699
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500700WL_EXPORT void
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500701wl_display_post_frame(struct wl_display *display,
702 uint32_t frame, uint32_t msecs)
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500703{
704 struct wl_client *client;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500705 uint32_t event[4];
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500706
707 event[0] = display->base.id;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500708 event[1] = WL_DISPLAY_FRAME | ((sizeof event) << 16);
709 event[2] = frame;
710 event[3] = msecs;
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500711
712 client = container_of(display->client_list.next,
713 struct wl_client, link);
714
715 while (&client->link != &display->client_list) {
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500716 if (client->pending_frame) {
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500717 wl_connection_write(client->connection,
718 event, sizeof event);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500719 client->pending_frame = 0;
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500720 }
721 client = container_of(client->link.next,
722 struct wl_client, link);
723 }
724}
725
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500726void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400727wl_display_set_compositor(struct wl_display *display,
728 struct wl_compositor *compositor)
729{
730 display->compositor = compositor;
731}
732
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500733WL_EXPORT struct wl_event_loop *
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400734wl_display_get_event_loop(struct wl_display *display)
735{
736 return display->loop;
737}
738
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500739static void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400740wl_display_run(struct wl_display *display)
741{
742 while (1)
743 wl_event_loop_wait(display->loop);
744}
745
746/* The plan here is to generate a random anonymous socket name and
747 * advertise that through a service on the session dbus.
748 */
749static const char socket_name[] = "\0wayland";
750
751static void
752socket_data(int fd, uint32_t mask, void *data)
753{
754 struct wl_display *display = data;
755 struct sockaddr_un name;
756 socklen_t length;
757 int client_fd;
758
759 length = sizeof name;
760 client_fd = accept (fd, (struct sockaddr *) &name, &length);
761 if (client_fd < 0)
762 fprintf(stderr, "failed to accept\n");
763
764 wl_client_create(display, client_fd);
765}
766
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500767static int
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400768wl_display_add_socket(struct wl_display *display)
769{
770 struct sockaddr_un name;
771 int sock;
772 socklen_t size;
773
774 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
775 if (sock < 0)
776 return -1;
777
778 name.sun_family = AF_LOCAL;
779 memcpy(name.sun_path, socket_name, sizeof socket_name);
780
781 size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
782 if (bind(sock, (struct sockaddr *) &name, size) < 0)
783 return -1;
784
785 if (listen(sock, 1) < 0)
786 return -1;
787
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400788 wl_event_loop_add_fd(display->loop, sock,
789 WL_EVENT_READABLE,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400790 socket_data, display);
791
792 return 0;
793}
794
795
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400796struct wl_surface_iterator {
797 struct wl_list *head;
798 struct wl_surface *surface;
799 uint32_t mask;
800};
801
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500802WL_EXPORT struct wl_surface_iterator *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400803wl_surface_iterator_create(struct wl_display *display, uint32_t mask)
804{
805 struct wl_surface_iterator *iterator;
806
807 iterator = malloc(sizeof *iterator);
808 if (iterator == NULL)
809 return NULL;
810
811 iterator->head = &display->surface_list;
812 iterator->surface = container_of(display->surface_list.next,
813 struct wl_surface, link);
814 iterator->mask = mask;
815
816 return iterator;
817}
818
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500819WL_EXPORT int
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400820wl_surface_iterator_next(struct wl_surface_iterator *iterator,
821 struct wl_surface **surface)
822{
823 if (&iterator->surface->link == iterator->head)
824 return 0;
825
826 *surface = iterator->surface;
827 iterator->surface = container_of(iterator->surface->link.next,
828 struct wl_surface, link);
829
830 return 1;
831}
832
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500833WL_EXPORT void
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400834wl_surface_iterator_destroy(struct wl_surface_iterator *iterator)
835{
836 free(iterator);
837}
838
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500839static int
840load_compositor(struct wl_display *display, const char *path)
841{
842 struct wl_compositor *(*create)(struct wl_display *display);
843 struct wl_compositor *compositor;
844 void *p;
845
846 p = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
847 if (p == NULL) {
848 fprintf(stderr, "failed to open compositor %s: %s\n",
849 path, dlerror());
850 return -1;
851 }
852
853 create = dlsym(p, "wl_compositor_create");
854 if (create == NULL) {
855 fprintf(stderr, "failed to look up compositor constructor\n");
856 return -1;
857 }
858
859 compositor = create(display);
860 if (compositor == NULL) {
861 fprintf(stderr, "couldn't create compositor\n");
862 return -1;
863 }
864
865 wl_display_set_compositor(display, compositor);
866
867 return 0;
868}
869
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400870int main(int argc, char *argv[])
871{
872 struct wl_display *display;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500873 const char *compositor = "./egl-compositor.so";
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400874
875 display = wl_display_create();
876
877 if (wl_display_add_socket(display)) {
878 fprintf(stderr, "failed to add socket: %m\n");
879 exit(EXIT_FAILURE);
880 }
881
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500882 if (argc == 2)
883 compositor = argv[1];
884 load_compositor(display, compositor);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400885
886 wl_display_run(display);
887
888 return 0;
889}