blob: 5b883c901c965f6f670cdb8c1d88a2e7af1556b3 [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øgsberg97f1ebe2008-09-30 09:46:10 -0400318
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400319static void
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400320wl_client_connection_data(int fd, uint32_t mask, void *data)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400321{
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400322 struct wl_client *client = data;
323 struct wl_connection *connection = client->connection;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400324 const struct wl_method *method;
325 struct wl_object *object;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400326 uint32_t p[2], opcode, size;
327 uint32_t cmask = 0;
328 int len;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400329
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400330 if (mask & WL_EVENT_READABLE)
331 cmask |= WL_CONNECTION_READABLE;
332 if (mask & WL_EVENT_WRITEABLE)
333 cmask |= WL_CONNECTION_WRITABLE;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400334
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400335 len = wl_connection_data(connection, cmask);
336 if (len < 0) {
337 wl_client_destroy(client);
338 return;
339 }
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400340
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500341 while (len >= sizeof p) {
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400342 wl_connection_copy(connection, p, sizeof p);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400343 opcode = p[1] & 0xffff;
344 size = p[1] >> 16;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400345 if (len < size)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400346 break;
347
348 object = wl_hash_lookup(&client->display->objects,
349 p[0]);
350 if (object == NULL) {
351 wl_client_event(client, &client->display->base,
352 WL_DISPLAY_INVALID_OBJECT);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400353 wl_connection_consume(connection, size);
354 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400355 continue;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400356 }
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400357
358 if (opcode >= object->interface->method_count) {
359 wl_client_event(client, &client->display->base,
360 WL_DISPLAY_INVALID_METHOD);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400361 wl_connection_consume(connection, size);
362 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400363 continue;
364 }
365
366 method = &object->interface->methods[opcode];
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400367 wl_client_demarshal(client, object, method, size);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400368 wl_connection_consume(connection, size);
369 len -= size;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400370 }
371}
372
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400373static int
374wl_client_connection_update(struct wl_connection *connection,
375 uint32_t mask, void *data)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400376{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400377 struct wl_client *client = data;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400378 uint32_t emask = 0;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400379
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400380 if (mask & WL_CONNECTION_READABLE)
381 emask |= WL_EVENT_READABLE;
382 if (mask & WL_CONNECTION_WRITABLE)
383 emask |= WL_EVENT_WRITEABLE;
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400384
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400385 return wl_event_loop_update_source(client->display->loop,
386 client->source, mask);
387}
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400388
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400389static void
390advertise_object(struct wl_client *client, struct wl_object *object)
391{
392 const struct wl_interface *interface;
393 static const char pad[4];
394 uint32_t length, p[2];
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400395
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400396 interface = object->interface;
397 length = strlen(interface->name);
398 p[0] = object->id;
399 p[1] = length;
400 wl_connection_write(client->connection, p, sizeof p);
401 wl_connection_write(client->connection, interface->name, length);
402 wl_connection_write(client->connection, pad, -length & 3);
403}
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400404
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500405static struct wl_client *
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400406wl_client_create(struct wl_display *display, int fd)
407{
408 struct wl_client *client;
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500409 struct wl_object_ref *ref;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500410 uint32_t count;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400411
412 client = malloc(sizeof *client);
413 if (client == NULL)
414 return NULL;
415
416 memset(client, 0, sizeof *client);
417 client->display = display;
418 client->source = wl_event_loop_add_fd(display->loop, fd,
419 WL_EVENT_READABLE,
420 wl_client_connection_data, client);
421 client->connection = wl_connection_create(fd,
422 wl_client_connection_update,
423 client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400424 wl_list_init(&client->object_list);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400425
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400426 wl_connection_write(client->connection,
427 &display->client_id_range,
428 sizeof display->client_id_range);
429 display->client_id_range += 256;
430
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500431 /* Write list of global objects to client. */
432 count = wl_list_length(&display->global_list);
433 wl_connection_write(client->connection, &count, sizeof count);
434
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500435 ref = container_of(display->global_list.next,
436 struct wl_object_ref, link);
437 while (&ref->link != &display->global_list) {
438 advertise_object(client, ref->object);
439
440 ref = container_of(ref->link.next,
441 struct wl_object_ref, link);
442 }
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400443
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500444 wl_list_insert(display->client_list.prev, &client->link);
445
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400446 return client;
447}
448
449void
450wl_client_destroy(struct wl_client *client)
451{
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400452 struct wl_object_ref *ref;
453
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400454 printf("disconnect from client %p\n", client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400455
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500456 wl_list_remove(&client->link);
457
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400458 while (client->object_list.next != &client->object_list) {
459 ref = container_of(client->object_list.next,
460 struct wl_object_ref, link);
461 wl_list_remove(&ref->link);
462 wl_surface_destroy(client, (struct wl_surface *) ref->object);
463 free(ref);
464 }
465
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400466 wl_event_loop_remove_source(client->display->loop, client->source);
467 wl_connection_destroy(client->connection);
468 free(client);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400469}
470
471static int
472wl_display_create_surface(struct wl_client *client,
473 struct wl_display *display, uint32_t id)
474{
475 struct wl_surface *surface;
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400476 struct wl_object_ref *ref;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400477
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400478 surface = wl_surface_create(display, id);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400479
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400480 ref = malloc(sizeof *ref);
481 if (ref == NULL) {
482 wl_client_event(client, &display->base,
483 WL_DISPLAY_NO_MEMORY);
484 return -1;
485 }
486
487 ref->object = &surface->base;
488 wl_hash_insert(&display->objects, &surface->base);
489 wl_list_insert(client->object_list.prev, &ref->link);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400490
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400491 return 0;
492}
493
494static const struct wl_argument create_surface_arguments[] = {
495 { WL_ARGUMENT_NEW_ID }
496};
497
498static const struct wl_method display_methods[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400499 { "create_surface", wl_display_create_surface,
500 ARRAY_LENGTH(create_surface_arguments), create_surface_arguments },
501};
502
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400503static const struct wl_event display_events[] = {
504 { "invalid_object" },
505 { "invalid_method" },
506};
507
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400508static const struct wl_interface display_interface = {
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400509 "display", 1,
510 ARRAY_LENGTH(display_methods), display_methods,
511 ARRAY_LENGTH(display_events), display_events,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400512};
513
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500514static struct wl_display *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400515wl_display_create(void)
516{
517 struct wl_display *display;
518
519 display = malloc(sizeof *display);
520 if (display == NULL)
521 return NULL;
522
523 display->loop = wl_event_loop_create();
524 if (display->loop == NULL) {
525 free(display);
526 return NULL;
527 }
528
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400529 wl_list_init(&display->surface_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500530 wl_list_init(&display->client_list);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500531 wl_list_init(&display->global_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500532
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500533 display->pointer_x = 100;
534 display->pointer_y = 100;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400535
536 display->client_id_range = 256; /* Gah, arbitrary... */
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400537
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500538 display->id = 1;
539 display->base.interface = &display_interface;
540 wl_display_add_object(display, &display->base);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500541 if (wl_display_add_global(display, &display->base)) {
542 wl_event_loop_destroy(display->loop);
543 free(display);
544 return NULL;
545 }
546
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400547 return display;
548}
549
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500550WL_EXPORT void
551wl_display_add_object(struct wl_display *display, struct wl_object *object)
552{
553 object->id = display->id++;
554 wl_hash_insert(&display->objects, object);
555}
556
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500557WL_EXPORT int
558wl_display_add_global(struct wl_display *display, struct wl_object *object)
559{
560 struct wl_object_ref *ref;
561
562 ref = malloc(sizeof *ref);
563 if (ref == NULL)
564 return -1;
565
566 ref->object = object;
567 wl_list_insert(display->global_list.prev, &ref->link);
568
569 return 0;
570}
571
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500572static void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500573wl_display_send_event(struct wl_display *display, uint32_t *data, size_t size)
574{
575 struct wl_client *client;
576
577 client = container_of(display->client_list.next,
578 struct wl_client, link);
579 while (&client->link != &display->client_list) {
580 wl_connection_write(client->connection, data, size);
581
582 client = container_of(client->link.next,
583 struct wl_client, link);
584 }
585}
586
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500587#define WL_INPUT_MOTION 0
588#define WL_INPUT_BUTTON 1
589#define WL_INPUT_KEY 2
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500590
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500591WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500592wl_display_post_relative_event(struct wl_display *display,
593 struct wl_object *source, int dx, int dy)
594{
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500595 const struct wl_compositor_interface *interface;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500596 uint32_t p[4];
597
598 display->pointer_x += dx;
599 display->pointer_y += dy;
600
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500601 interface = display->compositor->interface;
602 interface->notify_pointer_motion(display->compositor, source,
603 display->pointer_x, display->pointer_y);
604
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500605 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500606 p[1] = (sizeof p << 16) | WL_INPUT_MOTION;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500607 p[2] = display->pointer_x;
608 p[3] = display->pointer_y;
609
610 wl_display_send_event(display, p, sizeof p);
611}
612
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500613WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500614wl_display_post_absolute_event(struct wl_display *display,
615 struct wl_object *source, int x, int y)
616{
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500617 const struct wl_compositor_interface *interface;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500618 uint32_t p[4];
619
620 display->pointer_x = x;
621 display->pointer_y = y;
622
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500623 interface = display->compositor->interface;
624 interface->notify_pointer_motion(display->compositor, source,
625 display->pointer_x, display->pointer_y);
626
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500627 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500628 p[1] = (sizeof p << 16) | WL_INPUT_MOTION;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500629 p[2] = display->pointer_x;
630 p[3] = display->pointer_y;
631
632 wl_display_send_event(display, p, sizeof p);
633}
634
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500635WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500636wl_display_post_button_event(struct wl_display *display,
637 struct wl_object *source, int button, int state)
638{
639 uint32_t p[4];
640
641 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500642 p[1] = (sizeof p << 16) | WL_INPUT_BUTTON;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500643 p[2] = button;
644 p[3] = state;
645
646 wl_display_send_event(display, p, sizeof p);
647}
648
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500649WL_EXPORT void
650wl_display_post_key_event(struct wl_display *display,
651 struct wl_object *source, int key, int state)
652{
653 const struct wl_compositor_interface *interface;
654 uint32_t p[4];
655
656 interface = display->compositor->interface;
657 interface->notify_key(display->compositor, source, key, state);
658
659 p[0] = source->id;
660 p[1] = (sizeof p << 16) | WL_INPUT_KEY;
661 p[2] = key;
662 p[3] = state;
663
664 wl_display_send_event(display, p, sizeof p);
665}
666
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500667void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400668wl_display_set_compositor(struct wl_display *display,
669 struct wl_compositor *compositor)
670{
671 display->compositor = compositor;
672}
673
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500674WL_EXPORT struct wl_event_loop *
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400675wl_display_get_event_loop(struct wl_display *display)
676{
677 return display->loop;
678}
679
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500680static void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400681wl_display_run(struct wl_display *display)
682{
683 while (1)
684 wl_event_loop_wait(display->loop);
685}
686
687/* The plan here is to generate a random anonymous socket name and
688 * advertise that through a service on the session dbus.
689 */
690static const char socket_name[] = "\0wayland";
691
692static void
693socket_data(int fd, uint32_t mask, void *data)
694{
695 struct wl_display *display = data;
696 struct sockaddr_un name;
697 socklen_t length;
698 int client_fd;
699
700 length = sizeof name;
701 client_fd = accept (fd, (struct sockaddr *) &name, &length);
702 if (client_fd < 0)
703 fprintf(stderr, "failed to accept\n");
704
705 wl_client_create(display, client_fd);
706}
707
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500708static int
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400709wl_display_add_socket(struct wl_display *display)
710{
711 struct sockaddr_un name;
712 int sock;
713 socklen_t size;
714
715 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
716 if (sock < 0)
717 return -1;
718
719 name.sun_family = AF_LOCAL;
720 memcpy(name.sun_path, socket_name, sizeof socket_name);
721
722 size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
723 if (bind(sock, (struct sockaddr *) &name, size) < 0)
724 return -1;
725
726 if (listen(sock, 1) < 0)
727 return -1;
728
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400729 wl_event_loop_add_fd(display->loop, sock,
730 WL_EVENT_READABLE,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400731 socket_data, display);
732
733 return 0;
734}
735
736
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400737struct wl_surface_iterator {
738 struct wl_list *head;
739 struct wl_surface *surface;
740 uint32_t mask;
741};
742
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500743WL_EXPORT struct wl_surface_iterator *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400744wl_surface_iterator_create(struct wl_display *display, uint32_t mask)
745{
746 struct wl_surface_iterator *iterator;
747
748 iterator = malloc(sizeof *iterator);
749 if (iterator == NULL)
750 return NULL;
751
752 iterator->head = &display->surface_list;
753 iterator->surface = container_of(display->surface_list.next,
754 struct wl_surface, link);
755 iterator->mask = mask;
756
757 return iterator;
758}
759
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500760WL_EXPORT int
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400761wl_surface_iterator_next(struct wl_surface_iterator *iterator,
762 struct wl_surface **surface)
763{
764 if (&iterator->surface->link == iterator->head)
765 return 0;
766
767 *surface = iterator->surface;
768 iterator->surface = container_of(iterator->surface->link.next,
769 struct wl_surface, link);
770
771 return 1;
772}
773
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500774WL_EXPORT void
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400775wl_surface_iterator_destroy(struct wl_surface_iterator *iterator)
776{
777 free(iterator);
778}
779
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500780static int
781load_compositor(struct wl_display *display, const char *path)
782{
783 struct wl_compositor *(*create)(struct wl_display *display);
784 struct wl_compositor *compositor;
785 void *p;
786
787 p = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
788 if (p == NULL) {
789 fprintf(stderr, "failed to open compositor %s: %s\n",
790 path, dlerror());
791 return -1;
792 }
793
794 create = dlsym(p, "wl_compositor_create");
795 if (create == NULL) {
796 fprintf(stderr, "failed to look up compositor constructor\n");
797 return -1;
798 }
799
800 compositor = create(display);
801 if (compositor == NULL) {
802 fprintf(stderr, "couldn't create compositor\n");
803 return -1;
804 }
805
806 wl_display_set_compositor(display, compositor);
807
808 return 0;
809}
810
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400811int main(int argc, char *argv[])
812{
813 struct wl_display *display;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500814 const char *compositor = "./egl-compositor.so";
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400815
816 display = wl_display_create();
817
818 if (wl_display_add_socket(display)) {
819 fprintf(stderr, "failed to add socket: %m\n");
820 exit(EXIT_FAILURE);
821 }
822
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500823 if (argc == 2)
824 compositor = argv[1];
825 load_compositor(display, compositor);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400826
827 wl_display_run(display);
828
829 return 0;
830}