blob: 6057502f80f7fd326449b362b8912cbd4d72217b [file] [log] [blame]
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05001/*
2 * Copyright © 2008 Kristian Høgsberg
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040023#include <stdlib.h>
24#include <stdint.h>
25#include <stddef.h>
26#include <stdio.h>
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -050027#include <stdarg.h>
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040028#include <errno.h>
29#include <string.h>
30#include <unistd.h>
31#include <sys/socket.h>
32#include <sys/un.h>
Kristian Høgsberg5503bf82008-11-06 10:38:17 -050033#include <dlfcn.h>
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -050034#include <assert.h>
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040035#include <ffi.h>
Kristian Høgsberg680f1c72008-10-08 12:48:46 -040036
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040037#include "wayland.h"
Kristian Høgsberg680f1c72008-10-08 12:48:46 -040038#include "connection.h"
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040039
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040040struct wl_client {
Kristian Høgsberg680f1c72008-10-08 12:48:46 -040041 struct wl_connection *connection;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040042 struct wl_event_source *source;
43 struct wl_display *display;
Kristian Høgsberg94a2e862008-10-11 21:37:55 -040044 struct wl_list object_list;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050045 struct wl_list link;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -050046 uint32_t pending_frame;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040047};
48
49struct wl_display {
50 struct wl_object base;
51 struct wl_event_loop *loop;
52 struct wl_hash objects;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040053
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050054 struct wl_object *pointer;
55
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040056 struct wl_compositor *compositor;
57 struct wl_compositor_interface *compositor_interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040058
59 struct wl_list surface_list;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050060 struct wl_list client_list;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040061 uint32_t client_id_range;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -050062 uint32_t id;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050063
Kristian Høgsberg14fcff72008-11-23 19:10:23 -050064 struct wl_list global_list;
65
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -050066 int32_t pointer_x;
67 int32_t pointer_y;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040068};
69
70struct wl_surface {
71 struct wl_object base;
72
73 /* provided by client */
74 int width, height;
75 int buffer;
76 int stride;
77
Kristian Høgsberg05eff512008-10-07 10:10:36 -040078 struct wl_map map;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040079 struct wl_list link;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040080
81 /* how to convert buffer contents to pixels in screen format;
82 * yuv->rgb, indexed->rgb, svg->rgb, but mostly just rgb->rgb. */
83
84 /* how to transform/render rectangular contents to polygons. */
Kristian Høgsberg05eff512008-10-07 10:10:36 -040085
86 void *compositor_data;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040087};
88
Kristian Høgsberg94a2e862008-10-11 21:37:55 -040089struct wl_object_ref {
90 struct wl_object *object;
91 struct wl_list link;
92};
Kristian Høgsberg05eff512008-10-07 10:10:36 -040093
94static void
95wl_surface_destroy(struct wl_client *client,
96 struct wl_surface *surface)
97{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -050098 const struct wl_compositor_interface *interface;
Kristian Høgsberg05eff512008-10-07 10:10:36 -040099
100 interface = client->display->compositor->interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400101 interface->notify_surface_destroy(client->display->compositor,
102 surface);
103 wl_list_remove(&surface->link);
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400104}
105
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400106static void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400107wl_surface_attach(struct wl_client *client,
108 struct wl_surface *surface, uint32_t name,
109 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400110{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500111 const struct wl_compositor_interface *interface;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400112
113 interface = client->display->compositor->interface;
114 interface->notify_surface_attach(client->display->compositor,
115 surface, name, width, height, stride);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400116}
117
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400118static const struct wl_argument attach_arguments[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400119 { WL_ARGUMENT_UINT32 },
120 { WL_ARGUMENT_UINT32 },
121 { WL_ARGUMENT_UINT32 },
122 { WL_ARGUMENT_UINT32 },
123};
124
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500125static void
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400126wl_surface_map(struct wl_client *client, struct wl_surface *surface,
127 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400128{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500129 const struct wl_compositor_interface *interface;
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400130
131 /* FIXME: This needs to take a tri-mesh argument... - count
132 * and a list of tris. 0 tris means unmap. */
133
134 surface->map.x = x;
135 surface->map.y = y;
136 surface->map.width = width;
137 surface->map.height = height;
138
139 interface = client->display->compositor->interface;
140 interface->notify_surface_map(client->display->compositor,
141 surface, &surface->map);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400142}
143
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400144static const struct wl_argument map_arguments[] = {
145 { WL_ARGUMENT_UINT32 },
146 { WL_ARGUMENT_UINT32 },
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400147 { WL_ARGUMENT_UINT32 },
148 { WL_ARGUMENT_UINT32 },
149};
150
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500151static void
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500152wl_surface_copy(struct wl_client *client, struct wl_surface *surface,
153 int32_t dst_x, int32_t dst_y, uint32_t name, uint32_t stride,
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_copy(client->display->compositor,
160 surface, dst_x, dst_y,
161 name, stride, x, y, width, height);
162}
163
164static const struct wl_argument copy_arguments[] = {
165 { WL_ARGUMENT_UINT32 },
166 { WL_ARGUMENT_UINT32 },
167 { WL_ARGUMENT_UINT32 },
168 { WL_ARGUMENT_UINT32 },
169 { WL_ARGUMENT_UINT32 },
170 { WL_ARGUMENT_UINT32 },
171 { WL_ARGUMENT_UINT32 },
172 { WL_ARGUMENT_UINT32 },
173 { WL_ARGUMENT_UINT32 },
174 { WL_ARGUMENT_UINT32 },
175};
176
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500177static void
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500178wl_surface_damage(struct wl_client *client, struct wl_surface *surface,
179 int32_t x, int32_t y, int32_t width, int32_t height)
180{
181 const struct wl_compositor_interface *interface;
182
183 interface = client->display->compositor->interface;
184 interface->notify_surface_damage(client->display->compositor,
185 surface, x, y, width, height);
186}
187
188static const struct wl_argument damage_arguments[] = {
189 { WL_ARGUMENT_UINT32 },
190 { WL_ARGUMENT_UINT32 },
191 { WL_ARGUMENT_UINT32 },
192 { WL_ARGUMENT_UINT32 },
193};
194
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400195static const struct wl_method surface_methods[] = {
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400196 { "destroy", wl_surface_destroy,
197 0, NULL },
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400198 { "attach", wl_surface_attach,
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400199 ARRAY_LENGTH(attach_arguments), attach_arguments },
200 { "map", wl_surface_map,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500201 ARRAY_LENGTH(map_arguments), map_arguments },
202 { "copy", wl_surface_copy,
203 ARRAY_LENGTH(copy_arguments), copy_arguments },
204 { "damage", wl_surface_damage,
205 ARRAY_LENGTH(damage_arguments), damage_arguments }
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400206};
207
208static const struct wl_interface surface_interface = {
209 "surface", 1,
210 ARRAY_LENGTH(surface_methods),
211 surface_methods,
212};
213
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500214static struct wl_surface *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400215wl_surface_create(struct wl_display *display, uint32_t id)
216{
217 struct wl_surface *surface;
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500218 const struct wl_compositor_interface *interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400219
220 surface = malloc(sizeof *surface);
221 if (surface == NULL)
222 return NULL;
223
224 surface->base.id = id;
225 surface->base.interface = &surface_interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400226
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400227 wl_list_insert(display->surface_list.prev, &surface->link);
228
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400229 interface = display->compositor->interface;
230 interface->notify_surface_create(display->compositor, surface);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400231
232 return surface;
233}
234
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500235WL_EXPORT void
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400236wl_surface_set_data(struct wl_surface *surface, void *data)
237{
238 surface->compositor_data = data;
239}
240
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500241WL_EXPORT void *
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400242wl_surface_get_data(struct wl_surface *surface)
243{
244 return surface->compositor_data;
245}
246
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400247void
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400248wl_client_destroy(struct wl_client *client);
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400249
250static void
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500251wl_client_marshal(struct wl_client *client, struct wl_object *sender,
252 uint32_t opcode, ...)
253{
254 const struct wl_event *event;
255 struct wl_object *object;
256 uint32_t args[10], size, *p;
257 va_list ap;
258 int i;
259
260 event = &sender->interface->events[opcode];
261 size = 0;
262 va_start(ap, opcode);
263 p = &args[2];
264 for (i = 0; i < event->argument_count; i++) {
265 switch (event->arguments[i].type) {
266 case WL_ARGUMENT_UINT32:
267 p[i] = va_arg(ap, uint32_t);
268 size += sizeof p[i];
269 break;
270 case WL_ARGUMENT_STRING:
271 /* FIXME */
272 p[i] = 0;
273 size += sizeof p[i];
274 break;
275 case WL_ARGUMENT_OBJECT:
276 object = va_arg(ap, struct wl_object *);
277 p[i] = object->id;
278 size += sizeof p[i];
279 break;
280 case WL_ARGUMENT_NEW_ID:
281 default:
282 assert(0);
283 break;
284 }
285 }
286 va_end(ap);
287
288 size += 2 * sizeof args[0];
289 args[0] = sender->id;
290 args[1] = opcode | (size << 16);
291 wl_connection_write(client->connection, args, size);
292}
293
294static void
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400295wl_client_demarshal(struct wl_client *client, struct wl_object *target,
296 const struct wl_method *method, size_t size)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400297{
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500298 ffi_type *types[20];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400299 ffi_cif cif;
300 uint32_t *p, result;
301 int i;
302 union {
303 uint32_t uint32;
304 const char *string;
305 void *object;
306 uint32_t new_id;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500307 } values[20];
308 void *args[20];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400309 struct wl_object *object;
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400310 uint32_t data[64];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400311
312 if (method->argument_count > ARRAY_LENGTH(types)) {
313 printf("too many args (%d)\n", method->argument_count);
314 return;
315 }
316
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400317 if (sizeof data < size) {
318 printf("request too big, should malloc tmp buffer here\n");
319 return;
320 }
321
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400322 types[0] = &ffi_type_pointer;
323 values[0].object = client;
324 args[0] = &values[0];
325
326 types[1] = &ffi_type_pointer;
327 values[1].object = target;
328 args[1] = &values[1];
329
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400330 wl_connection_copy(client->connection, data, size);
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400331 p = &data[2];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400332 for (i = 0; i < method->argument_count; i++) {
333 switch (method->arguments[i].type) {
334 case WL_ARGUMENT_UINT32:
335 types[i + 2] = &ffi_type_uint32;
336 values[i + 2].uint32 = *p;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400337 p++;
338 break;
339 case WL_ARGUMENT_STRING:
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400340 types[i + 2] = &ffi_type_pointer;
341 /* FIXME */
342 values[i + 2].uint32 = *p++;
343 break;
344 case WL_ARGUMENT_OBJECT:
345 types[i + 2] = &ffi_type_pointer;
346 object = wl_hash_lookup(&client->display->objects, *p);
347 if (object == NULL)
348 printf("unknown object (%d)\n", *p);
349 if (object->interface != method->arguments[i].data)
350 printf("wrong object type\n");
351 values[i + 2].object = object;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400352 p++;
353 break;
354 case WL_ARGUMENT_NEW_ID:
355 types[i + 2] = &ffi_type_uint32;
356 values[i + 2].new_id = *p;
357 object = wl_hash_lookup(&client->display->objects, *p);
358 if (object != NULL)
359 printf("object already exists (%d)\n", *p);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400360 p++;
361 break;
362 default:
363 printf("unknown type\n");
364 break;
365 }
366 args[i + 2] = &values[i + 2];
367 }
368
369 ffi_prep_cif(&cif, FFI_DEFAULT_ABI, method->argument_count + 2,
370 &ffi_type_uint32, types);
371 ffi_call(&cif, FFI_FN(method->func), &result, args);
372}
373
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400374#define WL_DISPLAY_INVALID_OBJECT 0
375#define WL_DISPLAY_INVALID_METHOD 1
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400376#define WL_DISPLAY_NO_MEMORY 2
Kristian Høgsberg40979232008-11-25 22:40:39 -0500377#define WL_DISPLAY_ACKNOWLEDGE 3
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500378#define WL_DISPLAY_FRAME 4
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400379
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400380static void
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400381wl_client_connection_data(int fd, uint32_t mask, void *data)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400382{
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400383 struct wl_client *client = data;
384 struct wl_connection *connection = client->connection;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400385 const struct wl_method *method;
386 struct wl_object *object;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400387 uint32_t p[2], opcode, size;
388 uint32_t cmask = 0;
389 int len;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400390
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400391 if (mask & WL_EVENT_READABLE)
392 cmask |= WL_CONNECTION_READABLE;
393 if (mask & WL_EVENT_WRITEABLE)
394 cmask |= WL_CONNECTION_WRITABLE;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400395
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400396 len = wl_connection_data(connection, cmask);
397 if (len < 0) {
398 wl_client_destroy(client);
399 return;
400 }
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400401
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500402 while (len >= sizeof p) {
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400403 wl_connection_copy(connection, p, sizeof p);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400404 opcode = p[1] & 0xffff;
405 size = p[1] >> 16;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400406 if (len < size)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400407 break;
408
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500409 object = wl_hash_lookup(&client->display->objects, p[0]);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400410 if (object == NULL) {
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500411 wl_client_marshal(client, &client->display->base,
412 WL_DISPLAY_INVALID_OBJECT, p[0]);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400413 wl_connection_consume(connection, size);
414 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400415 continue;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400416 }
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400417
418 if (opcode >= object->interface->method_count) {
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500419 wl_client_marshal(client, &client->display->base,
420 WL_DISPLAY_INVALID_METHOD, p[0], opcode);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400421 wl_connection_consume(connection, size);
422 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400423 continue;
424 }
425
426 method = &object->interface->methods[opcode];
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400427 wl_client_demarshal(client, object, method, size);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400428 wl_connection_consume(connection, size);
429 len -= size;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400430 }
431}
432
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400433static int
434wl_client_connection_update(struct wl_connection *connection,
435 uint32_t mask, void *data)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400436{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400437 struct wl_client *client = data;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400438 uint32_t emask = 0;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400439
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400440 if (mask & WL_CONNECTION_READABLE)
441 emask |= WL_EVENT_READABLE;
442 if (mask & WL_CONNECTION_WRITABLE)
443 emask |= WL_EVENT_WRITEABLE;
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400444
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500445 return wl_event_source_fd_update(client->source, mask);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400446}
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400447
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400448static void
449advertise_object(struct wl_client *client, struct wl_object *object)
450{
451 const struct wl_interface *interface;
452 static const char pad[4];
453 uint32_t length, p[2];
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400454
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400455 interface = object->interface;
456 length = strlen(interface->name);
457 p[0] = object->id;
458 p[1] = length;
459 wl_connection_write(client->connection, p, sizeof p);
460 wl_connection_write(client->connection, interface->name, length);
461 wl_connection_write(client->connection, pad, -length & 3);
462}
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400463
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500464static struct wl_client *
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400465wl_client_create(struct wl_display *display, int fd)
466{
467 struct wl_client *client;
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500468 struct wl_object_ref *ref;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500469 uint32_t count;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400470
471 client = malloc(sizeof *client);
472 if (client == NULL)
473 return NULL;
474
475 memset(client, 0, sizeof *client);
476 client->display = display;
477 client->source = wl_event_loop_add_fd(display->loop, fd,
478 WL_EVENT_READABLE,
479 wl_client_connection_data, client);
480 client->connection = wl_connection_create(fd,
481 wl_client_connection_update,
482 client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400483 wl_list_init(&client->object_list);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400484
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400485 wl_connection_write(client->connection,
486 &display->client_id_range,
487 sizeof display->client_id_range);
488 display->client_id_range += 256;
489
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500490 /* Write list of global objects to client. */
491 count = wl_list_length(&display->global_list);
492 wl_connection_write(client->connection, &count, sizeof count);
493
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500494 ref = container_of(display->global_list.next,
495 struct wl_object_ref, link);
496 while (&ref->link != &display->global_list) {
497 advertise_object(client, ref->object);
498
499 ref = container_of(ref->link.next,
500 struct wl_object_ref, link);
501 }
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400502
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500503 wl_list_insert(display->client_list.prev, &client->link);
504
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400505 return client;
506}
507
508void
509wl_client_destroy(struct wl_client *client)
510{
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400511 struct wl_object_ref *ref;
512
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400513 printf("disconnect from client %p\n", client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400514
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500515 wl_list_remove(&client->link);
516
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400517 while (client->object_list.next != &client->object_list) {
518 ref = container_of(client->object_list.next,
519 struct wl_object_ref, link);
520 wl_list_remove(&ref->link);
521 wl_surface_destroy(client, (struct wl_surface *) ref->object);
522 free(ref);
523 }
524
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500525 wl_event_source_remove(client->source);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400526 wl_connection_destroy(client->connection);
527 free(client);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400528}
529
530static int
531wl_display_create_surface(struct wl_client *client,
532 struct wl_display *display, uint32_t id)
533{
534 struct wl_surface *surface;
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400535 struct wl_object_ref *ref;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400536
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400537 surface = wl_surface_create(display, id);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400538
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400539 ref = malloc(sizeof *ref);
540 if (ref == NULL) {
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500541 wl_client_marshal(client, &display->base,
542 WL_DISPLAY_NO_MEMORY);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400543 return -1;
544 }
545
546 ref->object = &surface->base;
547 wl_hash_insert(&display->objects, &surface->base);
548 wl_list_insert(client->object_list.prev, &ref->link);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400549
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400550 return 0;
551}
552
553static const struct wl_argument create_surface_arguments[] = {
554 { WL_ARGUMENT_NEW_ID }
555};
556
Kristian Høgsberg40979232008-11-25 22:40:39 -0500557static int
558wl_display_commit(struct wl_client *client,
559 struct wl_display *display, uint32_t key)
560{
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500561 const struct wl_compositor_interface *interface;
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500562 uint32_t frame;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500563
564 client->pending_frame = 1;
565
566 interface = display->compositor->interface;
567 frame = interface->notify_commit(display->compositor);
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500568 wl_client_marshal(client, &display->base,
569 WL_DISPLAY_ACKNOWLEDGE, key, frame);
Kristian Høgsberg40979232008-11-25 22:40:39 -0500570
571 return 0;
572}
573
574static const struct wl_argument commit_arguments[] = {
575 { WL_ARGUMENT_UINT32 }
576};
577
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400578static const struct wl_method display_methods[] = {
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400579 { "create_surface", wl_display_create_surface,
580 ARRAY_LENGTH(create_surface_arguments), create_surface_arguments },
Kristian Høgsberg40979232008-11-25 22:40:39 -0500581 { "commit", wl_display_commit,
582 ARRAY_LENGTH(commit_arguments), commit_arguments },
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400583};
584
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500585static const struct wl_argument invalid_object_arguments[] = {
586 { WL_ARGUMENT_UINT32 }
587};
588
589static const struct wl_argument invalid_method_arguments[] = {
590 { WL_ARGUMENT_UINT32 },
591 { WL_ARGUMENT_UINT32 }
592};
593
594static const struct wl_argument acknowledge_arguments[] = {
595 { WL_ARGUMENT_UINT32 },
596 { WL_ARGUMENT_UINT32 }
597};
598
599static const struct wl_argument frame_arguments[] = {
600 { WL_ARGUMENT_UINT32 },
601 { WL_ARGUMENT_UINT32 }
602};
603
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400604static const struct wl_event display_events[] = {
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500605 { "invalid_object",
606 ARRAY_LENGTH(invalid_object_arguments), invalid_object_arguments },
607 { "invalid_method",
608 ARRAY_LENGTH(invalid_method_arguments), invalid_method_arguments },
609 { "no_memory",
610 0, NULL },
611 { "acknowledge",
612 ARRAY_LENGTH(acknowledge_arguments), acknowledge_arguments },
613 { "frame",
614 ARRAY_LENGTH(frame_arguments), frame_arguments },
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400615};
616
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400617static const struct wl_interface display_interface = {
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400618 "display", 1,
619 ARRAY_LENGTH(display_methods), display_methods,
620 ARRAY_LENGTH(display_events), display_events,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400621};
622
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500623static struct wl_display *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400624wl_display_create(void)
625{
626 struct wl_display *display;
627
628 display = malloc(sizeof *display);
629 if (display == NULL)
630 return NULL;
631
632 display->loop = wl_event_loop_create();
633 if (display->loop == NULL) {
634 free(display);
635 return NULL;
636 }
637
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400638 wl_list_init(&display->surface_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500639 wl_list_init(&display->client_list);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500640 wl_list_init(&display->global_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500641
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500642 display->pointer_x = 100;
643 display->pointer_y = 100;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400644
645 display->client_id_range = 256; /* Gah, arbitrary... */
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400646
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500647 display->id = 1;
648 display->base.interface = &display_interface;
649 wl_display_add_object(display, &display->base);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500650 if (wl_display_add_global(display, &display->base)) {
651 wl_event_loop_destroy(display->loop);
652 free(display);
653 return NULL;
654 }
655
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400656 return display;
657}
658
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500659WL_EXPORT void
660wl_display_add_object(struct wl_display *display, struct wl_object *object)
661{
662 object->id = display->id++;
663 wl_hash_insert(&display->objects, object);
664}
665
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500666WL_EXPORT int
667wl_display_add_global(struct wl_display *display, struct wl_object *object)
668{
669 struct wl_object_ref *ref;
670
671 ref = malloc(sizeof *ref);
672 if (ref == NULL)
673 return -1;
674
675 ref->object = object;
676 wl_list_insert(display->global_list.prev, &ref->link);
677
678 return 0;
679}
680
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500681static void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500682wl_display_send_event(struct wl_display *display, uint32_t *data, size_t size)
683{
684 struct wl_client *client;
685
686 client = container_of(display->client_list.next,
687 struct wl_client, link);
688 while (&client->link != &display->client_list) {
689 wl_connection_write(client->connection, data, size);
690
691 client = container_of(client->link.next,
692 struct wl_client, link);
693 }
694}
695
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500696#define WL_INPUT_MOTION 0
697#define WL_INPUT_BUTTON 1
698#define WL_INPUT_KEY 2
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500699
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500700WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500701wl_display_post_relative_event(struct wl_display *display,
702 struct wl_object *source, int dx, int dy)
703{
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500704 const struct wl_compositor_interface *interface;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500705 uint32_t p[4];
706
707 display->pointer_x += dx;
708 display->pointer_y += dy;
709
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500710 interface = display->compositor->interface;
711 interface->notify_pointer_motion(display->compositor, source,
712 display->pointer_x, display->pointer_y);
713
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500714 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500715 p[1] = (sizeof p << 16) | WL_INPUT_MOTION;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500716 p[2] = display->pointer_x;
717 p[3] = display->pointer_y;
718
719 wl_display_send_event(display, p, sizeof p);
720}
721
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500722WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500723wl_display_post_absolute_event(struct wl_display *display,
724 struct wl_object *source, int x, int y)
725{
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500726 const struct wl_compositor_interface *interface;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500727 uint32_t p[4];
728
729 display->pointer_x = x;
730 display->pointer_y = y;
731
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500732 interface = display->compositor->interface;
733 interface->notify_pointer_motion(display->compositor, source,
734 display->pointer_x, display->pointer_y);
735
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500736 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500737 p[1] = (sizeof p << 16) | WL_INPUT_MOTION;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500738 p[2] = display->pointer_x;
739 p[3] = display->pointer_y;
740
741 wl_display_send_event(display, p, sizeof p);
742}
743
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500744WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500745wl_display_post_button_event(struct wl_display *display,
746 struct wl_object *source, int button, int state)
747{
748 uint32_t p[4];
749
750 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500751 p[1] = (sizeof p << 16) | WL_INPUT_BUTTON;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500752 p[2] = button;
753 p[3] = state;
754
755 wl_display_send_event(display, p, sizeof p);
756}
757
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500758WL_EXPORT void
759wl_display_post_key_event(struct wl_display *display,
760 struct wl_object *source, int key, int state)
761{
762 const struct wl_compositor_interface *interface;
763 uint32_t p[4];
764
765 interface = display->compositor->interface;
766 interface->notify_key(display->compositor, source, key, state);
767
768 p[0] = source->id;
769 p[1] = (sizeof p << 16) | WL_INPUT_KEY;
770 p[2] = key;
771 p[3] = state;
772
773 wl_display_send_event(display, p, sizeof p);
774}
775
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500776WL_EXPORT void
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500777wl_display_post_frame(struct wl_display *display,
778 uint32_t frame, uint32_t msecs)
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500779{
780 struct wl_client *client;
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500781
782 client = container_of(display->client_list.next,
783 struct wl_client, link);
784
785 while (&client->link != &display->client_list) {
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500786 if (client->pending_frame) {
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500787 wl_client_marshal(client, &display->base,
788 WL_DISPLAY_FRAME, frame, msecs);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500789 client->pending_frame = 0;
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500790 }
791 client = container_of(client->link.next,
792 struct wl_client, link);
793 }
794}
795
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500796void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400797wl_display_set_compositor(struct wl_display *display,
798 struct wl_compositor *compositor)
799{
800 display->compositor = compositor;
801}
802
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500803WL_EXPORT struct wl_event_loop *
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400804wl_display_get_event_loop(struct wl_display *display)
805{
806 return display->loop;
807}
808
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500809static void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400810wl_display_run(struct wl_display *display)
811{
812 while (1)
813 wl_event_loop_wait(display->loop);
814}
815
816/* The plan here is to generate a random anonymous socket name and
817 * advertise that through a service on the session dbus.
818 */
819static const char socket_name[] = "\0wayland";
820
821static void
822socket_data(int fd, uint32_t mask, void *data)
823{
824 struct wl_display *display = data;
825 struct sockaddr_un name;
826 socklen_t length;
827 int client_fd;
828
829 length = sizeof name;
830 client_fd = accept (fd, (struct sockaddr *) &name, &length);
831 if (client_fd < 0)
832 fprintf(stderr, "failed to accept\n");
833
834 wl_client_create(display, client_fd);
835}
836
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500837static int
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400838wl_display_add_socket(struct wl_display *display)
839{
840 struct sockaddr_un name;
841 int sock;
842 socklen_t size;
843
844 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
845 if (sock < 0)
846 return -1;
847
848 name.sun_family = AF_LOCAL;
849 memcpy(name.sun_path, socket_name, sizeof socket_name);
850
851 size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
852 if (bind(sock, (struct sockaddr *) &name, size) < 0)
853 return -1;
854
855 if (listen(sock, 1) < 0)
856 return -1;
857
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400858 wl_event_loop_add_fd(display->loop, sock,
859 WL_EVENT_READABLE,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400860 socket_data, display);
861
862 return 0;
863}
864
865
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400866struct wl_surface_iterator {
867 struct wl_list *head;
868 struct wl_surface *surface;
869 uint32_t mask;
870};
871
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500872WL_EXPORT struct wl_surface_iterator *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400873wl_surface_iterator_create(struct wl_display *display, uint32_t mask)
874{
875 struct wl_surface_iterator *iterator;
876
877 iterator = malloc(sizeof *iterator);
878 if (iterator == NULL)
879 return NULL;
880
881 iterator->head = &display->surface_list;
882 iterator->surface = container_of(display->surface_list.next,
883 struct wl_surface, link);
884 iterator->mask = mask;
885
886 return iterator;
887}
888
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500889WL_EXPORT int
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400890wl_surface_iterator_next(struct wl_surface_iterator *iterator,
891 struct wl_surface **surface)
892{
893 if (&iterator->surface->link == iterator->head)
894 return 0;
895
896 *surface = iterator->surface;
897 iterator->surface = container_of(iterator->surface->link.next,
898 struct wl_surface, link);
899
900 return 1;
901}
902
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500903WL_EXPORT void
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400904wl_surface_iterator_destroy(struct wl_surface_iterator *iterator)
905{
906 free(iterator);
907}
908
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500909static int
910load_compositor(struct wl_display *display, const char *path)
911{
912 struct wl_compositor *(*create)(struct wl_display *display);
913 struct wl_compositor *compositor;
914 void *p;
915
916 p = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
917 if (p == NULL) {
918 fprintf(stderr, "failed to open compositor %s: %s\n",
919 path, dlerror());
920 return -1;
921 }
922
923 create = dlsym(p, "wl_compositor_create");
924 if (create == NULL) {
925 fprintf(stderr, "failed to look up compositor constructor\n");
926 return -1;
927 }
928
929 compositor = create(display);
930 if (compositor == NULL) {
931 fprintf(stderr, "couldn't create compositor\n");
932 return -1;
933 }
934
935 wl_display_set_compositor(display, compositor);
936
937 return 0;
938}
939
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400940int main(int argc, char *argv[])
941{
942 struct wl_display *display;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500943 const char *compositor = "./egl-compositor.so";
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400944
945 display = wl_display_create();
946
947 if (wl_display_add_socket(display)) {
948 fprintf(stderr, "failed to add socket: %m\n");
949 exit(EXIT_FAILURE);
950 }
951
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500952 if (argc == 2)
953 compositor = argv[1];
Kristian Høgsberg35052562008-12-02 15:38:53 -0500954 if (load_compositor(display, compositor))
955 return -1;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400956
957 wl_display_run(display);
958
959 return 0;
960}