blob: 5f321ba85121c8c1986c186e8ca856ec39927971 [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øgsbergb7a01922008-11-08 15:39:41 -0500118static void
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400119wl_surface_map(struct wl_client *client, struct wl_surface *surface,
120 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400121{
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500122 const struct wl_compositor_interface *interface;
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400123
124 /* FIXME: This needs to take a tri-mesh argument... - count
125 * and a list of tris. 0 tris means unmap. */
126
127 surface->map.x = x;
128 surface->map.y = y;
129 surface->map.width = width;
130 surface->map.height = height;
131
132 interface = client->display->compositor->interface;
133 interface->notify_surface_map(client->display->compositor,
134 surface, &surface->map);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400135}
136
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500137static void
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500138wl_surface_copy(struct wl_client *client, struct wl_surface *surface,
139 int32_t dst_x, int32_t dst_y, uint32_t name, uint32_t stride,
140 int32_t x, int32_t y, int32_t width, int32_t height)
141{
142 const struct wl_compositor_interface *interface;
143
144 interface = client->display->compositor->interface;
145 interface->notify_surface_copy(client->display->compositor,
146 surface, dst_x, dst_y,
147 name, stride, x, y, width, height);
148}
149
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500150static void
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500151wl_surface_damage(struct wl_client *client, struct wl_surface *surface,
152 int32_t x, int32_t y, int32_t width, int32_t height)
153{
154 const struct wl_compositor_interface *interface;
155
156 interface = client->display->compositor->interface;
157 interface->notify_surface_damage(client->display->compositor,
158 surface, x, y, width, height);
159}
160
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400161static const struct wl_method surface_methods[] = {
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500162 { "destroy", wl_surface_destroy, "" },
163 { "attach", wl_surface_attach, "uuuu" },
164 { "map", wl_surface_map, "iiii" },
165 { "copy", wl_surface_copy, "iiuuiiii" },
166 { "damage", wl_surface_damage, "iiii" }
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400167};
168
169static const struct wl_interface surface_interface = {
170 "surface", 1,
171 ARRAY_LENGTH(surface_methods),
172 surface_methods,
173};
174
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500175static struct wl_surface *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400176wl_surface_create(struct wl_display *display, uint32_t id)
177{
178 struct wl_surface *surface;
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500179 const struct wl_compositor_interface *interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400180
181 surface = malloc(sizeof *surface);
182 if (surface == NULL)
183 return NULL;
184
185 surface->base.id = id;
186 surface->base.interface = &surface_interface;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400187
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400188 wl_list_insert(display->surface_list.prev, &surface->link);
189
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400190 interface = display->compositor->interface;
191 interface->notify_surface_create(display->compositor, surface);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400192
193 return surface;
194}
195
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500196WL_EXPORT void
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400197wl_surface_set_data(struct wl_surface *surface, void *data)
198{
199 surface->compositor_data = data;
200}
201
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500202WL_EXPORT void *
Kristian Høgsberg05eff512008-10-07 10:10:36 -0400203wl_surface_get_data(struct wl_surface *surface)
204{
205 return surface->compositor_data;
206}
207
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400208void
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400209wl_client_destroy(struct wl_client *client);
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400210
211static void
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500212wl_client_marshal(struct wl_client *client, struct wl_object *sender,
213 uint32_t opcode, ...)
214{
215 const struct wl_event *event;
216 struct wl_object *object;
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500217 uint32_t args[10], size;
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500218 va_list ap;
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500219 int i, count;
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500220
221 event = &sender->interface->events[opcode];
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500222 count = strlen(event->signature) + 2;
223 assert(count <= ARRAY_LENGTH(args));
224
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500225 size = 0;
226 va_start(ap, opcode);
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500227 for (i = 2; i < count; i++) {
228 switch (event->signature[i - 2]) {
229 case 'u':
230 case 'i':
231 args[i] = va_arg(ap, uint32_t);
232 size += sizeof args[i];
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500233 break;
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500234 case 's':
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500235 /* FIXME */
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500236 args[i] = 0;
237 size += sizeof args[i];
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500238 break;
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500239 case 'o':
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500240 object = va_arg(ap, struct wl_object *);
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500241 args[i] = object->id;
242 size += sizeof args[i];
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500243 break;
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500244 default:
245 assert(0);
246 break;
247 }
248 }
249 va_end(ap);
250
251 size += 2 * sizeof args[0];
252 args[0] = sender->id;
253 args[1] = opcode | (size << 16);
254 wl_connection_write(client->connection, args, size);
255}
256
257static void
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400258wl_client_demarshal(struct wl_client *client, struct wl_object *target,
259 const struct wl_method *method, size_t size)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400260{
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500261 ffi_type *types[20];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400262 ffi_cif cif;
263 uint32_t *p, result;
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500264 int i, j, count;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400265 union {
266 uint32_t uint32;
267 const char *string;
268 void *object;
269 uint32_t new_id;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500270 } values[20];
271 void *args[20];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400272 struct wl_object *object;
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400273 uint32_t data[64];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400274
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500275 count = strlen(method->signature) + 2;
276 if (count > ARRAY_LENGTH(types)) {
277 printf("too many args (%d)\n", count);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400278 return;
279 }
280
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400281 if (sizeof data < size) {
282 printf("request too big, should malloc tmp buffer here\n");
283 return;
284 }
285
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400286 types[0] = &ffi_type_pointer;
287 values[0].object = client;
288 args[0] = &values[0];
289
290 types[1] = &ffi_type_pointer;
291 values[1].object = target;
292 args[1] = &values[1];
293
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400294 wl_connection_copy(client->connection, data, size);
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400295 p = &data[2];
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500296 j = 0;
297 for (i = 2; i < count; i++) {
298 switch (method->signature[i - 2]) {
299 case 'u':
300 case 'i':
301 types[i] = &ffi_type_uint32;
302 values[i].uint32 = *p;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400303 p++;
304 break;
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500305 case 's':
306 types[i] = &ffi_type_pointer;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400307 /* FIXME */
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500308 values[i].uint32 = *p++;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400309 break;
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500310 case 'o':
311 types[i] = &ffi_type_pointer;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400312 object = wl_hash_lookup(&client->display->objects, *p);
313 if (object == NULL)
314 printf("unknown object (%d)\n", *p);
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500315 if (object->interface != method->types[j])
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400316 printf("wrong object type\n");
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500317 values[i].object = object;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400318 p++;
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500319 j++;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400320 break;
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500321 case 'n':
322 types[i] = &ffi_type_uint32;
323 values[i].new_id = *p;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400324 object = wl_hash_lookup(&client->display->objects, *p);
325 if (object != NULL)
326 printf("object already exists (%d)\n", *p);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400327 p++;
328 break;
329 default:
330 printf("unknown type\n");
331 break;
332 }
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500333 args[i] = &values[i];
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400334 }
335
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500336 ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400337 ffi_call(&cif, FFI_FN(method->func), &result, args);
338}
339
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400340#define WL_DISPLAY_INVALID_OBJECT 0
341#define WL_DISPLAY_INVALID_METHOD 1
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400342#define WL_DISPLAY_NO_MEMORY 2
Kristian Høgsberg40979232008-11-25 22:40:39 -0500343#define WL_DISPLAY_ACKNOWLEDGE 3
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500344#define WL_DISPLAY_FRAME 4
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400345
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400346static void
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400347wl_client_connection_data(int fd, uint32_t mask, void *data)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400348{
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400349 struct wl_client *client = data;
350 struct wl_connection *connection = client->connection;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400351 const struct wl_method *method;
352 struct wl_object *object;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400353 uint32_t p[2], opcode, size;
354 uint32_t cmask = 0;
355 int len;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400356
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400357 if (mask & WL_EVENT_READABLE)
358 cmask |= WL_CONNECTION_READABLE;
359 if (mask & WL_EVENT_WRITEABLE)
360 cmask |= WL_CONNECTION_WRITABLE;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400361
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400362 len = wl_connection_data(connection, cmask);
363 if (len < 0) {
364 wl_client_destroy(client);
365 return;
366 }
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400367
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500368 while (len >= sizeof p) {
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400369 wl_connection_copy(connection, p, sizeof p);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400370 opcode = p[1] & 0xffff;
371 size = p[1] >> 16;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400372 if (len < size)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400373 break;
374
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500375 object = wl_hash_lookup(&client->display->objects, p[0]);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400376 if (object == NULL) {
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500377 wl_client_marshal(client, &client->display->base,
378 WL_DISPLAY_INVALID_OBJECT, p[0]);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400379 wl_connection_consume(connection, size);
380 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400381 continue;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400382 }
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400383
384 if (opcode >= object->interface->method_count) {
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500385 wl_client_marshal(client, &client->display->base,
386 WL_DISPLAY_INVALID_METHOD, p[0], opcode);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400387 wl_connection_consume(connection, size);
388 len -= size;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400389 continue;
390 }
391
392 method = &object->interface->methods[opcode];
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400393 wl_client_demarshal(client, object, method, size);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400394 wl_connection_consume(connection, size);
395 len -= size;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400396 }
397}
398
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400399static int
400wl_client_connection_update(struct wl_connection *connection,
401 uint32_t mask, void *data)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400402{
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400403 struct wl_client *client = data;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400404 uint32_t emask = 0;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400405
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400406 if (mask & WL_CONNECTION_READABLE)
407 emask |= WL_EVENT_READABLE;
408 if (mask & WL_CONNECTION_WRITABLE)
409 emask |= WL_EVENT_WRITEABLE;
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400410
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500411 return wl_event_source_fd_update(client->source, mask);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400412}
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400413
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400414static void
415advertise_object(struct wl_client *client, struct wl_object *object)
416{
417 const struct wl_interface *interface;
418 static const char pad[4];
419 uint32_t length, p[2];
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400420
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400421 interface = object->interface;
422 length = strlen(interface->name);
423 p[0] = object->id;
424 p[1] = length;
425 wl_connection_write(client->connection, p, sizeof p);
426 wl_connection_write(client->connection, interface->name, length);
427 wl_connection_write(client->connection, pad, -length & 3);
428}
Kristian Høgsbergc5089872008-10-08 10:47:59 -0400429
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500430static struct wl_client *
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400431wl_client_create(struct wl_display *display, int fd)
432{
433 struct wl_client *client;
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500434 struct wl_object_ref *ref;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500435 uint32_t count;
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400436
437 client = malloc(sizeof *client);
438 if (client == NULL)
439 return NULL;
440
441 memset(client, 0, sizeof *client);
442 client->display = display;
443 client->source = wl_event_loop_add_fd(display->loop, fd,
444 WL_EVENT_READABLE,
445 wl_client_connection_data, client);
446 client->connection = wl_connection_create(fd,
447 wl_client_connection_update,
448 client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400449 wl_list_init(&client->object_list);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400450
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400451 wl_connection_write(client->connection,
452 &display->client_id_range,
453 sizeof display->client_id_range);
454 display->client_id_range += 256;
455
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500456 /* Write list of global objects to client. */
457 count = wl_list_length(&display->global_list);
458 wl_connection_write(client->connection, &count, sizeof count);
459
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500460 ref = container_of(display->global_list.next,
461 struct wl_object_ref, link);
462 while (&ref->link != &display->global_list) {
463 advertise_object(client, ref->object);
464
465 ref = container_of(ref->link.next,
466 struct wl_object_ref, link);
467 }
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400468
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500469 wl_list_insert(display->client_list.prev, &client->link);
470
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400471 return client;
472}
473
474void
475wl_client_destroy(struct wl_client *client)
476{
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400477 struct wl_object_ref *ref;
478
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400479 printf("disconnect from client %p\n", client);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400480
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500481 wl_list_remove(&client->link);
482
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400483 while (client->object_list.next != &client->object_list) {
484 ref = container_of(client->object_list.next,
485 struct wl_object_ref, link);
486 wl_list_remove(&ref->link);
487 wl_surface_destroy(client, (struct wl_surface *) ref->object);
488 free(ref);
489 }
490
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500491 wl_event_source_remove(client->source);
Kristian Høgsberg680f1c72008-10-08 12:48:46 -0400492 wl_connection_destroy(client->connection);
493 free(client);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400494}
495
496static int
497wl_display_create_surface(struct wl_client *client,
498 struct wl_display *display, uint32_t id)
499{
500 struct wl_surface *surface;
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400501 struct wl_object_ref *ref;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400502
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400503 surface = wl_surface_create(display, id);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400504
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400505 ref = malloc(sizeof *ref);
506 if (ref == NULL) {
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500507 wl_client_marshal(client, &display->base,
508 WL_DISPLAY_NO_MEMORY);
Kristian Høgsberg94a2e862008-10-11 21:37:55 -0400509 return -1;
510 }
511
512 ref->object = &surface->base;
513 wl_hash_insert(&display->objects, &surface->base);
514 wl_list_insert(client->object_list.prev, &ref->link);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400515
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400516 return 0;
517}
518
Kristian Høgsberg40979232008-11-25 22:40:39 -0500519static int
520wl_display_commit(struct wl_client *client,
521 struct wl_display *display, uint32_t key)
522{
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500523 const struct wl_compositor_interface *interface;
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500524 uint32_t frame;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500525
526 client->pending_frame = 1;
527
528 interface = display->compositor->interface;
529 frame = interface->notify_commit(display->compositor);
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500530 wl_client_marshal(client, &display->base,
531 WL_DISPLAY_ACKNOWLEDGE, key, frame);
Kristian Høgsberg40979232008-11-25 22:40:39 -0500532
533 return 0;
534}
535
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400536static const struct wl_method display_methods[] = {
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500537 { "create_surface", wl_display_create_surface, "n" },
538 { "commit", wl_display_commit, "u" }
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500539};
540
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400541static const struct wl_event display_events[] = {
Kristian Høgsberg87e0a382008-12-05 10:38:42 -0500542 { "invalid_object", "u" },
543 { "invalid_method", "uu" },
544 { "no_memory", "" },
545 { "acknowledge", "uu" },
546 { "frame", "uu" }
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400547};
548
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400549static const struct wl_interface display_interface = {
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400550 "display", 1,
551 ARRAY_LENGTH(display_methods), display_methods,
552 ARRAY_LENGTH(display_events), display_events,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400553};
554
Kristian Høgsberg122912c2008-12-05 11:13:50 -0500555WL_EXPORT struct wl_display *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400556wl_display_create(void)
557{
558 struct wl_display *display;
559
560 display = malloc(sizeof *display);
561 if (display == NULL)
562 return NULL;
563
564 display->loop = wl_event_loop_create();
565 if (display->loop == NULL) {
566 free(display);
567 return NULL;
568 }
569
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400570 wl_list_init(&display->surface_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500571 wl_list_init(&display->client_list);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500572 wl_list_init(&display->global_list);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500573
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500574 display->pointer_x = 100;
575 display->pointer_y = 100;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400576
577 display->client_id_range = 256; /* Gah, arbitrary... */
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400578
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500579 display->id = 1;
580 display->base.interface = &display_interface;
581 wl_display_add_object(display, &display->base);
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500582 if (wl_display_add_global(display, &display->base)) {
583 wl_event_loop_destroy(display->loop);
584 free(display);
585 return NULL;
586 }
587
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400588 return display;
589}
590
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500591WL_EXPORT void
592wl_display_add_object(struct wl_display *display, struct wl_object *object)
593{
594 object->id = display->id++;
595 wl_hash_insert(&display->objects, object);
596}
597
Kristian Høgsberg14fcff72008-11-23 19:10:23 -0500598WL_EXPORT int
599wl_display_add_global(struct wl_display *display, struct wl_object *object)
600{
601 struct wl_object_ref *ref;
602
603 ref = malloc(sizeof *ref);
604 if (ref == NULL)
605 return -1;
606
607 ref->object = object;
608 wl_list_insert(display->global_list.prev, &ref->link);
609
610 return 0;
611}
612
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500613static void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500614wl_display_send_event(struct wl_display *display, uint32_t *data, size_t size)
615{
616 struct wl_client *client;
617
618 client = container_of(display->client_list.next,
619 struct wl_client, link);
620 while (&client->link != &display->client_list) {
621 wl_connection_write(client->connection, data, size);
622
623 client = container_of(client->link.next,
624 struct wl_client, link);
625 }
626}
627
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500628#define WL_INPUT_MOTION 0
629#define WL_INPUT_BUTTON 1
630#define WL_INPUT_KEY 2
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500631
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500632WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500633wl_display_post_relative_event(struct wl_display *display,
634 struct wl_object *source, int dx, int dy)
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 += dx;
640 display->pointer_y += dy;
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;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500647 p[1] = (sizeof p << 16) | WL_INPUT_MOTION;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500648 p[2] = display->pointer_x;
649 p[3] = display->pointer_y;
650
651 wl_display_send_event(display, p, sizeof p);
652}
653
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500654WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500655wl_display_post_absolute_event(struct wl_display *display,
656 struct wl_object *source, int x, int y)
657{
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500658 const struct wl_compositor_interface *interface;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500659 uint32_t p[4];
660
661 display->pointer_x = x;
662 display->pointer_y = y;
663
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500664 interface = display->compositor->interface;
665 interface->notify_pointer_motion(display->compositor, source,
666 display->pointer_x, display->pointer_y);
667
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500668 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500669 p[1] = (sizeof p << 16) | WL_INPUT_MOTION;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500670 p[2] = display->pointer_x;
671 p[3] = display->pointer_y;
672
673 wl_display_send_event(display, p, sizeof p);
674}
675
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500676WL_EXPORT void
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500677wl_display_post_button_event(struct wl_display *display,
678 struct wl_object *source, int button, int state)
679{
680 uint32_t p[4];
681
682 p[0] = source->id;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500683 p[1] = (sizeof p << 16) | WL_INPUT_BUTTON;
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500684 p[2] = button;
685 p[3] = state;
686
687 wl_display_send_event(display, p, sizeof p);
688}
689
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500690WL_EXPORT void
691wl_display_post_key_event(struct wl_display *display,
692 struct wl_object *source, int key, int state)
693{
694 const struct wl_compositor_interface *interface;
695 uint32_t p[4];
696
697 interface = display->compositor->interface;
698 interface->notify_key(display->compositor, source, key, state);
699
700 p[0] = source->id;
701 p[1] = (sizeof p << 16) | WL_INPUT_KEY;
702 p[2] = key;
703 p[3] = state;
704
705 wl_display_send_event(display, p, sizeof p);
706}
707
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500708WL_EXPORT void
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500709wl_display_post_frame(struct wl_display *display,
710 uint32_t frame, uint32_t msecs)
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500711{
712 struct wl_client *client;
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500713
714 client = container_of(display->client_list.next,
715 struct wl_client, link);
716
717 while (&client->link != &display->client_list) {
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500718 if (client->pending_frame) {
Kristian Høgsbergc2b633e2008-11-28 19:12:45 -0500719 wl_client_marshal(client, &display->base,
720 WL_DISPLAY_FRAME, frame, msecs);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500721 client->pending_frame = 0;
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500722 }
723 client = container_of(client->link.next,
724 struct wl_client, link);
725 }
726}
727
Kristian Høgsberg122912c2008-12-05 11:13:50 -0500728WL_EXPORT void
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400729wl_display_set_compositor(struct wl_display *display,
730 struct wl_compositor *compositor)
731{
732 display->compositor = compositor;
733}
734
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500735WL_EXPORT struct wl_event_loop *
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400736wl_display_get_event_loop(struct wl_display *display)
737{
738 return display->loop;
739}
740
Kristian Høgsberg122912c2008-12-05 11:13:50 -0500741WL_EXPORT void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400742wl_display_run(struct wl_display *display)
743{
744 while (1)
745 wl_event_loop_wait(display->loop);
746}
747
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400748static void
749socket_data(int fd, uint32_t mask, void *data)
750{
751 struct wl_display *display = data;
752 struct sockaddr_un name;
753 socklen_t length;
754 int client_fd;
755
756 length = sizeof name;
757 client_fd = accept (fd, (struct sockaddr *) &name, &length);
758 if (client_fd < 0)
759 fprintf(stderr, "failed to accept\n");
760
761 wl_client_create(display, client_fd);
762}
763
Kristian Høgsberg122912c2008-12-05 11:13:50 -0500764WL_EXPORT int
765wl_display_add_socket(struct wl_display *display, const char *socket_name)
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400766{
767 struct sockaddr_un name;
768 int sock;
769 socklen_t size;
770
771 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
772 if (sock < 0)
773 return -1;
774
775 name.sun_family = AF_LOCAL;
776 memcpy(name.sun_path, socket_name, sizeof socket_name);
777
778 size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
779 if (bind(sock, (struct sockaddr *) &name, size) < 0)
780 return -1;
781
782 if (listen(sock, 1) < 0)
783 return -1;
784
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400785 wl_event_loop_add_fd(display->loop, sock,
786 WL_EVENT_READABLE,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400787 socket_data, display);
788
789 return 0;
790}
791
792
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400793struct wl_surface_iterator {
794 struct wl_list *head;
795 struct wl_surface *surface;
796 uint32_t mask;
797};
798
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500799WL_EXPORT struct wl_surface_iterator *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400800wl_surface_iterator_create(struct wl_display *display, uint32_t mask)
801{
802 struct wl_surface_iterator *iterator;
803
804 iterator = malloc(sizeof *iterator);
805 if (iterator == NULL)
806 return NULL;
807
808 iterator->head = &display->surface_list;
809 iterator->surface = container_of(display->surface_list.next,
810 struct wl_surface, link);
811 iterator->mask = mask;
812
813 return iterator;
814}
815
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500816WL_EXPORT int
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400817wl_surface_iterator_next(struct wl_surface_iterator *iterator,
818 struct wl_surface **surface)
819{
820 if (&iterator->surface->link == iterator->head)
821 return 0;
822
823 *surface = iterator->surface;
824 iterator->surface = container_of(iterator->surface->link.next,
825 struct wl_surface, link);
826
827 return 1;
828}
829
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500830WL_EXPORT void
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400831wl_surface_iterator_destroy(struct wl_surface_iterator *iterator)
832{
833 free(iterator);
834}