blob: 563956436e49443bb6a46696966304df3715f0a1 [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øgsbergf9bc7952008-11-02 10:12:29 -0500514static const char input_device_file[] =
515 "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-mouse";
516
517static void
518wl_display_create_input_devices(struct wl_display *display)
519{
Kristian Høgsberg33a52bd2008-11-03 15:31:30 -0500520 const char *path;
521
522 path = getenv("WAYLAND_POINTER");
523 if (path == NULL)
524 path = input_device_file;
525
526 display->pointer = wl_input_device_create(display, path, 1);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500527
528 if (display->pointer != NULL)
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500529 wl_display_add_object(display, display->pointer);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500530
531 display->pointer_x = 100;
532 display->pointer_y = 100;
533}
534
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500535static struct wl_display *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400536wl_display_create(void)
537{
538 struct wl_display *display;
539
540 display = malloc(sizeof *display);
541 if (display == NULL)
542 return NULL;
543
544 display->loop = wl_event_loop_create();
545 if (display->loop == NULL) {
546 free(display);
547 return NULL;
548 }
549
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400550 wl_list_init(&display->surface_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500551 wl_list_init(&display->client_list);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500552 wl_list_init(&display->global_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500553
554 wl_display_create_input_devices(display);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400555
556 display->client_id_range = 256; /* Gah, arbitrary... */
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400557
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500558 display->id = 1;
559 display->base.interface = &display_interface;
560 wl_display_add_object(display, &display->base);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500561 if (wl_display_add_global(display, &display->base)) {
562 wl_event_loop_destroy(display->loop);
563 free(display);
564 return NULL;
565 }
566
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400567 return display;
568}
569
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500570WL_EXPORT void
571wl_display_add_object(struct wl_display *display, struct wl_object *object)
572{
573 object->id = display->id++;
574 wl_hash_insert(&display->objects, object);
575}
576
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500577WL_EXPORT int
578wl_display_add_global(struct wl_display *display, struct wl_object *object)
579{
580 struct wl_object_ref *ref;
581
582 ref = malloc(sizeof *ref);
583 if (ref == NULL)
584 return -1;
585
586 ref->object = object;
587 wl_list_insert(display->global_list.prev, &ref->link);
588
589 return 0;
590}
591
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500592static void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500593wl_display_send_event(struct wl_display *display, uint32_t *data, size_t size)
594{
595 struct wl_client *client;
596
597 client = container_of(display->client_list.next,
598 struct wl_client, link);
599 while (&client->link != &display->client_list) {
600 wl_connection_write(client->connection, data, size);
601
602 client = container_of(client->link.next,
603 struct wl_client, link);
604 }
605}
606
607#define WL_POINTER_MOTION 0
608#define WL_POINTER_BUTTON 1
609
610void
611wl_display_post_relative_event(struct wl_display *display,
612 struct wl_object *source, int dx, int dy)
613{
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500614 const struct wl_compositor_interface *interface;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500615 uint32_t p[4];
616
617 display->pointer_x += dx;
618 display->pointer_y += dy;
619
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500620 interface = display->compositor->interface;
621 interface->notify_pointer_motion(display->compositor, source,
622 display->pointer_x, display->pointer_y);
623
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500624 p[0] = source->id;
625 p[1] = (sizeof p << 16) | WL_POINTER_MOTION;
626 p[2] = display->pointer_x;
627 p[3] = display->pointer_y;
628
629 wl_display_send_event(display, p, sizeof p);
630}
631
632void
633wl_display_post_absolute_event(struct wl_display *display,
634 struct wl_object *source, int x, int y)
635{
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500636 const struct wl_compositor_interface *interface;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500637 uint32_t p[4];
638
639 display->pointer_x = x;
640 display->pointer_y = y;
641
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500642 interface = display->compositor->interface;
643 interface->notify_pointer_motion(display->compositor, source,
644 display->pointer_x, display->pointer_y);
645
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500646 p[0] = source->id;
647 p[1] = (sizeof p << 16) | WL_POINTER_MOTION;
648 p[2] = display->pointer_x;
649 p[3] = display->pointer_y;
650
651 wl_display_send_event(display, p, sizeof p);
652}
653
654void
655wl_display_post_button_event(struct wl_display *display,
656 struct wl_object *source, int button, int state)
657{
658 uint32_t p[4];
659
660 p[0] = source->id;
661 p[1] = (sizeof p << 16) | WL_POINTER_BUTTON;
662 p[2] = button;
663 p[3] = state;
664
665 wl_display_send_event(display, p, sizeof p);
666}
667
668void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400669wl_display_set_compositor(struct wl_display *display,
670 struct wl_compositor *compositor)
671{
672 display->compositor = compositor;
673}
674
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500675WL_EXPORT struct wl_event_loop *
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400676wl_display_get_event_loop(struct wl_display *display)
677{
678 return display->loop;
679}
680
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500681static void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400682wl_display_run(struct wl_display *display)
683{
684 while (1)
685 wl_event_loop_wait(display->loop);
686}
687
688/* The plan here is to generate a random anonymous socket name and
689 * advertise that through a service on the session dbus.
690 */
691static const char socket_name[] = "\0wayland";
692
693static void
694socket_data(int fd, uint32_t mask, void *data)
695{
696 struct wl_display *display = data;
697 struct sockaddr_un name;
698 socklen_t length;
699 int client_fd;
700
701 length = sizeof name;
702 client_fd = accept (fd, (struct sockaddr *) &name, &length);
703 if (client_fd < 0)
704 fprintf(stderr, "failed to accept\n");
705
706 wl_client_create(display, client_fd);
707}
708
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500709static int
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400710wl_display_add_socket(struct wl_display *display)
711{
712 struct sockaddr_un name;
713 int sock;
714 socklen_t size;
715
716 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
717 if (sock < 0)
718 return -1;
719
720 name.sun_family = AF_LOCAL;
721 memcpy(name.sun_path, socket_name, sizeof socket_name);
722
723 size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
724 if (bind(sock, (struct sockaddr *) &name, size) < 0)
725 return -1;
726
727 if (listen(sock, 1) < 0)
728 return -1;
729
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400730 wl_event_loop_add_fd(display->loop, sock,
731 WL_EVENT_READABLE,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400732 socket_data, display);
733
734 return 0;
735}
736
737
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400738struct wl_surface_iterator {
739 struct wl_list *head;
740 struct wl_surface *surface;
741 uint32_t mask;
742};
743
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500744WL_EXPORT struct wl_surface_iterator *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400745wl_surface_iterator_create(struct wl_display *display, uint32_t mask)
746{
747 struct wl_surface_iterator *iterator;
748
749 iterator = malloc(sizeof *iterator);
750 if (iterator == NULL)
751 return NULL;
752
753 iterator->head = &display->surface_list;
754 iterator->surface = container_of(display->surface_list.next,
755 struct wl_surface, link);
756 iterator->mask = mask;
757
758 return iterator;
759}
760
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500761WL_EXPORT int
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400762wl_surface_iterator_next(struct wl_surface_iterator *iterator,
763 struct wl_surface **surface)
764{
765 if (&iterator->surface->link == iterator->head)
766 return 0;
767
768 *surface = iterator->surface;
769 iterator->surface = container_of(iterator->surface->link.next,
770 struct wl_surface, link);
771
772 return 1;
773}
774
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500775WL_EXPORT void
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400776wl_surface_iterator_destroy(struct wl_surface_iterator *iterator)
777{
778 free(iterator);
779}
780
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500781static int
782load_compositor(struct wl_display *display, const char *path)
783{
784 struct wl_compositor *(*create)(struct wl_display *display);
785 struct wl_compositor *compositor;
786 void *p;
787
788 p = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
789 if (p == NULL) {
790 fprintf(stderr, "failed to open compositor %s: %s\n",
791 path, dlerror());
792 return -1;
793 }
794
795 create = dlsym(p, "wl_compositor_create");
796 if (create == NULL) {
797 fprintf(stderr, "failed to look up compositor constructor\n");
798 return -1;
799 }
800
801 compositor = create(display);
802 if (compositor == NULL) {
803 fprintf(stderr, "couldn't create compositor\n");
804 return -1;
805 }
806
807 wl_display_set_compositor(display, compositor);
808
809 return 0;
810}
811
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400812int main(int argc, char *argv[])
813{
814 struct wl_display *display;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500815 const char *compositor = "./egl-compositor.so";
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400816
817 display = wl_display_create();
818
819 if (wl_display_add_socket(display)) {
820 fprintf(stderr, "failed to add socket: %m\n");
821 exit(EXIT_FAILURE);
822 }
823
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500824 if (argc == 2)
825 compositor = argv[1];
826 load_compositor(display, compositor);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400827
828 wl_display_run(display);
829
830 return 0;
831}