1 | /* |
2 | * Copyright © 2008 Kristian Høgsberg |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining |
5 | * a copy of this software and associated documentation files (the |
6 | * "Software"), to deal in the Software without restriction, including |
7 | * without limitation the rights to use, copy, modify, merge, publish, |
8 | * distribute, sublicense, and/or sell copies of the Software, and to |
9 | * permit persons to whom the Software is furnished to do so, subject to |
10 | * the following conditions: |
11 | * |
12 | * The above copyright notice and this permission notice (including the |
13 | * next paragraph) shall be included in all copies or substantial |
14 | * portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
20 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
21 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | * SOFTWARE. |
24 | */ |
25 | |
26 | #define _GNU_SOURCE |
27 | |
28 | #include <stdbool.h> |
29 | #include <stdlib.h> |
30 | #include <stdint.h> |
31 | #include <stddef.h> |
32 | #include <stdio.h> |
33 | #include <stdarg.h> |
34 | #include <errno.h> |
35 | #include <string.h> |
36 | #include <unistd.h> |
37 | #include <sys/socket.h> |
38 | #include <sys/un.h> |
39 | #include <dlfcn.h> |
40 | #include <assert.h> |
41 | #include <sys/time.h> |
42 | #include <fcntl.h> |
43 | #include <sys/eventfd.h> |
44 | #include <sys/file.h> |
45 | #include <sys/stat.h> |
46 | |
47 | #include "wayland-util.h" |
48 | #include "wayland-private.h" |
49 | #include "wayland-server-private.h" |
50 | #include "wayland-server.h" |
51 | #include "wayland-os.h" |
52 | |
53 | /* This is the size of the char array in struct sock_addr_un. |
54 | * No Wayland socket can be created with a path longer than this, |
55 | * including the null terminator. |
56 | */ |
57 | #ifndef UNIX_PATH_MAX |
58 | #define UNIX_PATH_MAX 108 |
59 | #endif |
60 | |
61 | #define LOCK_SUFFIX ".lock" |
62 | #define LOCK_SUFFIXLEN 5 |
63 | |
64 | struct wl_socket { |
65 | int fd; |
66 | int fd_lock; |
67 | struct sockaddr_un addr; |
68 | char lock_addr[UNIX_PATH_MAX + LOCK_SUFFIXLEN]; |
69 | struct wl_list link; |
70 | struct wl_event_source *source; |
71 | char *display_name; |
72 | }; |
73 | |
74 | struct wl_client { |
75 | struct wl_connection *connection; |
76 | struct wl_event_source *source; |
77 | struct wl_display *display; |
78 | struct wl_resource *display_resource; |
79 | struct wl_list link; |
80 | struct wl_map objects; |
81 | struct wl_priv_signal destroy_signal; |
82 | pid_t pid; |
83 | uid_t uid; |
84 | gid_t gid; |
85 | int error; |
86 | struct wl_priv_signal resource_created_signal; |
87 | }; |
88 | |
89 | struct wl_display { |
90 | struct wl_event_loop *loop; |
91 | int run; |
92 | |
93 | uint32_t id; |
94 | uint32_t serial; |
95 | |
96 | struct wl_list registry_resource_list; |
97 | struct wl_list global_list; |
98 | struct wl_list socket_list; |
99 | struct wl_list client_list; |
100 | struct wl_list protocol_loggers; |
101 | |
102 | struct wl_priv_signal destroy_signal; |
103 | struct wl_priv_signal create_client_signal; |
104 | |
105 | struct wl_array additional_shm_formats; |
106 | |
107 | wl_display_global_filter_func_t global_filter; |
108 | void *global_filter_data; |
109 | |
110 | int terminate_efd; |
111 | struct wl_event_source *term_source; |
112 | }; |
113 | |
114 | struct wl_global { |
115 | struct wl_display *display; |
116 | const struct wl_interface *interface; |
117 | uint32_t name; |
118 | uint32_t version; |
119 | void *data; |
120 | wl_global_bind_func_t bind; |
121 | struct wl_list link; |
122 | bool removed; |
123 | }; |
124 | |
125 | struct wl_resource { |
126 | struct wl_object object; |
127 | wl_resource_destroy_func_t destroy; |
128 | struct wl_list link; |
129 | /* Unfortunately some users of libwayland (e.g. mesa) still use the |
130 | * deprecated wl_resource struct, even if creating it with the new |
131 | * wl_resource_create(). So we cannot change the layout of the struct |
132 | * unless after the data field. */ |
133 | struct wl_signal deprecated_destroy_signal; |
134 | struct wl_client *client; |
135 | void *data; |
136 | int version; |
137 | wl_dispatcher_func_t dispatcher; |
138 | struct wl_priv_signal destroy_signal; |
139 | }; |
140 | |
141 | struct wl_protocol_logger { |
142 | struct wl_list link; |
143 | wl_protocol_logger_func_t func; |
144 | void *user_data; |
145 | }; |
146 | |
147 | static int debug_server = 0; |
148 | |
149 | static void |
150 | log_closure(struct wl_resource *resource, |
151 | struct wl_closure *closure, int send) |
152 | { |
153 | struct wl_object *object = &resource->object; |
154 | struct wl_display *display = resource->client->display; |
155 | struct wl_protocol_logger *protocol_logger; |
156 | struct wl_protocol_logger_message message; |
157 | |
158 | if (debug_server) |
159 | wl_closure_print(closure, target: object, send, false, NULL); |
160 | |
161 | if (!wl_list_empty(list: &display->protocol_loggers)) { |
162 | message.resource = resource; |
163 | message.message_opcode = closure->opcode; |
164 | message.message = closure->message; |
165 | message.arguments_count = closure->count; |
166 | message.arguments = closure->args; |
167 | wl_list_for_each(protocol_logger, |
168 | &display->protocol_loggers, link) { |
169 | protocol_logger->func(protocol_logger->user_data, |
170 | send ? WL_PROTOCOL_LOGGER_EVENT : |
171 | WL_PROTOCOL_LOGGER_REQUEST, |
172 | &message); |
173 | } |
174 | } |
175 | } |
176 | |
177 | static bool |
178 | verify_objects(struct wl_resource *resource, uint32_t opcode, |
179 | union wl_argument *args) |
180 | { |
181 | struct wl_object *object = &resource->object; |
182 | const char *signature = object->interface->events[opcode].signature; |
183 | struct argument_details arg; |
184 | struct wl_resource *res; |
185 | int count, i; |
186 | |
187 | count = arg_count_for_signature(signature); |
188 | for (i = 0; i < count; i++) { |
189 | signature = get_next_argument(signature, details: &arg); |
190 | switch (arg.type) { |
191 | case 'n': |
192 | case 'o': |
193 | res = (struct wl_resource *) (args[i].o); |
194 | if (res && res->client != resource->client) { |
195 | wl_log(fmt: "compositor bug: The compositor " |
196 | "tried to use an object from one " |
197 | "client in a '%s.%s' for a different " |
198 | "client.\n" , object->interface->name, |
199 | object->interface->events[opcode].name); |
200 | return false; |
201 | } |
202 | } |
203 | } |
204 | return true; |
205 | } |
206 | |
207 | static void |
208 | handle_array(struct wl_resource *resource, uint32_t opcode, |
209 | union wl_argument *args, |
210 | int (*send_func)(struct wl_closure *, struct wl_connection *)) |
211 | { |
212 | struct wl_closure *closure; |
213 | struct wl_object *object = &resource->object; |
214 | |
215 | if (resource->client->error) |
216 | return; |
217 | |
218 | if (!verify_objects(resource, opcode, args)) { |
219 | resource->client->error = 1; |
220 | return; |
221 | } |
222 | |
223 | closure = wl_closure_marshal(sender: object, opcode, args, |
224 | message: &object->interface->events[opcode]); |
225 | |
226 | if (closure == NULL) { |
227 | resource->client->error = 1; |
228 | return; |
229 | } |
230 | |
231 | log_closure(resource, closure, true); |
232 | |
233 | if (send_func(closure, resource->client->connection)) |
234 | resource->client->error = 1; |
235 | |
236 | wl_closure_destroy(closure); |
237 | } |
238 | |
239 | WL_EXPORT void |
240 | wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode, |
241 | union wl_argument *args) |
242 | { |
243 | handle_array(resource, opcode, args, send_func: wl_closure_send); |
244 | } |
245 | |
246 | WL_EXPORT void |
247 | wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...) |
248 | { |
249 | union wl_argument args[WL_CLOSURE_MAX_ARGS]; |
250 | struct wl_object *object = &resource->object; |
251 | va_list ap; |
252 | |
253 | va_start(ap, opcode); |
254 | wl_argument_from_va_list(signature: object->interface->events[opcode].signature, |
255 | args, WL_CLOSURE_MAX_ARGS, ap); |
256 | va_end(ap); |
257 | |
258 | wl_resource_post_event_array(resource, opcode, args); |
259 | } |
260 | |
261 | |
262 | WL_EXPORT void |
263 | wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode, |
264 | union wl_argument *args) |
265 | { |
266 | handle_array(resource, opcode, args, send_func: wl_closure_queue); |
267 | } |
268 | |
269 | WL_EXPORT void |
270 | wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...) |
271 | { |
272 | union wl_argument args[WL_CLOSURE_MAX_ARGS]; |
273 | struct wl_object *object = &resource->object; |
274 | va_list ap; |
275 | |
276 | va_start(ap, opcode); |
277 | wl_argument_from_va_list(signature: object->interface->events[opcode].signature, |
278 | args, WL_CLOSURE_MAX_ARGS, ap); |
279 | va_end(ap); |
280 | |
281 | wl_resource_queue_event_array(resource, opcode, args); |
282 | } |
283 | |
284 | static void |
285 | wl_resource_post_error_vargs(struct wl_resource *resource, |
286 | uint32_t code, const char *msg, va_list argp) |
287 | { |
288 | struct wl_client *client = resource->client; |
289 | char buffer[128]; |
290 | |
291 | vsnprintf(s: buffer, maxlen: sizeof buffer, format: msg, arg: argp); |
292 | |
293 | /* |
294 | * When a client aborts, its resources are destroyed in id order, |
295 | * which means the display resource is destroyed first. If destruction |
296 | * of any later resources results in a protocol error, we end up here |
297 | * with a NULL display_resource. Do not try to send errors to an |
298 | * already dead client. |
299 | */ |
300 | if (client->error || !client->display_resource) |
301 | return; |
302 | |
303 | wl_resource_post_event(resource: client->display_resource, |
304 | WL_DISPLAY_ERROR, resource, code, buffer); |
305 | client->error = 1; |
306 | |
307 | } |
308 | |
309 | WL_EXPORT void |
310 | wl_resource_post_error(struct wl_resource *resource, |
311 | uint32_t code, const char *msg, ...) |
312 | { |
313 | va_list ap; |
314 | |
315 | va_start(ap, msg); |
316 | wl_resource_post_error_vargs(resource, code, msg, argp: ap); |
317 | va_end(ap); |
318 | } |
319 | |
320 | static void |
321 | destroy_client_with_error(struct wl_client *client, const char *reason) |
322 | { |
323 | wl_log(fmt: "%s (pid %u)\n" , reason, client->pid); |
324 | wl_client_destroy(client); |
325 | } |
326 | |
327 | static int |
328 | wl_client_connection_data(int fd, uint32_t mask, void *data) |
329 | { |
330 | struct wl_client *client = data; |
331 | struct wl_connection *connection = client->connection; |
332 | struct wl_resource *resource; |
333 | struct wl_object *object; |
334 | struct wl_closure *closure; |
335 | const struct wl_message *message; |
336 | uint32_t p[2]; |
337 | uint32_t resource_flags; |
338 | int opcode, size, since; |
339 | int len; |
340 | |
341 | if (mask & WL_EVENT_HANGUP) { |
342 | wl_client_destroy(client); |
343 | return 1; |
344 | } |
345 | |
346 | if (mask & WL_EVENT_ERROR) { |
347 | destroy_client_with_error(client, reason: "socket error" ); |
348 | return 1; |
349 | } |
350 | |
351 | if (mask & WL_EVENT_WRITABLE) { |
352 | len = wl_connection_flush(connection); |
353 | if (len < 0 && errno != EAGAIN) { |
354 | destroy_client_with_error( |
355 | client, reason: "failed to flush client connection" ); |
356 | return 1; |
357 | } else if (len >= 0) { |
358 | wl_event_source_fd_update(source: client->source, |
359 | mask: WL_EVENT_READABLE); |
360 | } |
361 | } |
362 | |
363 | len = 0; |
364 | if (mask & WL_EVENT_READABLE) { |
365 | len = wl_connection_read(connection); |
366 | if (len == 0 || (len < 0 && errno != EAGAIN)) { |
367 | destroy_client_with_error( |
368 | client, reason: "failed to read client connection" ); |
369 | return 1; |
370 | } |
371 | } |
372 | |
373 | while (len >= 0 && (size_t) len >= sizeof p) { |
374 | wl_connection_copy(connection, data: p, size: sizeof p); |
375 | opcode = p[1] & 0xffff; |
376 | size = p[1] >> 16; |
377 | if (len < size) |
378 | break; |
379 | |
380 | resource = wl_map_lookup(map: &client->objects, i: p[0]); |
381 | resource_flags = wl_map_lookup_flags(map: &client->objects, i: p[0]); |
382 | if (resource == NULL) { |
383 | wl_resource_post_error(resource: client->display_resource, |
384 | code: WL_DISPLAY_ERROR_INVALID_OBJECT, |
385 | msg: "invalid object %u" , p[0]); |
386 | break; |
387 | } |
388 | |
389 | object = &resource->object; |
390 | if (opcode >= object->interface->method_count) { |
391 | wl_resource_post_error(resource: client->display_resource, |
392 | code: WL_DISPLAY_ERROR_INVALID_METHOD, |
393 | msg: "invalid method %d, object %s@%u" , |
394 | opcode, |
395 | object->interface->name, |
396 | object->id); |
397 | break; |
398 | } |
399 | |
400 | message = &object->interface->methods[opcode]; |
401 | since = wl_message_get_since(message); |
402 | if (!(resource_flags & WL_MAP_ENTRY_LEGACY) && |
403 | resource->version > 0 && resource->version < since) { |
404 | wl_resource_post_error(resource: client->display_resource, |
405 | code: WL_DISPLAY_ERROR_INVALID_METHOD, |
406 | msg: "invalid method %d (since %d < %d)" |
407 | ", object %s@%u" , |
408 | opcode, resource->version, since, |
409 | object->interface->name, |
410 | object->id); |
411 | break; |
412 | } |
413 | |
414 | |
415 | closure = wl_connection_demarshal(connection: client->connection, size, |
416 | objects: &client->objects, message); |
417 | |
418 | if (closure == NULL && errno == ENOMEM) { |
419 | wl_resource_post_no_memory(resource); |
420 | break; |
421 | } else if (closure == NULL || |
422 | wl_closure_lookup_objects(closure, objects: &client->objects) < 0) { |
423 | wl_resource_post_error(resource: client->display_resource, |
424 | code: WL_DISPLAY_ERROR_INVALID_METHOD, |
425 | msg: "invalid arguments for %s@%u.%s" , |
426 | object->interface->name, |
427 | object->id, |
428 | message->name); |
429 | wl_closure_destroy(closure); |
430 | break; |
431 | } |
432 | |
433 | log_closure(resource, closure, false); |
434 | |
435 | if ((resource_flags & WL_MAP_ENTRY_LEGACY) || |
436 | resource->dispatcher == NULL) { |
437 | wl_closure_invoke(closure, flags: WL_CLOSURE_INVOKE_SERVER, |
438 | target: object, opcode, data: client); |
439 | } else { |
440 | wl_closure_dispatch(closure, dispatcher: resource->dispatcher, |
441 | target: object, opcode); |
442 | } |
443 | |
444 | wl_closure_destroy(closure); |
445 | |
446 | if (client->error) |
447 | break; |
448 | |
449 | len = wl_connection_pending_input(connection); |
450 | } |
451 | |
452 | if (client->error) { |
453 | destroy_client_with_error(client, |
454 | reason: "error in client communication" ); |
455 | } |
456 | |
457 | return 1; |
458 | } |
459 | |
460 | /** Flush pending events to the client |
461 | * |
462 | * \param client The client object |
463 | * |
464 | * Events sent to clients are queued in a buffer and written to the |
465 | * socket later - typically when the compositor has handled all |
466 | * requests and goes back to block in the event loop. This function |
467 | * flushes all queued up events for a client immediately. |
468 | * |
469 | * \memberof wl_client |
470 | */ |
471 | WL_EXPORT void |
472 | wl_client_flush(struct wl_client *client) |
473 | { |
474 | wl_connection_flush(connection: client->connection); |
475 | } |
476 | |
477 | /** Get the display object for the given client |
478 | * |
479 | * \param client The client object |
480 | * \return The display object the client is associated with. |
481 | * |
482 | * \memberof wl_client |
483 | */ |
484 | WL_EXPORT struct wl_display * |
485 | wl_client_get_display(struct wl_client *client) |
486 | { |
487 | return client->display; |
488 | } |
489 | |
490 | static int |
491 | bind_display(struct wl_client *client, struct wl_display *display); |
492 | |
493 | /** Create a client for the given file descriptor |
494 | * |
495 | * \param display The display object |
496 | * \param fd The file descriptor for the socket to the client |
497 | * \return The new client object or NULL on failure. |
498 | * |
499 | * Given a file descriptor corresponding to one end of a socket, this |
500 | * function will create a wl_client struct and add the new client to |
501 | * the compositors client list. At that point, the client is |
502 | * initialized and ready to run, as if the client had connected to the |
503 | * servers listening socket. When the client eventually sends |
504 | * requests to the compositor, the wl_client argument to the request |
505 | * handler will be the wl_client returned from this function. |
506 | * |
507 | * The other end of the socket can be passed to |
508 | * wl_display_connect_to_fd() on the client side or used with the |
509 | * WAYLAND_SOCKET environment variable on the client side. |
510 | * |
511 | * Listeners added with wl_display_add_client_created_listener() will |
512 | * be notified by this function after the client is fully constructed. |
513 | * |
514 | * On failure this function sets errno accordingly and returns NULL. |
515 | * |
516 | * \memberof wl_display |
517 | */ |
518 | WL_EXPORT struct wl_client * |
519 | wl_client_create(struct wl_display *display, int fd) |
520 | { |
521 | struct wl_client *client; |
522 | |
523 | client = zalloc(s: sizeof *client); |
524 | if (client == NULL) |
525 | return NULL; |
526 | |
527 | wl_priv_signal_init(signal: &client->resource_created_signal); |
528 | client->display = display; |
529 | client->source = wl_event_loop_add_fd(loop: display->loop, fd, |
530 | mask: WL_EVENT_READABLE, |
531 | func: wl_client_connection_data, data: client); |
532 | |
533 | if (!client->source) |
534 | goto err_client; |
535 | |
536 | if (wl_os_socket_peercred(sockfd: fd, uid: &client->uid, gid: &client->gid, |
537 | pid: &client->pid) != 0) |
538 | goto err_source; |
539 | |
540 | client->connection = wl_connection_create(fd); |
541 | if (client->connection == NULL) |
542 | goto err_source; |
543 | |
544 | wl_map_init(map: &client->objects, WL_MAP_SERVER_SIDE); |
545 | |
546 | if (wl_map_insert_at(map: &client->objects, flags: 0, i: 0, NULL) < 0) |
547 | goto err_map; |
548 | |
549 | wl_priv_signal_init(signal: &client->destroy_signal); |
550 | if (bind_display(client, display) < 0) |
551 | goto err_map; |
552 | |
553 | wl_list_insert(list: display->client_list.prev, elm: &client->link); |
554 | |
555 | wl_priv_signal_emit(signal: &display->create_client_signal, data: client); |
556 | |
557 | return client; |
558 | |
559 | err_map: |
560 | wl_map_release(map: &client->objects); |
561 | wl_connection_destroy(connection: client->connection); |
562 | err_source: |
563 | wl_event_source_remove(source: client->source); |
564 | err_client: |
565 | free(ptr: client); |
566 | return NULL; |
567 | } |
568 | |
569 | /** Return Unix credentials for the client |
570 | * |
571 | * \param client The display object |
572 | * \param pid Returns the process ID |
573 | * \param uid Returns the user ID |
574 | * \param gid Returns the group ID |
575 | * |
576 | * This function returns the process ID, the user ID and the group ID |
577 | * for the given client. The credentials come from getsockopt() with |
578 | * SO_PEERCRED, on the client socket fd. All the pointers can be |
579 | * NULL, if the caller is not interested in a particular ID. |
580 | * |
581 | * Be aware that for clients that a compositor forks and execs and |
582 | * then connects using socketpair(), this function will return the |
583 | * credentials for the compositor. The credentials for the socketpair |
584 | * are set at creation time in the compositor. |
585 | * |
586 | * \memberof wl_client |
587 | */ |
588 | WL_EXPORT void |
589 | wl_client_get_credentials(struct wl_client *client, |
590 | pid_t *pid, uid_t *uid, gid_t *gid) |
591 | { |
592 | if (pid) |
593 | *pid = client->pid; |
594 | if (uid) |
595 | *uid = client->uid; |
596 | if (gid) |
597 | *gid = client->gid; |
598 | } |
599 | |
600 | /** Get the file descriptor for the client |
601 | * |
602 | * \param client The display object |
603 | * \return The file descriptor to use for the connection |
604 | * |
605 | * This function returns the file descriptor for the given client. |
606 | * |
607 | * Be sure to use the file descriptor from the client for inspection only. |
608 | * If the caller does anything to the file descriptor that changes its state, |
609 | * it will likely cause problems. |
610 | * |
611 | * See also wl_client_get_credentials(). |
612 | * It is recommended that you evaluate whether wl_client_get_credentials() |
613 | * can be applied to your use case instead of this function. |
614 | * |
615 | * If you would like to distinguish just between the client and the compositor |
616 | * itself from the client's request, it can be done by getting the client |
617 | * credentials and by checking the PID of the client and the compositor's PID. |
618 | * Regarding the case in which the socketpair() is being used, you need to be |
619 | * careful. Please note the documentation for wl_client_get_credentials(). |
620 | * |
621 | * This function can be used for a compositor to validate a request from |
622 | * a client if there are additional information provided from the client's |
623 | * file descriptor. For instance, suppose you can get the security contexts |
624 | * from the client's file descriptor. The compositor can validate the client's |
625 | * request with the contexts and make a decision whether it permits or deny it. |
626 | * |
627 | * \memberof wl_client |
628 | */ |
629 | WL_EXPORT int |
630 | wl_client_get_fd(struct wl_client *client) |
631 | { |
632 | return wl_connection_get_fd(connection: client->connection); |
633 | } |
634 | |
635 | /** Look up an object in the client name space |
636 | * |
637 | * \param client The client object |
638 | * \param id The object id |
639 | * \return The object or NULL if there is not object for the given ID |
640 | * |
641 | * This looks up an object in the client object name space by its |
642 | * object ID. |
643 | * |
644 | * \memberof wl_client |
645 | */ |
646 | WL_EXPORT struct wl_resource * |
647 | wl_client_get_object(struct wl_client *client, uint32_t id) |
648 | { |
649 | return wl_map_lookup(map: &client->objects, i: id); |
650 | } |
651 | |
652 | WL_EXPORT void |
653 | wl_client_post_no_memory(struct wl_client *client) |
654 | { |
655 | wl_resource_post_error(resource: client->display_resource, |
656 | code: WL_DISPLAY_ERROR_NO_MEMORY, msg: "no memory" ); |
657 | } |
658 | |
659 | /** Report an internal server error |
660 | * |
661 | * \param client The client object |
662 | * \param msg A printf-style format string |
663 | * \param ... Format string arguments |
664 | * |
665 | * Report an unspecified internal implementation error and disconnect |
666 | * the client. |
667 | * |
668 | * \memberof wl_client |
669 | */ |
670 | WL_EXPORT void |
671 | wl_client_post_implementation_error(struct wl_client *client, |
672 | char const *msg, ...) |
673 | { |
674 | va_list ap; |
675 | |
676 | va_start(ap, msg); |
677 | wl_resource_post_error_vargs(resource: client->display_resource, |
678 | code: WL_DISPLAY_ERROR_IMPLEMENTATION, |
679 | msg, argp: ap); |
680 | va_end(ap); |
681 | } |
682 | |
683 | WL_EXPORT void |
684 | wl_resource_post_no_memory(struct wl_resource *resource) |
685 | { |
686 | wl_resource_post_error(resource: resource->client->display_resource, |
687 | code: WL_DISPLAY_ERROR_NO_MEMORY, msg: "no memory" ); |
688 | } |
689 | |
690 | /** Detect if a wl_resource uses the deprecated public definition. |
691 | * |
692 | * Before Wayland 1.2.0, the definition of struct wl_resource was public. |
693 | * It was made opaque just before 1.2.0, and later new fields were added. |
694 | * The new fields cannot be accessed if a program is using the deprecated |
695 | * definition, as there would not be memory allocated for them. |
696 | * |
697 | * The creation pattern for the deprecated definition was wl_resource_init() |
698 | * followed by wl_client_add_resource(). wl_resource_init() was an inline |
699 | * function and no longer exists, but binaries might still carry it. |
700 | * wl_client_add_resource() still exists for ABI compatibility. |
701 | */ |
702 | static bool |
703 | resource_is_deprecated(struct wl_resource *resource) |
704 | { |
705 | struct wl_map *map = &resource->client->objects; |
706 | int id = resource->object.id; |
707 | |
708 | /* wl_client_add_resource() marks deprecated resources with the flag. */ |
709 | if (wl_map_lookup_flags(map, i: id) & WL_MAP_ENTRY_LEGACY) |
710 | return true; |
711 | |
712 | return false; |
713 | } |
714 | |
715 | static enum wl_iterator_result |
716 | destroy_resource(void *element, void *data, uint32_t flags) |
717 | { |
718 | struct wl_resource *resource = element; |
719 | |
720 | wl_signal_emit(signal: &resource->deprecated_destroy_signal, data: resource); |
721 | /* Don't emit the new signal for deprecated resources, as that would |
722 | * access memory outside the bounds of the deprecated struct */ |
723 | if (!resource_is_deprecated(resource)) |
724 | wl_priv_signal_final_emit(signal: &resource->destroy_signal, data: resource); |
725 | |
726 | if (resource->destroy) |
727 | resource->destroy(resource); |
728 | |
729 | if (!(flags & WL_MAP_ENTRY_LEGACY)) |
730 | free(ptr: resource); |
731 | |
732 | return WL_ITERATOR_CONTINUE; |
733 | } |
734 | |
735 | WL_EXPORT void |
736 | wl_resource_destroy(struct wl_resource *resource) |
737 | { |
738 | struct wl_client *client = resource->client; |
739 | uint32_t id; |
740 | uint32_t flags; |
741 | |
742 | id = resource->object.id; |
743 | flags = wl_map_lookup_flags(map: &client->objects, i: id); |
744 | destroy_resource(element: resource, NULL, flags); |
745 | |
746 | if (id < WL_SERVER_ID_START) { |
747 | if (client->display_resource) { |
748 | wl_resource_queue_event(resource: client->display_resource, |
749 | WL_DISPLAY_DELETE_ID, id); |
750 | } |
751 | wl_map_insert_at(map: &client->objects, flags: 0, i: id, NULL); |
752 | } else { |
753 | wl_map_remove(map: &client->objects, i: id); |
754 | } |
755 | } |
756 | |
757 | WL_EXPORT uint32_t |
758 | wl_resource_get_id(struct wl_resource *resource) |
759 | { |
760 | return resource->object.id; |
761 | } |
762 | |
763 | WL_EXPORT struct wl_list * |
764 | wl_resource_get_link(struct wl_resource *resource) |
765 | { |
766 | return &resource->link; |
767 | } |
768 | |
769 | WL_EXPORT struct wl_resource * |
770 | wl_resource_from_link(struct wl_list *link) |
771 | { |
772 | struct wl_resource *resource; |
773 | |
774 | return wl_container_of(link, resource, link); |
775 | } |
776 | |
777 | WL_EXPORT struct wl_resource * |
778 | wl_resource_find_for_client(struct wl_list *list, struct wl_client *client) |
779 | { |
780 | struct wl_resource *resource; |
781 | |
782 | if (client == NULL) |
783 | return NULL; |
784 | |
785 | wl_list_for_each(resource, list, link) { |
786 | if (resource->client == client) |
787 | return resource; |
788 | } |
789 | |
790 | return NULL; |
791 | } |
792 | |
793 | WL_EXPORT struct wl_client * |
794 | wl_resource_get_client(struct wl_resource *resource) |
795 | { |
796 | return resource->client; |
797 | } |
798 | |
799 | WL_EXPORT void |
800 | wl_resource_set_user_data(struct wl_resource *resource, void *data) |
801 | { |
802 | resource->data = data; |
803 | } |
804 | |
805 | WL_EXPORT void * |
806 | wl_resource_get_user_data(struct wl_resource *resource) |
807 | { |
808 | return resource->data; |
809 | } |
810 | |
811 | WL_EXPORT int |
812 | wl_resource_get_version(struct wl_resource *resource) |
813 | { |
814 | return resource->version; |
815 | } |
816 | |
817 | WL_EXPORT void |
818 | wl_resource_set_destructor(struct wl_resource *resource, |
819 | wl_resource_destroy_func_t destroy) |
820 | { |
821 | resource->destroy = destroy; |
822 | } |
823 | |
824 | WL_EXPORT int |
825 | wl_resource_instance_of(struct wl_resource *resource, |
826 | const struct wl_interface *interface, |
827 | const void *implementation) |
828 | { |
829 | return wl_interface_equal(iface1: resource->object.interface, iface2: interface) && |
830 | resource->object.implementation == implementation; |
831 | } |
832 | |
833 | WL_EXPORT void |
834 | wl_resource_add_destroy_listener(struct wl_resource *resource, |
835 | struct wl_listener * listener) |
836 | { |
837 | if (resource_is_deprecated(resource)) |
838 | wl_signal_add(signal: &resource->deprecated_destroy_signal, listener); |
839 | else |
840 | wl_priv_signal_add(signal: &resource->destroy_signal, listener); |
841 | } |
842 | |
843 | WL_EXPORT struct wl_listener * |
844 | wl_resource_get_destroy_listener(struct wl_resource *resource, |
845 | wl_notify_func_t notify) |
846 | { |
847 | if (resource_is_deprecated(resource)) |
848 | return wl_signal_get(signal: &resource->deprecated_destroy_signal, notify); |
849 | return wl_priv_signal_get(signal: &resource->destroy_signal, notify); |
850 | } |
851 | |
852 | /** Retrieve the interface name (class) of a resource object. |
853 | * |
854 | * \param resource The resource object |
855 | * |
856 | * \memberof wl_resource |
857 | */ |
858 | WL_EXPORT const char * |
859 | wl_resource_get_class(struct wl_resource *resource) |
860 | { |
861 | return resource->object.interface->name; |
862 | } |
863 | |
864 | WL_EXPORT void |
865 | wl_client_add_destroy_listener(struct wl_client *client, |
866 | struct wl_listener *listener) |
867 | { |
868 | wl_priv_signal_add(signal: &client->destroy_signal, listener); |
869 | } |
870 | |
871 | WL_EXPORT struct wl_listener * |
872 | wl_client_get_destroy_listener(struct wl_client *client, |
873 | wl_notify_func_t notify) |
874 | { |
875 | return wl_priv_signal_get(signal: &client->destroy_signal, notify); |
876 | } |
877 | |
878 | WL_EXPORT void |
879 | wl_client_destroy(struct wl_client *client) |
880 | { |
881 | uint32_t serial = 0; |
882 | |
883 | wl_priv_signal_final_emit(signal: &client->destroy_signal, data: client); |
884 | |
885 | wl_client_flush(client); |
886 | wl_map_for_each(map: &client->objects, func: destroy_resource, data: &serial); |
887 | wl_map_release(map: &client->objects); |
888 | wl_event_source_remove(source: client->source); |
889 | close(fd: wl_connection_destroy(connection: client->connection)); |
890 | wl_list_remove(elm: &client->link); |
891 | wl_list_remove(elm: &client->resource_created_signal.listener_list); |
892 | free(ptr: client); |
893 | } |
894 | |
895 | /* Check if a global filter is registered and use it if any. |
896 | * |
897 | * If no wl_global filter has been registered, this function will |
898 | * return true, allowing the wl_global to be visible to the wl_client |
899 | */ |
900 | static bool |
901 | wl_global_is_visible(const struct wl_client *client, |
902 | const struct wl_global *global) |
903 | { |
904 | struct wl_display *display = client->display; |
905 | |
906 | return (display->global_filter == NULL || |
907 | display->global_filter(client, global, display->global_filter_data)); |
908 | } |
909 | |
910 | static void |
911 | registry_bind(struct wl_client *client, |
912 | struct wl_resource *resource, uint32_t name, |
913 | const char *interface, uint32_t version, uint32_t id) |
914 | { |
915 | struct wl_global *global; |
916 | struct wl_display *display = resource->data; |
917 | |
918 | wl_list_for_each(global, &display->global_list, link) |
919 | if (global->name == name) |
920 | break; |
921 | |
922 | if (&global->link == &display->global_list) |
923 | wl_resource_post_error(resource, |
924 | code: WL_DISPLAY_ERROR_INVALID_OBJECT, |
925 | msg: "invalid global %s (%d)" , interface, name); |
926 | else if (strcmp(s1: global->interface->name, s2: interface) != 0) |
927 | wl_resource_post_error(resource, |
928 | code: WL_DISPLAY_ERROR_INVALID_OBJECT, |
929 | msg: "invalid interface for global %u: " |
930 | "have %s, wanted %s" , |
931 | name, interface, global->interface->name); |
932 | else if (version == 0) |
933 | wl_resource_post_error(resource, |
934 | code: WL_DISPLAY_ERROR_INVALID_OBJECT, |
935 | msg: "invalid version for global %s (%d): 0 is not a valid version" , |
936 | interface, name); |
937 | else if (global->version < version) |
938 | wl_resource_post_error(resource, |
939 | code: WL_DISPLAY_ERROR_INVALID_OBJECT, |
940 | msg: "invalid version for global %s (%d): have %d, wanted %d" , |
941 | interface, name, global->version, version); |
942 | else if (!wl_global_is_visible(client, global)) |
943 | wl_resource_post_error(resource, |
944 | code: WL_DISPLAY_ERROR_INVALID_OBJECT, |
945 | msg: "invalid global %s (%d)" , interface, name); |
946 | else |
947 | global->bind(client, global->data, version, id); |
948 | } |
949 | |
950 | static const struct wl_registry_interface registry_interface = { |
951 | registry_bind |
952 | }; |
953 | |
954 | static void |
955 | display_sync(struct wl_client *client, |
956 | struct wl_resource *resource, uint32_t id) |
957 | { |
958 | struct wl_resource *callback; |
959 | uint32_t serial; |
960 | |
961 | callback = wl_resource_create(client, interface: &wl_callback_interface, version: 1, id); |
962 | if (callback == NULL) { |
963 | wl_client_post_no_memory(client); |
964 | return; |
965 | } |
966 | |
967 | serial = wl_display_get_serial(display: client->display); |
968 | wl_callback_send_done(resource_: callback, callback_data: serial); |
969 | wl_resource_destroy(resource: callback); |
970 | } |
971 | |
972 | static void |
973 | unbind_resource(struct wl_resource *resource) |
974 | { |
975 | wl_list_remove(elm: &resource->link); |
976 | } |
977 | |
978 | static void |
979 | display_get_registry(struct wl_client *client, |
980 | struct wl_resource *resource, uint32_t id) |
981 | { |
982 | struct wl_display *display = resource->data; |
983 | struct wl_resource *registry_resource; |
984 | struct wl_global *global; |
985 | |
986 | registry_resource = |
987 | wl_resource_create(client, interface: &wl_registry_interface, version: 1, id); |
988 | if (registry_resource == NULL) { |
989 | wl_client_post_no_memory(client); |
990 | return; |
991 | } |
992 | |
993 | wl_resource_set_implementation(resource: registry_resource, |
994 | implementation: ®istry_interface, |
995 | data: display, destroy: unbind_resource); |
996 | |
997 | wl_list_insert(list: &display->registry_resource_list, |
998 | elm: ®istry_resource->link); |
999 | |
1000 | wl_list_for_each(global, &display->global_list, link) |
1001 | if (wl_global_is_visible(client, global) && !global->removed) |
1002 | wl_resource_post_event(resource: registry_resource, |
1003 | WL_REGISTRY_GLOBAL, |
1004 | global->name, |
1005 | global->interface->name, |
1006 | global->version); |
1007 | } |
1008 | |
1009 | static const struct wl_display_interface display_interface = { |
1010 | display_sync, |
1011 | display_get_registry |
1012 | }; |
1013 | |
1014 | static void |
1015 | destroy_client_display_resource(struct wl_resource *resource) |
1016 | { |
1017 | resource->client->display_resource = NULL; |
1018 | } |
1019 | |
1020 | static int |
1021 | bind_display(struct wl_client *client, struct wl_display *display) |
1022 | { |
1023 | client->display_resource = |
1024 | wl_resource_create(client, interface: &wl_display_interface, version: 1, id: 1); |
1025 | if (client->display_resource == NULL) { |
1026 | /* DON'T send no-memory error to client - it has no |
1027 | * resource to which it could post the event */ |
1028 | return -1; |
1029 | } |
1030 | |
1031 | wl_resource_set_implementation(resource: client->display_resource, |
1032 | implementation: &display_interface, data: display, |
1033 | destroy: destroy_client_display_resource); |
1034 | return 0; |
1035 | } |
1036 | |
1037 | static int |
1038 | handle_display_terminate(int fd, uint32_t mask, void *data) { |
1039 | uint64_t term_event; |
1040 | |
1041 | if (read(fd: fd, buf: &term_event, nbytes: sizeof(term_event)) < 0 && errno != EAGAIN) |
1042 | return -1; |
1043 | |
1044 | return 0; |
1045 | } |
1046 | |
1047 | /** Create Wayland display object. |
1048 | * |
1049 | * \return The Wayland display object. Null if failed to create |
1050 | * |
1051 | * This creates the wl_display object. |
1052 | * |
1053 | * \memberof wl_display |
1054 | */ |
1055 | WL_EXPORT struct wl_display * |
1056 | wl_display_create(void) |
1057 | { |
1058 | struct wl_display *display; |
1059 | const char *debug; |
1060 | |
1061 | debug = getenv(name: "WAYLAND_DEBUG" ); |
1062 | if (debug && (strstr(haystack: debug, needle: "server" ) || strstr(haystack: debug, needle: "1" ))) |
1063 | debug_server = 1; |
1064 | |
1065 | display = malloc(size: sizeof *display); |
1066 | if (display == NULL) |
1067 | return NULL; |
1068 | |
1069 | display->loop = wl_event_loop_create(); |
1070 | if (display->loop == NULL) { |
1071 | free(ptr: display); |
1072 | return NULL; |
1073 | } |
1074 | |
1075 | display->terminate_efd = eventfd(count: 0, EFD_CLOEXEC | EFD_NONBLOCK); |
1076 | if (display->terminate_efd < 0) |
1077 | goto err_eventfd; |
1078 | |
1079 | display->term_source = wl_event_loop_add_fd(loop: display->loop, |
1080 | fd: display->terminate_efd, |
1081 | mask: WL_EVENT_READABLE, |
1082 | func: handle_display_terminate, |
1083 | NULL); |
1084 | |
1085 | if (display->term_source == NULL) |
1086 | goto err_term_source; |
1087 | |
1088 | wl_list_init(list: &display->global_list); |
1089 | wl_list_init(list: &display->socket_list); |
1090 | wl_list_init(list: &display->client_list); |
1091 | wl_list_init(list: &display->registry_resource_list); |
1092 | wl_list_init(list: &display->protocol_loggers); |
1093 | |
1094 | wl_priv_signal_init(signal: &display->destroy_signal); |
1095 | wl_priv_signal_init(signal: &display->create_client_signal); |
1096 | |
1097 | display->id = 1; |
1098 | display->serial = 0; |
1099 | |
1100 | display->global_filter = NULL; |
1101 | display->global_filter_data = NULL; |
1102 | |
1103 | wl_array_init(array: &display->additional_shm_formats); |
1104 | |
1105 | return display; |
1106 | |
1107 | err_term_source: |
1108 | close(fd: display->terminate_efd); |
1109 | err_eventfd: |
1110 | wl_event_loop_destroy(loop: display->loop); |
1111 | free(ptr: display); |
1112 | return NULL; |
1113 | } |
1114 | |
1115 | static void |
1116 | wl_socket_destroy(struct wl_socket *s) |
1117 | { |
1118 | if (s->source) |
1119 | wl_event_source_remove(source: s->source); |
1120 | if (s->addr.sun_path[0]) |
1121 | unlink(name: s->addr.sun_path); |
1122 | if (s->fd >= 0) |
1123 | close(fd: s->fd); |
1124 | if (s->lock_addr[0]) |
1125 | unlink(name: s->lock_addr); |
1126 | if (s->fd_lock >= 0) |
1127 | close(fd: s->fd_lock); |
1128 | |
1129 | free(ptr: s); |
1130 | } |
1131 | |
1132 | static struct wl_socket * |
1133 | wl_socket_alloc(void) |
1134 | { |
1135 | struct wl_socket *s; |
1136 | |
1137 | s = zalloc(s: sizeof *s); |
1138 | if (!s) |
1139 | return NULL; |
1140 | |
1141 | s->fd = -1; |
1142 | s->fd_lock = -1; |
1143 | |
1144 | return s; |
1145 | } |
1146 | |
1147 | /** Destroy Wayland display object. |
1148 | * |
1149 | * \param display The Wayland display object which should be destroyed. |
1150 | * \return None. |
1151 | * |
1152 | * This function emits the wl_display destroy signal, releases |
1153 | * all the sockets added to this display, free's all the globals associated |
1154 | * with this display, free's memory of additional shared memory formats and |
1155 | * destroy the display object. |
1156 | * |
1157 | * \sa wl_display_add_destroy_listener |
1158 | * |
1159 | * \memberof wl_display |
1160 | */ |
1161 | WL_EXPORT void |
1162 | wl_display_destroy(struct wl_display *display) |
1163 | { |
1164 | struct wl_socket *s, *next; |
1165 | struct wl_global *global, *gnext; |
1166 | |
1167 | wl_priv_signal_final_emit(signal: &display->destroy_signal, data: display); |
1168 | |
1169 | wl_list_for_each_safe(s, next, &display->socket_list, link) { |
1170 | wl_socket_destroy(s); |
1171 | } |
1172 | |
1173 | close(fd: display->terminate_efd); |
1174 | wl_event_source_remove(source: display->term_source); |
1175 | |
1176 | wl_event_loop_destroy(loop: display->loop); |
1177 | |
1178 | wl_list_for_each_safe(global, gnext, &display->global_list, link) |
1179 | free(ptr: global); |
1180 | |
1181 | wl_array_release(array: &display->additional_shm_formats); |
1182 | |
1183 | wl_list_remove(elm: &display->protocol_loggers); |
1184 | |
1185 | free(ptr: display); |
1186 | } |
1187 | |
1188 | /** Set a filter function for global objects |
1189 | * |
1190 | * \param display The Wayland display object. |
1191 | * \param filter The global filter function. |
1192 | * \param data User data to be associated with the global filter. |
1193 | * \return None. |
1194 | * |
1195 | * Set a filter for the wl_display to advertise or hide global objects |
1196 | * to clients. |
1197 | * The set filter will be used during wl_global advertisement to |
1198 | * determine whether a global object should be advertised to a |
1199 | * given client, and during wl_global binding to determine whether |
1200 | * a given client should be allowed to bind to a global. |
1201 | * |
1202 | * Clients that try to bind to a global that was filtered out will |
1203 | * have an error raised. |
1204 | * |
1205 | * Setting the filter NULL will result in all globals being |
1206 | * advertised to all clients. The default is no filter. |
1207 | * |
1208 | * \memberof wl_display |
1209 | */ |
1210 | WL_EXPORT void |
1211 | wl_display_set_global_filter(struct wl_display *display, |
1212 | wl_display_global_filter_func_t filter, |
1213 | void *data) |
1214 | { |
1215 | display->global_filter = filter; |
1216 | display->global_filter_data = data; |
1217 | } |
1218 | |
1219 | WL_EXPORT struct wl_global * |
1220 | wl_global_create(struct wl_display *display, |
1221 | const struct wl_interface *interface, int version, |
1222 | void *data, wl_global_bind_func_t bind) |
1223 | { |
1224 | struct wl_global *global; |
1225 | struct wl_resource *resource; |
1226 | |
1227 | if (version < 1) { |
1228 | wl_log(fmt: "wl_global_create: failing to create interface " |
1229 | "'%s' with version %d because it is less than 1\n" , |
1230 | interface->name, version); |
1231 | return NULL; |
1232 | } |
1233 | |
1234 | if (version > interface->version) { |
1235 | wl_log(fmt: "wl_global_create: implemented version for '%s' " |
1236 | "higher than interface version (%d > %d)\n" , |
1237 | interface->name, version, interface->version); |
1238 | return NULL; |
1239 | } |
1240 | |
1241 | global = malloc(size: sizeof *global); |
1242 | if (global == NULL) |
1243 | return NULL; |
1244 | |
1245 | global->display = display; |
1246 | global->name = display->id++; |
1247 | global->interface = interface; |
1248 | global->version = version; |
1249 | global->data = data; |
1250 | global->bind = bind; |
1251 | global->removed = false; |
1252 | wl_list_insert(list: display->global_list.prev, elm: &global->link); |
1253 | |
1254 | wl_list_for_each(resource, &display->registry_resource_list, link) |
1255 | wl_resource_post_event(resource, |
1256 | WL_REGISTRY_GLOBAL, |
1257 | global->name, |
1258 | global->interface->name, |
1259 | global->version); |
1260 | |
1261 | return global; |
1262 | } |
1263 | |
1264 | /** Remove the global |
1265 | * |
1266 | * \param global The Wayland global. |
1267 | * |
1268 | * Broadcast a global remove event to all clients without destroying the |
1269 | * global. This function can only be called once per global. |
1270 | * |
1271 | * wl_global_destroy() removes the global and immediately destroys it. On |
1272 | * the other end, this function only removes the global, allowing clients |
1273 | * that have not yet received the global remove event to continue to bind to |
1274 | * it. |
1275 | * |
1276 | * This can be used by compositors to mitigate clients being disconnected |
1277 | * because a global has been added and removed too quickly. Compositors can call |
1278 | * wl_global_remove(), then wait an implementation-defined amount of time, then |
1279 | * call wl_global_destroy(). Note that the destruction of a global is still |
1280 | * racy, since clients have no way to acknowledge that they received the remove |
1281 | * event. |
1282 | * |
1283 | * \since 1.17.90 |
1284 | */ |
1285 | WL_EXPORT void |
1286 | wl_global_remove(struct wl_global *global) |
1287 | { |
1288 | struct wl_display *display = global->display; |
1289 | struct wl_resource *resource; |
1290 | |
1291 | if (global->removed) |
1292 | wl_abort(fmt: "wl_global_remove: called twice on the same " |
1293 | "global '%s@%" PRIu32"'" , global->interface->name, |
1294 | global->name); |
1295 | |
1296 | wl_list_for_each(resource, &display->registry_resource_list, link) |
1297 | wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE, |
1298 | global->name); |
1299 | |
1300 | global->removed = true; |
1301 | } |
1302 | |
1303 | WL_EXPORT void |
1304 | wl_global_destroy(struct wl_global *global) |
1305 | { |
1306 | if (!global->removed) |
1307 | wl_global_remove(global); |
1308 | wl_list_remove(elm: &global->link); |
1309 | free(ptr: global); |
1310 | } |
1311 | |
1312 | WL_EXPORT const struct wl_interface * |
1313 | wl_global_get_interface(const struct wl_global *global) |
1314 | { |
1315 | return global->interface; |
1316 | } |
1317 | |
1318 | /** Get the display object for the given global |
1319 | * |
1320 | * \param global The global object |
1321 | * \return The display object the global is associated with. |
1322 | * |
1323 | * \memberof wl_global |
1324 | * \since 1.20 |
1325 | */ |
1326 | WL_EXPORT struct wl_display * |
1327 | wl_global_get_display(const struct wl_global *global) |
1328 | { |
1329 | return global->display; |
1330 | } |
1331 | |
1332 | WL_EXPORT void * |
1333 | wl_global_get_user_data(const struct wl_global *global) |
1334 | { |
1335 | return global->data; |
1336 | } |
1337 | |
1338 | /** Set the global's user data |
1339 | * |
1340 | * \param global The global object |
1341 | * \param data The user data pointer |
1342 | * |
1343 | * \since 1.17.90 |
1344 | */ |
1345 | WL_EXPORT void |
1346 | wl_global_set_user_data(struct wl_global *global, void *data) |
1347 | { |
1348 | global->data = data; |
1349 | } |
1350 | |
1351 | /** Get the current serial number |
1352 | * |
1353 | * \param display The display object |
1354 | * |
1355 | * This function returns the most recent serial number, but does not |
1356 | * increment it. |
1357 | * |
1358 | * \memberof wl_display |
1359 | */ |
1360 | WL_EXPORT uint32_t |
1361 | wl_display_get_serial(struct wl_display *display) |
1362 | { |
1363 | return display->serial; |
1364 | } |
1365 | |
1366 | /** Get the next serial number |
1367 | * |
1368 | * \param display The display object |
1369 | * |
1370 | * This function increments the display serial number and returns the |
1371 | * new value. |
1372 | * |
1373 | * \memberof wl_display |
1374 | */ |
1375 | WL_EXPORT uint32_t |
1376 | wl_display_next_serial(struct wl_display *display) |
1377 | { |
1378 | display->serial++; |
1379 | |
1380 | return display->serial; |
1381 | } |
1382 | |
1383 | WL_EXPORT struct wl_event_loop * |
1384 | wl_display_get_event_loop(struct wl_display *display) |
1385 | { |
1386 | return display->loop; |
1387 | } |
1388 | |
1389 | WL_EXPORT void |
1390 | wl_display_terminate(struct wl_display *display) |
1391 | { |
1392 | int ret; |
1393 | uint64_t terminate = 1; |
1394 | |
1395 | display->run = 0; |
1396 | |
1397 | ret = write(fd: display->terminate_efd, buf: &terminate, n: sizeof(terminate)); |
1398 | assert (ret >= 0 || errno == EAGAIN); |
1399 | } |
1400 | |
1401 | WL_EXPORT void |
1402 | wl_display_run(struct wl_display *display) |
1403 | { |
1404 | display->run = 1; |
1405 | |
1406 | while (display->run) { |
1407 | wl_display_flush_clients(display); |
1408 | wl_event_loop_dispatch(loop: display->loop, timeout: -1); |
1409 | } |
1410 | } |
1411 | |
1412 | WL_EXPORT void |
1413 | wl_display_flush_clients(struct wl_display *display) |
1414 | { |
1415 | struct wl_client *client, *next; |
1416 | int ret; |
1417 | |
1418 | wl_list_for_each_safe(client, next, &display->client_list, link) { |
1419 | ret = wl_connection_flush(connection: client->connection); |
1420 | if (ret < 0 && errno == EAGAIN) { |
1421 | wl_event_source_fd_update(source: client->source, |
1422 | mask: WL_EVENT_WRITABLE | |
1423 | WL_EVENT_READABLE); |
1424 | } else if (ret < 0) { |
1425 | wl_client_destroy(client); |
1426 | } |
1427 | } |
1428 | } |
1429 | |
1430 | /** Destroy all clients connected to the display |
1431 | * |
1432 | * \param display The display object |
1433 | * |
1434 | * This function should be called right before wl_display_destroy() to ensure |
1435 | * all client resources are closed properly. Destroying a client from within |
1436 | * wl_display_destroy_clients() is safe, but creating one will leak resources |
1437 | * and raise a warning. |
1438 | * |
1439 | * \memberof wl_display |
1440 | */ |
1441 | WL_EXPORT void |
1442 | wl_display_destroy_clients(struct wl_display *display) |
1443 | { |
1444 | struct wl_list tmp_client_list, *pos; |
1445 | struct wl_client *client; |
1446 | |
1447 | /* Move the whole client list to a temporary head because some new clients |
1448 | * might be added to the original head. */ |
1449 | wl_list_init(list: &tmp_client_list); |
1450 | wl_list_insert_list(list: &tmp_client_list, other: &display->client_list); |
1451 | wl_list_init(list: &display->client_list); |
1452 | |
1453 | /* wl_list_for_each_safe isn't enough here: it fails if the next client is |
1454 | * destroyed by the destroy handler of the current one. */ |
1455 | while (!wl_list_empty(list: &tmp_client_list)) { |
1456 | pos = tmp_client_list.next; |
1457 | client = wl_container_of(pos, client, link); |
1458 | |
1459 | wl_client_destroy(client); |
1460 | } |
1461 | |
1462 | if (!wl_list_empty(list: &display->client_list)) { |
1463 | wl_log(fmt: "wl_display_destroy_clients: cannot destroy all clients because " |
1464 | "new ones were created by destroy callbacks\n" ); |
1465 | } |
1466 | } |
1467 | |
1468 | static int |
1469 | socket_data(int fd, uint32_t mask, void *data) |
1470 | { |
1471 | struct wl_display *display = data; |
1472 | struct sockaddr_un name; |
1473 | socklen_t length; |
1474 | int client_fd; |
1475 | |
1476 | length = sizeof name; |
1477 | client_fd = wl_os_accept_cloexec(sockfd: fd, addr: (struct sockaddr *) &name, |
1478 | addrlen: &length); |
1479 | if (client_fd < 0) |
1480 | wl_log(fmt: "failed to accept: %s\n" , strerror(errno)); |
1481 | else |
1482 | if (!wl_client_create(display, fd: client_fd)) |
1483 | close(fd: client_fd); |
1484 | |
1485 | return 1; |
1486 | } |
1487 | |
1488 | static int |
1489 | wl_socket_lock(struct wl_socket *socket) |
1490 | { |
1491 | struct stat socket_stat; |
1492 | |
1493 | snprintf(s: socket->lock_addr, maxlen: sizeof socket->lock_addr, |
1494 | format: "%s%s" , socket->addr.sun_path, LOCK_SUFFIX); |
1495 | |
1496 | socket->fd_lock = open(file: socket->lock_addr, O_CREAT | O_CLOEXEC | O_RDWR, |
1497 | (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)); |
1498 | |
1499 | if (socket->fd_lock < 0) { |
1500 | wl_log(fmt: "unable to open lockfile %s check permissions\n" , |
1501 | socket->lock_addr); |
1502 | goto err; |
1503 | } |
1504 | |
1505 | if (flock(fd: socket->fd_lock, LOCK_EX | LOCK_NB) < 0) { |
1506 | wl_log(fmt: "unable to lock lockfile %s, maybe another compositor is running\n" , |
1507 | socket->lock_addr); |
1508 | goto err_fd; |
1509 | } |
1510 | |
1511 | if (lstat(file: socket->addr.sun_path, buf: &socket_stat) < 0 ) { |
1512 | if (errno != ENOENT) { |
1513 | wl_log(fmt: "did not manage to stat file %s\n" , |
1514 | socket->addr.sun_path); |
1515 | goto err_fd; |
1516 | } |
1517 | } else if (socket_stat.st_mode & S_IWUSR || |
1518 | socket_stat.st_mode & S_IWGRP) { |
1519 | unlink(name: socket->addr.sun_path); |
1520 | } |
1521 | |
1522 | return 0; |
1523 | err_fd: |
1524 | close(fd: socket->fd_lock); |
1525 | socket->fd_lock = -1; |
1526 | err: |
1527 | *socket->lock_addr = 0; |
1528 | /* we did not set this value here, but without lock the |
1529 | * socket won't be created anyway. This prevents the |
1530 | * wl_socket_destroy from unlinking already existing socket |
1531 | * created by other compositor */ |
1532 | *socket->addr.sun_path = 0; |
1533 | |
1534 | return -1; |
1535 | } |
1536 | |
1537 | static int |
1538 | wl_socket_init_for_display_name(struct wl_socket *s, const char *name) |
1539 | { |
1540 | int name_size; |
1541 | const char *runtime_dir = "" ; |
1542 | const char *separator = "" ; |
1543 | |
1544 | if (name[0] != '/') { |
1545 | runtime_dir = getenv(name: "XDG_RUNTIME_DIR" ); |
1546 | if (!runtime_dir) { |
1547 | wl_log(fmt: "error: XDG_RUNTIME_DIR not set in the environment\n" ); |
1548 | |
1549 | /* to prevent programs reporting |
1550 | * "failed to add socket: Success" */ |
1551 | errno = ENOENT; |
1552 | return -1; |
1553 | } |
1554 | separator = "/" ; |
1555 | } |
1556 | |
1557 | s->addr.sun_family = AF_LOCAL; |
1558 | name_size = snprintf(s: s->addr.sun_path, maxlen: sizeof s->addr.sun_path, |
1559 | format: "%s%s%s" , runtime_dir, separator, name) + 1; |
1560 | |
1561 | assert(name_size > 0); |
1562 | if (name_size > (int)sizeof s->addr.sun_path) { |
1563 | wl_log(fmt: "error: socket path \"%s%s%s\" plus null terminator" |
1564 | " exceeds 108 bytes\n" , runtime_dir, separator, name); |
1565 | *s->addr.sun_path = 0; |
1566 | /* to prevent programs reporting |
1567 | * "failed to add socket: Success" */ |
1568 | errno = ENAMETOOLONG; |
1569 | return -1; |
1570 | } |
1571 | |
1572 | s->display_name = (s->addr.sun_path + name_size - 1) - strlen(s: name); |
1573 | |
1574 | return 0; |
1575 | } |
1576 | |
1577 | static int |
1578 | _wl_display_add_socket(struct wl_display *display, struct wl_socket *s) |
1579 | { |
1580 | socklen_t size; |
1581 | |
1582 | s->fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, protocol: 0); |
1583 | if (s->fd < 0) { |
1584 | return -1; |
1585 | } |
1586 | |
1587 | size = offsetof (struct sockaddr_un, sun_path) + strlen(s: s->addr.sun_path); |
1588 | if (bind(fd: s->fd, addr: (struct sockaddr *) &s->addr, len: size) < 0) { |
1589 | wl_log(fmt: "bind() failed with error: %s\n" , strerror(errno)); |
1590 | return -1; |
1591 | } |
1592 | |
1593 | if (listen(fd: s->fd, n: 128) < 0) { |
1594 | wl_log(fmt: "listen() failed with error: %s\n" , strerror(errno)); |
1595 | return -1; |
1596 | } |
1597 | |
1598 | s->source = wl_event_loop_add_fd(loop: display->loop, fd: s->fd, |
1599 | mask: WL_EVENT_READABLE, |
1600 | func: socket_data, data: display); |
1601 | if (s->source == NULL) { |
1602 | return -1; |
1603 | } |
1604 | |
1605 | wl_list_insert(list: display->socket_list.prev, elm: &s->link); |
1606 | return 0; |
1607 | } |
1608 | |
1609 | WL_EXPORT const char * |
1610 | wl_display_add_socket_auto(struct wl_display *display) |
1611 | { |
1612 | struct wl_socket *s; |
1613 | int displayno = 0; |
1614 | char display_name[16] = "" ; |
1615 | |
1616 | /* A reasonable number of maximum default sockets. If |
1617 | * you need more than this, use the explicit add_socket API. */ |
1618 | const int MAX_DISPLAYNO = 32; |
1619 | |
1620 | s = wl_socket_alloc(); |
1621 | if (s == NULL) |
1622 | return NULL; |
1623 | |
1624 | do { |
1625 | snprintf(s: display_name, maxlen: sizeof display_name, format: "wayland-%d" , displayno); |
1626 | if (wl_socket_init_for_display_name(s, name: display_name) < 0) { |
1627 | wl_socket_destroy(s); |
1628 | return NULL; |
1629 | } |
1630 | |
1631 | if (wl_socket_lock(socket: s) < 0) |
1632 | continue; |
1633 | |
1634 | if (_wl_display_add_socket(display, s) < 0) { |
1635 | wl_socket_destroy(s); |
1636 | return NULL; |
1637 | } |
1638 | |
1639 | return s->display_name; |
1640 | } while (displayno++ < MAX_DISPLAYNO); |
1641 | |
1642 | /* Ran out of display names. */ |
1643 | wl_socket_destroy(s); |
1644 | errno = EINVAL; |
1645 | return NULL; |
1646 | } |
1647 | |
1648 | /** Add a socket with an existing fd to Wayland display for the clients to connect. |
1649 | * |
1650 | * \param display Wayland display to which the socket should be added. |
1651 | * \param sock_fd The existing socket file descriptor to be used |
1652 | * \return 0 if success. -1 if failed. |
1653 | * |
1654 | * The existing socket fd must already be created, opened, and locked. |
1655 | * The fd must be properly set to CLOEXEC and bound to a socket file |
1656 | * with both bind() and listen() already called. |
1657 | * |
1658 | * \memberof wl_display |
1659 | */ |
1660 | WL_EXPORT int |
1661 | wl_display_add_socket_fd(struct wl_display *display, int sock_fd) |
1662 | { |
1663 | struct wl_socket *s; |
1664 | struct stat buf; |
1665 | |
1666 | /* Require a valid fd or fail */ |
1667 | if (sock_fd < 0 || fstat(fd: sock_fd, buf: &buf) < 0 || !S_ISSOCK(buf.st_mode)) { |
1668 | return -1; |
1669 | } |
1670 | |
1671 | s = wl_socket_alloc(); |
1672 | if (s == NULL) |
1673 | return -1; |
1674 | |
1675 | s->source = wl_event_loop_add_fd(loop: display->loop, fd: sock_fd, |
1676 | mask: WL_EVENT_READABLE, |
1677 | func: socket_data, data: display); |
1678 | if (s->source == NULL) { |
1679 | wl_log(fmt: "failed to establish event source\n" ); |
1680 | wl_socket_destroy(s); |
1681 | return -1; |
1682 | } |
1683 | |
1684 | /* Reuse the existing fd */ |
1685 | s->fd = sock_fd; |
1686 | |
1687 | wl_list_insert(list: display->socket_list.prev, elm: &s->link); |
1688 | |
1689 | return 0; |
1690 | } |
1691 | |
1692 | /** Add a socket to Wayland display for the clients to connect. |
1693 | * |
1694 | * \param display Wayland display to which the socket should be added. |
1695 | * \param name Name of the Unix socket. |
1696 | * \return 0 if success. -1 if failed. |
1697 | * |
1698 | * This adds a Unix socket to Wayland display which can be used by clients to |
1699 | * connect to Wayland display. |
1700 | * |
1701 | * If NULL is passed as name, then it would look for WAYLAND_DISPLAY env |
1702 | * variable for the socket name. If WAYLAND_DISPLAY is not set, then default |
1703 | * wayland-0 is used. |
1704 | * |
1705 | * If the socket name is a relative path, the Unix socket will be created in |
1706 | * the directory pointed to by environment variable XDG_RUNTIME_DIR. If |
1707 | * XDG_RUNTIME_DIR is not set, then this function fails and returns -1. |
1708 | * |
1709 | * If the socket name is an absolute path, then it is used as-is for the |
1710 | * the Unix socket. |
1711 | * |
1712 | * The length of the computed socket path must not exceed the maximum length |
1713 | * of a Unix socket path. |
1714 | * The function also fails if the user does not have write permission in the |
1715 | * directory or if the path is already in use. |
1716 | * |
1717 | * \memberof wl_display |
1718 | */ |
1719 | WL_EXPORT int |
1720 | wl_display_add_socket(struct wl_display *display, const char *name) |
1721 | { |
1722 | struct wl_socket *s; |
1723 | |
1724 | s = wl_socket_alloc(); |
1725 | if (s == NULL) |
1726 | return -1; |
1727 | |
1728 | if (name == NULL) |
1729 | name = getenv(name: "WAYLAND_DISPLAY" ); |
1730 | if (name == NULL) |
1731 | name = "wayland-0" ; |
1732 | |
1733 | if (wl_socket_init_for_display_name(s, name) < 0) { |
1734 | wl_socket_destroy(s); |
1735 | return -1; |
1736 | } |
1737 | |
1738 | if (wl_socket_lock(socket: s) < 0) { |
1739 | wl_socket_destroy(s); |
1740 | return -1; |
1741 | } |
1742 | |
1743 | if (_wl_display_add_socket(display, s) < 0) { |
1744 | wl_socket_destroy(s); |
1745 | return -1; |
1746 | } |
1747 | |
1748 | return 0; |
1749 | } |
1750 | |
1751 | WL_EXPORT void |
1752 | wl_display_add_destroy_listener(struct wl_display *display, |
1753 | struct wl_listener *listener) |
1754 | { |
1755 | wl_priv_signal_add(signal: &display->destroy_signal, listener); |
1756 | } |
1757 | |
1758 | /** Registers a listener for the client connection signal. |
1759 | * When a new client object is created, \a listener will be notified, carrying |
1760 | * a pointer to the new wl_client object. |
1761 | * |
1762 | * \ref wl_client_create |
1763 | * \ref wl_display |
1764 | * \ref wl_listener |
1765 | * |
1766 | * \param display The display object |
1767 | * \param listener Signal handler object |
1768 | */ |
1769 | WL_EXPORT void |
1770 | wl_display_add_client_created_listener(struct wl_display *display, |
1771 | struct wl_listener *listener) |
1772 | { |
1773 | wl_priv_signal_add(signal: &display->create_client_signal, listener); |
1774 | } |
1775 | |
1776 | WL_EXPORT struct wl_listener * |
1777 | wl_display_get_destroy_listener(struct wl_display *display, |
1778 | wl_notify_func_t notify) |
1779 | { |
1780 | return wl_priv_signal_get(signal: &display->destroy_signal, notify); |
1781 | } |
1782 | |
1783 | WL_EXPORT void |
1784 | wl_resource_set_implementation(struct wl_resource *resource, |
1785 | const void *implementation, |
1786 | void *data, wl_resource_destroy_func_t destroy) |
1787 | { |
1788 | resource->object.implementation = implementation; |
1789 | resource->data = data; |
1790 | resource->destroy = destroy; |
1791 | resource->dispatcher = NULL; |
1792 | } |
1793 | |
1794 | WL_EXPORT void |
1795 | wl_resource_set_dispatcher(struct wl_resource *resource, |
1796 | wl_dispatcher_func_t dispatcher, |
1797 | const void *implementation, |
1798 | void *data, wl_resource_destroy_func_t destroy) |
1799 | { |
1800 | resource->dispatcher = dispatcher; |
1801 | resource->object.implementation = implementation; |
1802 | resource->data = data; |
1803 | resource->destroy = destroy; |
1804 | } |
1805 | |
1806 | /** Create a new resource object |
1807 | * |
1808 | * \param client The client owner of the new resource. |
1809 | * \param interface The interface of the new resource. |
1810 | * \param version The version of the new resource. |
1811 | * \param id The id of the new resource. If 0, an available id will be used. |
1812 | * |
1813 | * Listeners added with \a wl_client_add_resource_created_listener will be |
1814 | * notified at the end of this function. |
1815 | * |
1816 | * \memberof wl_resource |
1817 | */ |
1818 | WL_EXPORT struct wl_resource * |
1819 | wl_resource_create(struct wl_client *client, |
1820 | const struct wl_interface *interface, |
1821 | int version, uint32_t id) |
1822 | { |
1823 | struct wl_resource *resource; |
1824 | |
1825 | resource = malloc(size: sizeof *resource); |
1826 | if (resource == NULL) |
1827 | return NULL; |
1828 | |
1829 | if (id == 0) |
1830 | id = wl_map_insert_new(map: &client->objects, flags: 0, NULL); |
1831 | |
1832 | resource->object.id = id; |
1833 | resource->object.interface = interface; |
1834 | resource->object.implementation = NULL; |
1835 | |
1836 | wl_signal_init(signal: &resource->deprecated_destroy_signal); |
1837 | wl_priv_signal_init(signal: &resource->destroy_signal); |
1838 | |
1839 | resource->destroy = NULL; |
1840 | resource->client = client; |
1841 | resource->data = NULL; |
1842 | resource->version = version; |
1843 | resource->dispatcher = NULL; |
1844 | |
1845 | if (wl_map_insert_at(map: &client->objects, flags: 0, i: id, data: resource) < 0) { |
1846 | wl_resource_post_error(resource: client->display_resource, |
1847 | code: WL_DISPLAY_ERROR_INVALID_OBJECT, |
1848 | msg: "invalid new id %d" , id); |
1849 | free(ptr: resource); |
1850 | return NULL; |
1851 | } |
1852 | |
1853 | wl_priv_signal_emit(signal: &client->resource_created_signal, data: resource); |
1854 | return resource; |
1855 | } |
1856 | |
1857 | WL_EXPORT void |
1858 | wl_log_set_handler_server(wl_log_func_t handler) |
1859 | { |
1860 | wl_log_handler = handler; |
1861 | } |
1862 | |
1863 | /** Adds a new protocol logger. |
1864 | * |
1865 | * When a new protocol message arrives or is sent from the server |
1866 | * all the protocol logger functions will be called, carrying the |
1867 | * \a user_data pointer, the type of the message (request or |
1868 | * event) and the actual message. |
1869 | * The lifetime of the messages passed to the logger function ends |
1870 | * when they return so the messages cannot be stored and accessed |
1871 | * later. |
1872 | * |
1873 | * \a errno is set on error. |
1874 | * |
1875 | * \param display The display object |
1876 | * \param func The function to call to log a new protocol message |
1877 | * \param user_data The user data pointer to pass to \a func |
1878 | * |
1879 | * \return The protol logger object on success, NULL on failure. |
1880 | * |
1881 | * \sa wl_protocol_logger_destroy |
1882 | * |
1883 | * \memberof wl_display |
1884 | */ |
1885 | WL_EXPORT struct wl_protocol_logger * |
1886 | wl_display_add_protocol_logger(struct wl_display *display, |
1887 | wl_protocol_logger_func_t func, void *user_data) |
1888 | { |
1889 | struct wl_protocol_logger *logger; |
1890 | |
1891 | logger = malloc(size: sizeof *logger); |
1892 | if (!logger) |
1893 | return NULL; |
1894 | |
1895 | logger->func = func; |
1896 | logger->user_data = user_data; |
1897 | wl_list_insert(list: &display->protocol_loggers, elm: &logger->link); |
1898 | |
1899 | return logger; |
1900 | } |
1901 | |
1902 | /** Destroys a protocol logger. |
1903 | * |
1904 | * This function destroys a protocol logger and removes it from the display |
1905 | * it was added to with \a wl_display_add_protocol_logger. |
1906 | * The \a logger object becomes invalid after calling this function. |
1907 | * |
1908 | * \sa wl_display_add_protocol_logger |
1909 | * |
1910 | * \memberof wl_protocol_logger |
1911 | */ |
1912 | WL_EXPORT void |
1913 | wl_protocol_logger_destroy(struct wl_protocol_logger *logger) |
1914 | { |
1915 | wl_list_remove(elm: &logger->link); |
1916 | free(ptr: logger); |
1917 | } |
1918 | |
1919 | /** Add support for a wl_shm pixel format |
1920 | * |
1921 | * \param display The display object |
1922 | * \param format The wl_shm pixel format to advertise |
1923 | * \return A pointer to the wl_shm format that was added to the list |
1924 | * or NULL if adding it to the list failed. |
1925 | * |
1926 | * Add the specified wl_shm format to the list of formats the wl_shm |
1927 | * object advertises when a client binds to it. Adding a format to |
1928 | * the list means that clients will know that the compositor supports |
1929 | * this format and may use it for creating wl_shm buffers. The |
1930 | * compositor must be able to handle the pixel format when a client |
1931 | * requests it. |
1932 | * |
1933 | * The compositor by default supports WL_SHM_FORMAT_ARGB8888 and |
1934 | * WL_SHM_FORMAT_XRGB8888. |
1935 | * |
1936 | * \memberof wl_display |
1937 | */ |
1938 | WL_EXPORT uint32_t * |
1939 | wl_display_add_shm_format(struct wl_display *display, uint32_t format) |
1940 | { |
1941 | uint32_t *p = NULL; |
1942 | |
1943 | p = wl_array_add(array: &display->additional_shm_formats, size: sizeof *p); |
1944 | |
1945 | if (p != NULL) |
1946 | *p = format; |
1947 | return p; |
1948 | } |
1949 | |
1950 | /** |
1951 | * Get list of additional wl_shm pixel formats |
1952 | * |
1953 | * \param display The display object |
1954 | * |
1955 | * This function returns the list of addition wl_shm pixel formats |
1956 | * that the compositor supports. WL_SHM_FORMAT_ARGB8888 and |
1957 | * WL_SHM_FORMAT_XRGB8888 are always supported and not included in the |
1958 | * array, but all formats added through wl_display_add_shm_format() |
1959 | * will be in the array. |
1960 | * |
1961 | * \sa wl_display_add_shm_format() |
1962 | * |
1963 | * \private |
1964 | * |
1965 | * \memberof wl_display |
1966 | */ |
1967 | struct wl_array * |
1968 | wl_display_get_additional_shm_formats(struct wl_display *display) |
1969 | { |
1970 | return &display->additional_shm_formats; |
1971 | } |
1972 | |
1973 | /** Get the list of currently connected clients |
1974 | * |
1975 | * \param display The display object |
1976 | * |
1977 | * This function returns a pointer to the list of clients currently |
1978 | * connected to the display. You can iterate on the list by using |
1979 | * the \a wl_client_for_each macro. |
1980 | * The returned value is valid for the lifetime of the \a display. |
1981 | * You must not modify the returned list, but only access it. |
1982 | * |
1983 | * \sa wl_client_for_each() |
1984 | * \sa wl_client_get_link() |
1985 | * \sa wl_client_from_link() |
1986 | * |
1987 | * \memberof wl_display |
1988 | */ |
1989 | WL_EXPORT struct wl_list * |
1990 | wl_display_get_client_list(struct wl_display *display) |
1991 | { |
1992 | return &display->client_list; |
1993 | } |
1994 | |
1995 | /** Get the link by which a client is inserted in the client list |
1996 | * |
1997 | * \param client The client object |
1998 | * |
1999 | * \sa wl_client_for_each() |
2000 | * \sa wl_display_get_client_list() |
2001 | * \sa wl_client_from_link() |
2002 | * |
2003 | * \memberof wl_client |
2004 | */ |
2005 | WL_EXPORT struct wl_list * |
2006 | wl_client_get_link(struct wl_client *client) |
2007 | { |
2008 | return &client->link; |
2009 | } |
2010 | |
2011 | /** Get a wl_client by its link |
2012 | * |
2013 | * \param link The link of a wl_client |
2014 | * |
2015 | * \sa wl_client_for_each() |
2016 | * \sa wl_display_get_client_list() |
2017 | * \sa wl_client_get_link() |
2018 | * |
2019 | * \memberof wl_client |
2020 | */ |
2021 | WL_EXPORT struct wl_client * |
2022 | wl_client_from_link(struct wl_list *link) |
2023 | { |
2024 | struct wl_client *client; |
2025 | |
2026 | return wl_container_of(link, client, link); |
2027 | } |
2028 | |
2029 | /** Add a listener for the client's resource creation signal |
2030 | * |
2031 | * \param client The client object |
2032 | * \param listener The listener to be added |
2033 | * |
2034 | * When a new resource is created for this client the listener |
2035 | * will be notified, carrying the new resource as the data argument. |
2036 | * |
2037 | * \memberof wl_client |
2038 | */ |
2039 | WL_EXPORT void |
2040 | wl_client_add_resource_created_listener(struct wl_client *client, |
2041 | struct wl_listener *listener) |
2042 | { |
2043 | wl_priv_signal_add(signal: &client->resource_created_signal, listener); |
2044 | } |
2045 | |
2046 | struct wl_resource_iterator_context { |
2047 | void *user_data; |
2048 | wl_client_for_each_resource_iterator_func_t it; |
2049 | }; |
2050 | |
2051 | static enum wl_iterator_result |
2052 | resource_iterator_helper(void *res, void *user_data, uint32_t flags) |
2053 | { |
2054 | struct wl_resource_iterator_context *context = user_data; |
2055 | struct wl_resource *resource = res; |
2056 | |
2057 | return context->it(resource, context->user_data); |
2058 | } |
2059 | |
2060 | /** Iterate over all the resources of a client |
2061 | * |
2062 | * \param client The client object |
2063 | * \param iterator The iterator function |
2064 | * \param user_data The user data pointer |
2065 | * |
2066 | * The function pointed by \a iterator will be called for each |
2067 | * resource owned by the client. The \a user_data will be passed |
2068 | * as the second argument of the iterator function. |
2069 | * If the \a iterator function returns \a WL_ITERATOR_CONTINUE the iteration |
2070 | * will continue, if it returns \a WL_ITERATOR_STOP it will stop. |
2071 | * |
2072 | * Creating and destroying resources while iterating is safe, but new |
2073 | * resources may or may not be picked up by the iterator. |
2074 | * |
2075 | * \sa wl_iterator_result |
2076 | * |
2077 | * \memberof wl_client |
2078 | */ |
2079 | WL_EXPORT void |
2080 | wl_client_for_each_resource(struct wl_client *client, |
2081 | wl_client_for_each_resource_iterator_func_t iterator, |
2082 | void *user_data) |
2083 | { |
2084 | struct wl_resource_iterator_context context = { |
2085 | .user_data = user_data, |
2086 | .it = iterator, |
2087 | }; |
2088 | |
2089 | wl_map_for_each(map: &client->objects, func: resource_iterator_helper, data: &context); |
2090 | } |
2091 | |
2092 | /** \cond INTERNAL */ |
2093 | |
2094 | /** Initialize a wl_priv_signal object |
2095 | * |
2096 | * wl_priv_signal is a safer implementation of a signal type, with the same API |
2097 | * as wl_signal, but kept as a private utility of libwayland-server. |
2098 | * It is safer because listeners can be removed from within wl_priv_signal_emit() |
2099 | * without corrupting the signal's list. |
2100 | * |
2101 | * Before passing a wl_priv_signal object to any other function it must be |
2102 | * initialized by using wl_priv_signal_init(). |
2103 | * |
2104 | * \memberof wl_priv_signal |
2105 | */ |
2106 | void |
2107 | wl_priv_signal_init(struct wl_priv_signal *signal) |
2108 | { |
2109 | wl_list_init(list: &signal->listener_list); |
2110 | wl_list_init(list: &signal->emit_list); |
2111 | } |
2112 | |
2113 | /** Add a listener to a signal |
2114 | * |
2115 | * The new listener will be called when calling wl_signal_emit(). If a listener is |
2116 | * added to the signal while wl_signal_emit() is running it will be called from |
2117 | * the next time wl_priv_signal_emit() is called. |
2118 | * To remove a listener call wl_list_remove() on its link member. |
2119 | * |
2120 | * \memberof wl_priv_signal |
2121 | */ |
2122 | void |
2123 | wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener) |
2124 | { |
2125 | wl_list_insert(list: signal->listener_list.prev, elm: &listener->link); |
2126 | } |
2127 | |
2128 | /** Get a listener added to a signal |
2129 | * |
2130 | * Returns the listener added to the given \a signal and with the given |
2131 | * \a notify function, or NULL if there isn't any. |
2132 | * Calling this function from within wl_priv_signal_emit() is safe and will |
2133 | * return the correct value. |
2134 | * |
2135 | * \memberof wl_priv_signal |
2136 | */ |
2137 | struct wl_listener * |
2138 | wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify) |
2139 | { |
2140 | struct wl_listener *l; |
2141 | |
2142 | wl_list_for_each(l, &signal->listener_list, link) |
2143 | if (l->notify == notify) |
2144 | return l; |
2145 | wl_list_for_each(l, &signal->emit_list, link) |
2146 | if (l->notify == notify) |
2147 | return l; |
2148 | |
2149 | return NULL; |
2150 | } |
2151 | |
2152 | /** Emit the signal, calling all the installed listeners |
2153 | * |
2154 | * Iterate over all the listeners added to this \a signal and call |
2155 | * their \a notify function pointer, passing on the given \a data. |
2156 | * Removing or adding a listener from within wl_priv_signal_emit() |
2157 | * is safe. |
2158 | */ |
2159 | void |
2160 | wl_priv_signal_emit(struct wl_priv_signal *signal, void *data) |
2161 | { |
2162 | struct wl_listener *l; |
2163 | struct wl_list *pos; |
2164 | |
2165 | wl_list_insert_list(list: &signal->emit_list, other: &signal->listener_list); |
2166 | wl_list_init(list: &signal->listener_list); |
2167 | |
2168 | /* Take every element out of the list and put them in a temporary list. |
2169 | * This way, the 'it' func can remove any element it wants from the list |
2170 | * without troubles, because we always get the first element, not the |
2171 | * one after the current, which may be invalid. |
2172 | * wl_list_for_each_safe tries to be safe but it fails: it works fine |
2173 | * if the current item is removed, but not if the next one is. */ |
2174 | while (!wl_list_empty(list: &signal->emit_list)) { |
2175 | pos = signal->emit_list.next; |
2176 | l = wl_container_of(pos, l, link); |
2177 | |
2178 | wl_list_remove(elm: pos); |
2179 | wl_list_insert(list: &signal->listener_list, elm: pos); |
2180 | |
2181 | l->notify(l, data); |
2182 | } |
2183 | } |
2184 | |
2185 | /** Emit the signal for the last time, calling all the installed listeners |
2186 | * |
2187 | * Iterate over all the listeners added to this \a signal and call |
2188 | * their \a notify function pointer, passing on the given \a data. |
2189 | * Removing or adding a listener from within wl_priv_signal_emit() |
2190 | * is safe, as is freeing the structure containing the listener. |
2191 | * |
2192 | * A large body of external code assumes it's ok to free a destruction |
2193 | * listener without removing that listener from the list. Mixing code |
2194 | * that acts like this and code that doesn't will result in list |
2195 | * corruption. |
2196 | * |
2197 | * We resolve this by removing each item from the list and isolating it |
2198 | * in another list. We discard it completely after firing the notifier. |
2199 | * This should allow interoperability between code that unlinks its |
2200 | * destruction listeners and code that just frees structures they're in. |
2201 | * |
2202 | */ |
2203 | void |
2204 | wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data) |
2205 | { |
2206 | struct wl_listener *l; |
2207 | struct wl_list *pos; |
2208 | |
2209 | /* During a destructor notifier isolate every list item before |
2210 | * notifying. This renders harmless the long standing misuse |
2211 | * of freeing listeners without removing them, but allows |
2212 | * callers that do choose to remove them to interoperate with |
2213 | * ones that don't. */ |
2214 | while (!wl_list_empty(list: &signal->listener_list)) { |
2215 | pos = signal->listener_list.next; |
2216 | l = wl_container_of(pos, l, link); |
2217 | |
2218 | wl_list_remove(elm: pos); |
2219 | wl_list_init(list: pos); |
2220 | |
2221 | l->notify(l, data); |
2222 | } |
2223 | } |
2224 | |
2225 | /** \endcond INTERNAL */ |
2226 | |
2227 | /** \cond */ /* Deprecated functions below. */ |
2228 | |
2229 | uint32_t |
2230 | wl_client_add_resource(struct wl_client *client, |
2231 | struct wl_resource *resource) WL_DEPRECATED; |
2232 | |
2233 | WL_EXPORT uint32_t |
2234 | wl_client_add_resource(struct wl_client *client, |
2235 | struct wl_resource *resource) |
2236 | { |
2237 | if (resource->object.id == 0) { |
2238 | resource->object.id = |
2239 | wl_map_insert_new(map: &client->objects, |
2240 | flags: WL_MAP_ENTRY_LEGACY, data: resource); |
2241 | } else if (wl_map_insert_at(map: &client->objects, flags: WL_MAP_ENTRY_LEGACY, |
2242 | i: resource->object.id, data: resource) < 0) { |
2243 | wl_resource_post_error(resource: client->display_resource, |
2244 | code: WL_DISPLAY_ERROR_INVALID_OBJECT, |
2245 | msg: "invalid new id %d" , |
2246 | resource->object.id); |
2247 | return 0; |
2248 | } |
2249 | |
2250 | resource->client = client; |
2251 | wl_signal_init(signal: &resource->deprecated_destroy_signal); |
2252 | |
2253 | return resource->object.id; |
2254 | } |
2255 | |
2256 | struct wl_resource * |
2257 | wl_client_add_object(struct wl_client *client, |
2258 | const struct wl_interface *interface, |
2259 | const void *implementation, |
2260 | uint32_t id, void *data) WL_DEPRECATED; |
2261 | |
2262 | WL_EXPORT struct wl_resource * |
2263 | wl_client_add_object(struct wl_client *client, |
2264 | const struct wl_interface *interface, |
2265 | const void *implementation, uint32_t id, void *data) |
2266 | { |
2267 | struct wl_resource *resource; |
2268 | |
2269 | resource = wl_resource_create(client, interface, version: -1, id); |
2270 | if (resource == NULL) |
2271 | wl_client_post_no_memory(client); |
2272 | else |
2273 | wl_resource_set_implementation(resource, |
2274 | implementation, data, NULL); |
2275 | |
2276 | return resource; |
2277 | } |
2278 | |
2279 | struct wl_resource * |
2280 | wl_client_new_object(struct wl_client *client, |
2281 | const struct wl_interface *interface, |
2282 | const void *implementation, void *data) WL_DEPRECATED; |
2283 | |
2284 | WL_EXPORT struct wl_resource * |
2285 | wl_client_new_object(struct wl_client *client, |
2286 | const struct wl_interface *interface, |
2287 | const void *implementation, void *data) |
2288 | { |
2289 | struct wl_resource *resource; |
2290 | |
2291 | resource = wl_resource_create(client, interface, version: -1, id: 0); |
2292 | if (resource == NULL) |
2293 | wl_client_post_no_memory(client); |
2294 | else |
2295 | wl_resource_set_implementation(resource, |
2296 | implementation, data, NULL); |
2297 | |
2298 | return resource; |
2299 | } |
2300 | |
2301 | struct wl_global * |
2302 | wl_display_add_global(struct wl_display *display, |
2303 | const struct wl_interface *interface, |
2304 | void *data, wl_global_bind_func_t bind) WL_DEPRECATED; |
2305 | |
2306 | WL_EXPORT struct wl_global * |
2307 | wl_display_add_global(struct wl_display *display, |
2308 | const struct wl_interface *interface, |
2309 | void *data, wl_global_bind_func_t bind) |
2310 | { |
2311 | return wl_global_create(display, interface, version: interface->version, data, bind); |
2312 | } |
2313 | |
2314 | void |
2315 | wl_display_remove_global(struct wl_display *display, |
2316 | struct wl_global *global) WL_DEPRECATED; |
2317 | |
2318 | WL_EXPORT void |
2319 | wl_display_remove_global(struct wl_display *display, struct wl_global *global) |
2320 | { |
2321 | wl_global_destroy(global); |
2322 | } |
2323 | |
2324 | /** \endcond */ |
2325 | |
2326 | /* Functions at the end of this file are deprecated. Instead of adding new |
2327 | * code here, add it before the comment above that states: |
2328 | * Deprecated functions below. |
2329 | */ |
2330 | |