/* * Copyright © 2008-2012 Kristian Høgsberg * Copyright © 2010-2012 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wayland-util.h" #include "wayland-os.h" #include "wayland-client.h" #include "wayland-private.h" /** \cond */ enum wl_proxy_flag { WL_PROXY_FLAG_ID_DELETED = (1 << 0), WL_PROXY_FLAG_DESTROYED = (1 << 1), WL_PROXY_FLAG_WRAPPER = (1 << 2), }; struct wl_proxy { struct wl_object object; struct wl_display *display; struct wl_event_queue *queue; uint32_t flags; int refcount; void *user_data; wl_dispatcher_func_t dispatcher; uint32_t version; }; struct wl_global { uint32_t id; char *interface; uint32_t version; struct wl_list link; }; struct wl_event_queue { struct wl_list event_list; struct wl_display *display; }; struct wl_display { struct wl_proxy proxy; struct wl_connection *connection; /* errno of the last wl_display error */ int last_error; /* When display gets an error event from some object, it stores * information about it here, so that client can get this * information afterwards */ struct { /* Code of the error. It can be compared to * the interface's errors enumeration. */ uint32_t code; /* interface (protocol) in which the error occurred */ const struct wl_interface *interface; /* id of the proxy that caused the error. There's no warranty * that the proxy is still valid. It's up to client how it will * use it */ uint32_t id; } protocol_error; int fd; struct wl_map objects; struct wl_event_queue display_queue; struct wl_event_queue default_queue; pthread_mutex_t mutex; int reader_count; uint32_t read_serial; pthread_cond_t reader_cond; }; /** \endcond */ static int debug_client = 0; /** * This helper function wakes up all threads that are * waiting for display->reader_cond (i. e. when reading is done, * canceled, or an error occurred) * * NOTE: must be called with display->mutex locked */ static void display_wakeup_threads(struct wl_display *display) { /* Thread can get sleeping only in read_events(). If we're * waking it up, it means that the read completed or was * canceled, so we must increase the read_serial. * This prevents from indefinite sleeping in read_events(). */ ++display->read_serial; pthread_cond_broadcast(&display->reader_cond); } /** * This function is called for local errors (no memory, server hung up) * * \param display * \param error error value (EINVAL, EFAULT, ...) * * \note this function is called with display mutex locked */ static void display_fatal_error(struct wl_display *display, int error) { if (display->last_error) return; if (!error) error = EFAULT; display->last_error = error; display_wakeup_threads(display); } /** * This function is called for error events * and indicates that in some object an error occurred. * The difference between this function and display_fatal_error() * is that this one handles errors that will come by wire, * whereas display_fatal_error() is called for local errors. * * \param display * \param code error code * \param id id of the object that generated the error * \param intf protocol interface */ static void display_protocol_error(struct wl_display *display, uint32_t code, uint32_t id, const struct wl_interface *intf) { int err; if (display->last_error) return; /* set correct errno */ if (intf && wl_interface_equal(intf, &wl_display_interface)) { switch (code) { case WL_DISPLAY_ERROR_INVALID_OBJECT: case WL_DISPLAY_ERROR_INVALID_METHOD: err = EINVAL; break; case WL_DISPLAY_ERROR_NO_MEMORY: err = ENOMEM; break; default: err = EFAULT; } } else { err = EPROTO; } pthread_mutex_lock(&display->mutex); display->last_error = err; display->protocol_error.code = code; display->protocol_error.id = id; display->protocol_error.interface = intf; /* * here it is not necessary to wake up threads like in * display_fatal_error, because this function is called from * an event handler and that means that read_events() is done * and woke up all threads. Since wl_display_prepare_read() * fails when there are events in the queue, no threads * can sleep in read_events() during dispatching * (and therefore during calling this function), so this is safe. */ pthread_mutex_unlock(&display->mutex); } static void wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display) { wl_list_init(&queue->event_list); queue->display = display; } static void decrease_closure_args_refcount(struct wl_closure *closure) { const char *signature; struct argument_details arg; int i, count; struct wl_proxy *proxy; signature = closure->message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case 'n': case 'o': proxy = (struct wl_proxy *) closure->args[i].o; if (proxy) { if (proxy->flags & WL_PROXY_FLAG_DESTROYED) closure->args[i].o = NULL; proxy->refcount--; if (!proxy->refcount) free(proxy); } break; default: break; } } } static void wl_event_queue_release(struct wl_event_queue *queue) { struct wl_closure *closure; struct wl_proxy *proxy; bool proxy_destroyed; while (!wl_list_empty(&queue->event_list)) { closure = container_of(queue->event_list.next, struct wl_closure, link); wl_list_remove(&closure->link); decrease_closure_args_refcount(closure); proxy = closure->proxy; proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); proxy->refcount--; if (proxy_destroyed && !proxy->refcount) free(proxy); wl_closure_destroy(closure); } } /** Destroy an event queue * * \param queue The event queue to be destroyed * * Destroy the given event queue. Any pending event on that queue is * discarded. * * The \ref wl_display object used to create the queue should not be * destroyed until all event queues created with it are destroyed with * this function. * * \memberof wl_event_queue */ WL_EXPORT void wl_event_queue_destroy(struct wl_event_queue *queue) { struct wl_display *display = queue->display; pthread_mutex_lock(&display->mutex); wl_event_queue_release(queue); free(queue); pthread_mutex_unlock(&display->mutex); } /** Create a new event queue for this display * * \param display The display context object * \return A new event queue associated with this display or NULL on * failure. * * \memberof wl_display */ WL_EXPORT struct wl_event_queue * wl_display_create_queue(struct wl_display *display) { struct wl_event_queue *queue; queue = malloc(sizeof *queue); if (queue == NULL) return NULL; wl_event_queue_init(queue, display); return queue; } static struct wl_proxy * proxy_create(struct wl_proxy *factory, const struct wl_interface *interface, uint32_t version) { struct wl_proxy *proxy; struct wl_display *display = factory->display; proxy = zalloc(sizeof *proxy); if (proxy == NULL) return NULL; proxy->object.interface = interface; proxy->display = display; proxy->queue = factory->queue; proxy->refcount = 1; proxy->version = version; proxy->object.id = wl_map_insert_new(&display->objects, 0, proxy); return proxy; } /** Create a proxy object with a given interface * * \param factory Factory proxy object * \param interface Interface the proxy object should use * \return A newly allocated proxy object or NULL on failure * * This function creates a new proxy object with the supplied interface. The * proxy object will have an id assigned from the client id space. The id * should be created on the compositor side by sending an appropriate request * with \ref wl_proxy_marshal(). * * The proxy will inherit the display and event queue of the factory object. * * \note This should not normally be used by non-generated code. * * \sa wl_display, wl_event_queue, wl_proxy_marshal() * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface) { struct wl_display *display = factory->display; struct wl_proxy *proxy; pthread_mutex_lock(&display->mutex); proxy = proxy_create(factory, interface, factory->version); pthread_mutex_unlock(&display->mutex); return proxy; } /* The caller should hold the display lock */ static struct wl_proxy * wl_proxy_create_for_id(struct wl_proxy *factory, uint32_t id, const struct wl_interface *interface) { struct wl_proxy *proxy; struct wl_display *display = factory->display; proxy = zalloc(sizeof *proxy); if (proxy == NULL) return NULL; proxy->object.interface = interface; proxy->object.id = id; proxy->display = display; proxy->queue = factory->queue; proxy->refcount = 1; proxy->version = factory->version; wl_map_insert_at(&display->objects, 0, id, proxy); return proxy; } static void proxy_destroy(struct wl_proxy *proxy) { if (proxy->flags & WL_PROXY_FLAG_ID_DELETED) wl_map_remove(&proxy->display->objects, proxy->object.id); else if (proxy->object.id < WL_SERVER_ID_START) wl_map_insert_at(&proxy->display->objects, 0, proxy->object.id, WL_ZOMBIE_OBJECT); else wl_map_insert_at(&proxy->display->objects, 0, proxy->object.id, NULL); proxy->flags |= WL_PROXY_FLAG_DESTROYED; proxy->refcount--; if (!proxy->refcount) free(proxy); } /** Destroy a proxy object * * \param proxy The proxy to be destroyed * * \c proxy must not be a proxy wrapper. * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_destroy(struct wl_proxy *proxy) { struct wl_display *display = proxy->display; if (proxy->flags & WL_PROXY_FLAG_WRAPPER) wl_abort("Tried to destroy wrapper with wl_proxy_destroy()\n"); pthread_mutex_lock(&display->mutex); proxy_destroy(proxy); pthread_mutex_unlock(&display->mutex); } /** Set a proxy's listener * * \param proxy The proxy object * \param implementation The listener to be added to proxy * \param data User data to be associated with the proxy * \return 0 on success or -1 on failure * * Set proxy's listener to \c implementation and its user data to * \c data. If a listener has already been set, this function * fails and nothing is changed. * * \c implementation is a vector of function pointers. For an opcode * \c n, \c implementation[n] should point to the handler of \c n for * the given object. * * \c proxy must not be a proxy wrapper. * * \memberof wl_proxy */ WL_EXPORT int wl_proxy_add_listener(struct wl_proxy *proxy, void (**implementation)(void), void *data) { if (proxy->flags & WL_PROXY_FLAG_WRAPPER) wl_abort("Proxy %p is a wrapper\n", proxy); if (proxy->object.implementation || proxy->dispatcher) { wl_log("proxy %p already has listener\n", proxy); return -1; } proxy->object.implementation = implementation; proxy->user_data = data; return 0; } /** Get a proxy's listener * * \param proxy The proxy object * \return The address of the proxy's listener or NULL if no listener is set * * Gets the address to the proxy's listener; which is the listener set with * \ref wl_proxy_add_listener. * * This function is useful in clients with multiple listeners on the same * interface to allow the identification of which code to execute. * * \memberof wl_proxy */ WL_EXPORT const void * wl_proxy_get_listener(struct wl_proxy *proxy) { return proxy->object.implementation; } /** Set a proxy's listener (with dispatcher) * * \param proxy The proxy object * \param dispatcher The dispatcher to be used for this proxy * \param implementation The dispatcher-specific listener implementation * \param data User data to be associated with the proxy * \return 0 on success or -1 on failure * * Set proxy's listener to use \c dispatcher_func as its dispatcher and \c * dispatcher_data as its dispatcher-specific implementation and its user data * to \c data. If a listener has already been set, this function * fails and nothing is changed. * * The exact details of dispatcher_data depend on the dispatcher used. This * function is intended to be used by language bindings, not user code. * * \c proxy must not be a proxy wrapper. * * \memberof wl_proxy */ WL_EXPORT int wl_proxy_add_dispatcher(struct wl_proxy *proxy, wl_dispatcher_func_t dispatcher, const void *implementation, void *data) { if (proxy->flags & WL_PROXY_FLAG_WRAPPER) wl_abort("Proxy %p is a wrapper\n", proxy); if (proxy->object.implementation || proxy->dispatcher) { wl_log("proxy %p already has listener\n", proxy); return -1; } proxy->object.implementation = implementation; proxy->dispatcher = dispatcher; proxy->user_data = data; return 0; } static struct wl_proxy * create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message, union wl_argument *args, const struct wl_interface *interface, uint32_t version) { int i, count; const char *signature; struct argument_details arg; struct wl_proxy *new_proxy = NULL; signature = message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case 'n': new_proxy = proxy_create(proxy, interface, version); if (new_proxy == NULL) return NULL; args[i].o = &new_proxy->object; break; } } return new_proxy; } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param args Extra arguments for the given request * \param interface The interface to use for the new proxy * * This function translates a request given an opcode, an interface and a * wl_argument array to the wire format and writes it to the connection * buffer. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned * on success or NULL on error with errno set accordingly. The newly * created proxy will inherit their version from their parent. * * \note This is intended to be used by language bindings and not in * non-generated code. * * \sa wl_proxy_marshal() * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface) { return wl_proxy_marshal_array_constructor_versioned(proxy, opcode, args, interface, proxy->version); } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param args Extra arguments for the given request * \param interface The interface to use for the new proxy * \param version The protocol object version for the new proxy * * Translates the request given by opcode and the extra arguments into the * wire format and write it to the connection buffer. This version takes an * array of the union type wl_argument. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned * on success or NULL on error with errno set accordingly. The newly * created proxy will have the version specified. * * \note This is intended to be used by language bindings and not in * non-generated code. * * \sa wl_proxy_marshal() * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface, uint32_t version) { struct wl_closure *closure; struct wl_proxy *new_proxy = NULL; const struct wl_message *message; pthread_mutex_lock(&proxy->display->mutex); message = &proxy->object.interface->methods[opcode]; if (interface) { new_proxy = create_outgoing_proxy(proxy, message, args, interface, version); if (new_proxy == NULL) goto err_unlock; } closure = wl_closure_marshal(&proxy->object, opcode, args, message); if (closure == NULL) wl_abort("Error marshalling request: %s\n", strerror(errno)); if (debug_client) wl_closure_print(closure, &proxy->object, true); if (wl_closure_send(closure, proxy->display->connection)) wl_abort("Error sending request: %s\n", strerror(errno)); wl_closure_destroy(closure); err_unlock: pthread_mutex_unlock(&proxy->display->mutex); return new_proxy; } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param ... Extra arguments for the given request * * This function is similar to wl_proxy_marshal_constructor(), except * it doesn't create proxies for new-id arguments. * * \note This should not normally be used by non-generated code. * * \sa wl_proxy_create() * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; va_list ap; va_start(ap, opcode); wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature, args, WL_CLOSURE_MAX_ARGS, ap); va_end(ap); wl_proxy_marshal_array_constructor(proxy, opcode, args, NULL); } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param interface The interface to use for the new proxy * \param ... Extra arguments for the given request * \return A new wl_proxy for the new_id argument or NULL on error * * This function translates a request given an opcode, an interface and extra * arguments to the wire format and writes it to the connection buffer. The * types of the extra arguments must correspond to the argument types of the * method associated with the opcode in the interface. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned * on success or NULL on error with errno set accordingly. The newly * created proxy will inherit their version from their parent. * * \note This should not normally be used by non-generated code. * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, ...) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; va_list ap; va_start(ap, interface); wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature, args, WL_CLOSURE_MAX_ARGS, ap); va_end(ap); return wl_proxy_marshal_array_constructor(proxy, opcode, args, interface); } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param interface The interface to use for the new proxy * \param version The protocol object version of the new proxy * \param ... Extra arguments for the given request * \return A new wl_proxy for the new_id argument or NULL on error * * Translates the request given by opcode and the extra arguments into the * wire format and write it to the connection buffer. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned * on success or NULL on error with errno set accordingly. The newly * created proxy will have the version specified. * * \note This should not normally be used by non-generated code. * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; va_list ap; va_start(ap, version); wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature, args, WL_CLOSURE_MAX_ARGS, ap); va_end(ap); return wl_proxy_marshal_array_constructor_versioned(proxy, opcode, args, interface, version); } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param args Extra arguments for the given request * * This function is similar to wl_proxy_marshal_array_constructor(), except * it doesn't create proxies for new-id arguments. * * \note This is intended to be used by language bindings and not in * non-generated code. * * \sa wl_proxy_marshal() * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_marshal_array(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args) { wl_proxy_marshal_array_constructor(proxy, opcode, args, NULL); } static void display_handle_error(void *data, struct wl_display *display, void *object, uint32_t code, const char *message) { struct wl_proxy *proxy = object; uint32_t object_id; const struct wl_interface *interface; if (proxy) { wl_log("%s@%u: error %d: %s\n", proxy->object.interface->name, proxy->object.id, code, message); object_id = proxy->object.id; interface = proxy->object.interface; } else { wl_log("[destroyed object]: error %d: %s\n", code, message); object_id = 0; interface = NULL; } display_protocol_error(display, code, object_id, interface); } static void display_handle_delete_id(void *data, struct wl_display *display, uint32_t id) { struct wl_proxy *proxy; pthread_mutex_lock(&display->mutex); proxy = wl_map_lookup(&display->objects, id); if (!proxy) wl_log("error: received delete_id for unknown id (%u)\n", id); if (proxy && proxy != WL_ZOMBIE_OBJECT) proxy->flags |= WL_PROXY_FLAG_ID_DELETED; else wl_map_remove(&display->objects, id); pthread_mutex_unlock(&display->mutex); } static const struct wl_display_listener display_listener = { display_handle_error, display_handle_delete_id }; static int connect_to_socket(const char *name) { struct sockaddr_un addr; socklen_t size; const char *runtime_dir; int name_size, fd; runtime_dir = getenv("XDG_RUNTIME_DIR"); if (!runtime_dir) { wl_log("error: XDG_RUNTIME_DIR not set in the environment.\n"); /* to prevent programs reporting * "failed to create display: Success" */ errno = ENOENT; return -1; } if (name == NULL) name = getenv("WAYLAND_DISPLAY"); if (name == NULL) name = "wayland-0"; fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0); if (fd < 0) return -1; memset(&addr, 0, sizeof addr); addr.sun_family = AF_LOCAL; name_size = snprintf(addr.sun_path, sizeof addr.sun_path, "%s/%s", runtime_dir, name) + 1; assert(name_size > 0); if (name_size > (int)sizeof addr.sun_path) { wl_log("error: socket path \"%s/%s\" plus null terminator" " exceeds 108 bytes\n", runtime_dir, name); close(fd); /* to prevent programs reporting * "failed to add socket: Success" */ errno = ENAMETOOLONG; return -1; }; size = offsetof (struct sockaddr_un, sun_path) + name_size; if (connect(fd, (struct sockaddr *) &addr, size) < 0) { close(fd); return -1; } return fd; } /** Connect to Wayland display on an already open fd * * \param fd The fd to use for the connection * \return A \ref wl_display object or \c NULL on failure * * The wl_display takes ownership of the fd and will close it when the * display is destroyed. The fd will also be closed in case of * failure. * * \memberof wl_display */ WL_EXPORT struct wl_display * wl_display_connect_to_fd(int fd) { struct wl_display *display; const char *debug; debug = getenv("WAYLAND_DEBUG"); if (debug && (strstr(debug, "client") || strstr(debug, "1"))) debug_client = 1; display = zalloc(sizeof *display); if (display == NULL) { close(fd); return NULL; } display->fd = fd; wl_map_init(&display->objects, WL_MAP_CLIENT_SIDE); wl_event_queue_init(&display->default_queue, display); wl_event_queue_init(&display->display_queue, display); pthread_mutex_init(&display->mutex, NULL); pthread_cond_init(&display->reader_cond, NULL); display->reader_count = 0; wl_map_insert_new(&display->objects, 0, NULL); display->proxy.object.interface = &wl_display_interface; display->proxy.object.id = wl_map_insert_new(&display->objects, 0, display); display->proxy.display = display; display->proxy.object.implementation = (void(**)(void)) &display_listener; display->proxy.user_data = display; display->proxy.queue = &display->default_queue; display->proxy.flags = 0; display->proxy.refcount = 1; /* We set this version to 0 for backwards compatibility. * * If a client is using old versions of protocol headers, * it will use unversioned API to create proxies. Those * proxies will inherit this 0. * * A client could be passing these proxies into library * code newer than the headers that checks proxy * versions. When the proxy version is reported as 0 * the library will know that it can't reliably determine * the proxy version, and should do whatever fallback is * required. * * This trick forces wl_display to always report 0, but * since it's a special object that we can't bind * specific versions of anyway, this should be fine. */ display->proxy.version = 0; display->connection = wl_connection_create(display->fd); if (display->connection == NULL) goto err_connection; return display; err_connection: pthread_mutex_destroy(&display->mutex); pthread_cond_destroy(&display->reader_cond); wl_map_release(&display->objects); close(display->fd); free(display); return NULL; } /** Connect to a Wayland display * * \param name Name of the Wayland display to connect to * \return A \ref wl_display object or \c NULL on failure * * Connect to the Wayland display named \c name. If \c name is \c NULL, * its value will be replaced with the WAYLAND_DISPLAY environment * variable if it is set, otherwise display "wayland-0" will be used. * * \memberof wl_display */ WL_EXPORT struct wl_display * wl_display_connect(const char *name) { char *connection, *end; int flags, fd; connection = getenv("WAYLAND_SOCKET"); if (connection) { int prev_errno = errno; errno = 0; fd = strtol(connection, &end, 0); if (errno != 0 || connection == end || *end != '\0') return NULL; errno = prev_errno; flags = fcntl(fd, F_GETFD); if (flags != -1) fcntl(fd, F_SETFD, flags | FD_CLOEXEC); unsetenv("WAYLAND_SOCKET"); } else { fd = connect_to_socket(name); if (fd < 0) return NULL; } return wl_display_connect_to_fd(fd); } /** Close a connection to a Wayland display * * \param display The display context object * * Close the connection to \c display and free all resources associated * with it. * * \memberof wl_display */ WL_EXPORT void wl_display_disconnect(struct wl_display *display) { wl_connection_destroy(display->connection); wl_map_release(&display->objects); wl_event_queue_release(&display->default_queue); wl_event_queue_release(&display->display_queue); pthread_mutex_destroy(&display->mutex); pthread_cond_destroy(&display->reader_cond); close(display->fd); free(display); } /** Get a display context's file descriptor * * \param display The display context object * \return Display object file descriptor * * Return the file descriptor associated with a display so it can be * integrated into the client's main loop. * * \memberof wl_display */ WL_EXPORT int wl_display_get_fd(struct wl_display *display) { return display->fd; } static void sync_callback(void *data, struct wl_callback *callback, uint32_t serial) { int *done = data; *done = 1; wl_callback_destroy(callback); } static const struct wl_callback_listener sync_listener = { sync_callback }; /** Block until all pending request are processed by the server * * \param display The display context object * \param queue The queue on which to run the roundtrip * \return The number of dispatched events on success or -1 on failure * * This function blocks until the server has processed all currently issued * requests by sending a request to the display server and waiting for a * reply before returning. * * This function uses wl_display_dispatch_queue() internally. It is not allowed * to call this function while the thread is being prepared for reading events, * and doing so will cause a dead lock. * * \note This function may dispatch other events being received on the given * queue. * * \sa wl_display_roundtrip() * \memberof wl_display */ WL_EXPORT int wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *queue) { struct wl_display *display_wrapper; struct wl_callback *callback; int done, ret = 0; done = 0; display_wrapper = wl_proxy_create_wrapper(display); if (!display_wrapper) return -1; wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue); callback = wl_display_sync(display_wrapper); wl_proxy_wrapper_destroy(display_wrapper); if (callback == NULL) return -1; wl_callback_add_listener(callback, &sync_listener, &done); while (!done && ret >= 0) ret = wl_display_dispatch_queue(display, queue); if (ret == -1 && !done) wl_callback_destroy(callback); return ret; } /** Block until all pending request are processed by the server * * \param display The display context object * \return The number of dispatched events on success or -1 on failure * * This function blocks until the server has processed all currently issued * requests by sending a request to the display server and waiting for a reply * before returning. * * This function uses wl_display_dispatch_queue() internally. It is not allowed * to call this function while the thread is being prepared for reading events, * and doing so will cause a dead lock. * * \note This function may dispatch other events being received on the default * queue. * * \memberof wl_display */ WL_EXPORT int wl_display_roundtrip(struct wl_display *display) { return wl_display_roundtrip_queue(display, &display->default_queue); } static int create_proxies(struct wl_proxy *sender, struct wl_closure *closure) { struct wl_proxy *proxy; const char *signature; struct argument_details arg; uint32_t id; int i; int count; signature = closure->message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case 'n': id = closure->args[i].n; if (id == 0) { closure->args[i].o = NULL; break; } proxy = wl_proxy_create_for_id(sender, id, closure->message->types[i]); if (proxy == NULL) return -1; closure->args[i].o = (struct wl_object *)proxy; break; default: break; } } return 0; } static void increase_closure_args_refcount(struct wl_closure *closure) { const char *signature; struct argument_details arg; int i, count; struct wl_proxy *proxy; signature = closure->message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case 'n': case 'o': proxy = (struct wl_proxy *) closure->args[i].o; if (proxy) proxy->refcount++; break; default: break; } } } static int queue_event(struct wl_display *display, int len) { uint32_t p[2], id; int opcode, size; struct wl_proxy *proxy; struct wl_closure *closure; const struct wl_message *message; struct wl_event_queue *queue; wl_connection_copy(display->connection, p, sizeof p); id = p[0]; opcode = p[1] & 0xffff; size = p[1] >> 16; if (len < size) return 0; proxy = wl_map_lookup(&display->objects, id); if (proxy == WL_ZOMBIE_OBJECT) { wl_connection_consume(display->connection, size); return size; } else if (proxy == NULL) { wl_connection_consume(display->connection, size); return size; } message = &proxy->object.interface->events[opcode]; closure = wl_connection_demarshal(display->connection, size, &display->objects, message); if (!closure) return -1; if (create_proxies(proxy, closure) < 0) { wl_closure_destroy(closure); return -1; } if (wl_closure_lookup_objects(closure, &display->objects) != 0) { wl_closure_destroy(closure); return -1; } increase_closure_args_refcount(closure); proxy->refcount++; closure->proxy = proxy; if (proxy == &display->proxy) queue = &display->display_queue; else queue = proxy->queue; wl_list_insert(queue->event_list.prev, &closure->link); return size; } static void dispatch_event(struct wl_display *display, struct wl_event_queue *queue) { struct wl_closure *closure; struct wl_proxy *proxy; int opcode; bool proxy_destroyed; closure = container_of(queue->event_list.next, struct wl_closure, link); wl_list_remove(&closure->link); opcode = closure->opcode; /* Verify that the receiving object is still valid by checking if has * been destroyed by the application. */ decrease_closure_args_refcount(closure); proxy = closure->proxy; proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); proxy->refcount--; if (proxy_destroyed) { if (!proxy->refcount) free(proxy); wl_closure_destroy(closure); return; } pthread_mutex_unlock(&display->mutex); if (proxy->dispatcher) { if (debug_client) wl_closure_print(closure, &proxy->object, false); wl_closure_dispatch(closure, proxy->dispatcher, &proxy->object, opcode); } else if (proxy->object.implementation) { if (debug_client) wl_closure_print(closure, &proxy->object, false); wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT, &proxy->object, opcode, proxy->user_data); } wl_closure_destroy(closure); pthread_mutex_lock(&display->mutex); } static int read_events(struct wl_display *display) { int total, rem, size; uint32_t serial; display->reader_count--; if (display->reader_count == 0) { total = wl_connection_read(display->connection); if (total == -1) { if (errno == EAGAIN) { /* we must wake up threads whenever * the reader_count dropped to 0 */ display_wakeup_threads(display); return 0; } display_fatal_error(display, errno); return -1; } else if (total == 0) { /* The compositor has closed the socket. This * should be considered an error so we'll fake * an errno */ errno = EPIPE; display_fatal_error(display, errno); return -1; } for (rem = total; rem >= 8; rem -= size) { size = queue_event(display, rem); if (size == -1) { display_fatal_error(display, errno); return -1; } else if (size == 0) { break; } } display_wakeup_threads(display); } else { serial = display->read_serial; while (display->read_serial == serial) pthread_cond_wait(&display->reader_cond, &display->mutex); if (display->last_error) { errno = display->last_error; return -1; } } return 0; } static void cancel_read(struct wl_display *display) { display->reader_count--; if (display->reader_count == 0) display_wakeup_threads(display); } /** Read events from display file descriptor * * \param display The display context object * \return 0 on success or -1 on error. In case of error errno will * be set accordingly * * Calling this function will result in data available on the display file * descriptor being read and read events will be queued on their corresponding * event queues. * * Before calling this function, depending on what thread it is to be called * from, wl_display_prepare_read_queue() or wl_display_prepare_read() needs to * be called. See wl_display_prepare_read_queue() for more details. * * When being called at a point where other threads have been prepared to read * (using wl_display_prepare_read_queue() or wl_display_prepare_read()) this * function will sleep until all other prepared threads have either been * cancelled (using wl_display_cancel_read()) or them self entered this * function. The last thread that calls this function will then read and queue * events on their corresponding event queues, and finally wake up all other * wl_display_read_events() calls causing them to return. * * If a thread cancels a read preparation when all other threads that have * prepared to read has either called wl_display_cancel_read() or * wl_display_read_events(), all reader threads will return without having read * any data. * * To dispatch events that may have been queued, call * wl_display_dispatch_pending() or wl_display_dispatch_queue_pending(). * * \sa wl_display_prepare_read(), wl_display_cancel_read(), * wl_display_dispatch_pending(), wl_display_dispatch() * * \memberof wl_display */ WL_EXPORT int wl_display_read_events(struct wl_display *display) { int ret; pthread_mutex_lock(&display->mutex); if (display->last_error) { cancel_read(display); pthread_mutex_unlock(&display->mutex); errno = display->last_error; return -1; } ret = read_events(display); pthread_mutex_unlock(&display->mutex); return ret; } static int dispatch_queue(struct wl_display *display, struct wl_event_queue *queue) { int count; if (display->last_error) goto err; count = 0; while (!wl_list_empty(&display->display_queue.event_list)) { dispatch_event(display, &display->display_queue); if (display->last_error) goto err; count++; } while (!wl_list_empty(&queue->event_list)) { dispatch_event(display, queue); if (display->last_error) goto err; count++; } return count; err: errno = display->last_error; return -1; } /** Prepare to read events from the display's file descriptor to a queue * * \param display The display context object * \param queue The event queue to use * \return 0 on success or -1 if event queue was not empty * * This function (or wl_display_prepare_read()) must be called before reading * from the file descriptor using wl_display_read_events(). Calling * wl_display_prepare_read_queue() announces the calling thread's intention to * read and ensures that until the thread is ready to read and calls * wl_display_read_events(), no other thread will read from the file descriptor. * This only succeeds if the event queue is empty, and if not -1 is returned and * errno set to EAGAIN. * * If a thread successfully calls wl_display_prepare_read_queue(), it must * either call wl_display_read_events() when it's ready or cancel the read * intention by calling wl_display_cancel_read(). * * Use this function before polling on the display fd or integrate the fd into a * toolkit event loop in a race-free way. A correct usage would be (with most * error checking left out): * * \code * while (wl_display_prepare_read_queue(display, queue) != 0) * wl_display_dispatch_queue_pending(display, queue); * wl_display_flush(display); * * ret = poll(fds, nfds, -1); * if (has_error(ret)) * wl_display_cancel_read(display); * else * wl_display_read_events(display); * * wl_display_dispatch_queue_pending(display, queue); * \endcode * * Here we call wl_display_prepare_read_queue(), which ensures that between * returning from that call and eventually calling wl_display_read_events(), no * other thread will read from the fd and queue events in our queue. If the call * to wl_display_prepare_read_queue() fails, we dispatch the pending events and * try again until we're successful. * * The wl_display_prepare_read_queue() function doesn't acquire exclusive access * to the display's fd. It only registers that the thread calling this function * has intention to read from fd. When all registered readers call * wl_display_read_events(), only one (at random) eventually reads and queues * the events and the others are sleeping meanwhile. This way we avoid races and * still can read from more threads. * * \sa wl_display_cancel_read(), wl_display_read_events(), * wl_display_prepare_read() * * \memberof wl_display */ WL_EXPORT int wl_display_prepare_read_queue(struct wl_display *display, struct wl_event_queue *queue) { int ret; pthread_mutex_lock(&display->mutex); if (!wl_list_empty(&queue->event_list)) { errno = EAGAIN; ret = -1; } else { display->reader_count++; ret = 0; } pthread_mutex_unlock(&display->mutex); return ret; } /** Prepare to read events from the display's file descriptor * * \param display The display context object * \return 0 on success or -1 if event queue was not empty * * This function does the same thing as wl_display_prepare_read_queue() * with the default queue passed as the queue. * * \sa wl_display_prepare_read_queue * \memberof wl_display */ WL_EXPORT int wl_display_prepare_read(struct wl_display *display) { return wl_display_prepare_read_queue(display, &display->default_queue); } /** Cancel read intention on display's fd * * \param display The display context object * * After a thread successfully called wl_display_prepare_read() it must * either call wl_display_read_events() or wl_display_cancel_read(). * If the threads do not follow this rule it will lead to deadlock. * * \sa wl_display_prepare_read(), wl_display_read_events() * * \memberof wl_display */ WL_EXPORT void wl_display_cancel_read(struct wl_display *display) { pthread_mutex_lock(&display->mutex); cancel_read(display); pthread_mutex_unlock(&display->mutex); } static int wl_display_poll(struct wl_display *display, short int events) { int ret; struct pollfd pfd[1]; pfd[0].fd = display->fd; pfd[0].events = events; do { ret = poll(pfd, 1, -1); } while (ret == -1 && errno == EINTR); return ret; } /** Dispatch events in an event queue * * \param display The display context object * \param queue The event queue to dispatch * \return The number of dispatched events on success or -1 on failure * * Dispatch events on the given event queue. * * If the given event queue is empty, this function blocks until there are * events to be read from the display fd. Events are read and queued on * the appropriate event queues. Finally, events on given event queue are * dispatched. On failure -1 is returned and errno set appropriately. * * In a multi threaded environment, do not manually wait using poll() (or * equivalent) before calling this function, as doing so might cause a dead * lock. If external reliance on poll() (or equivalent) is required, see * wl_display_prepare_read_queue() of how to do so. * * This function is thread safe as long as it dispatches the right queue on the * right thread. It is also compatible with the multi thread event reading * preparation API (see wl_display_prepare_read_queue()), and uses the * equivalent functionality internally. It is not allowed to call this function * while the thread is being prepared for reading events, and doing so will * cause a dead lock. * * It can be used as a helper function to ease the procedure of reading and * dispatching events. * * \note Since Wayland 1.5 the display has an extra queue * for its own events (i. e. delete_id). This queue is dispatched always, * no matter what queue we passed as an argument to this function. * That means that this function can return non-0 value even when it * haven't dispatched any event for the given queue. * * \sa wl_display_dispatch(), wl_display_dispatch_pending(), * wl_display_dispatch_queue_pending(), wl_display_prepare_read_queue() * * \memberof wl_display */ WL_EXPORT int wl_display_dispatch_queue(struct wl_display *display, struct wl_event_queue *queue) { int ret; if (wl_display_prepare_read_queue(display, queue) == -1) return wl_display_dispatch_queue_pending(display, queue); while (true) { ret = wl_display_flush(display); if (ret != -1 || errno != EAGAIN) break; if (wl_display_poll(display, POLLOUT) == -1) { wl_display_cancel_read(display); return -1; } } /* Don't stop if flushing hits an EPIPE; continue so we can read any * protocol error that may have triggered it. */ if (ret < 0 && errno != EPIPE) { wl_display_cancel_read(display); return -1; } if (wl_display_poll(display, POLLIN) == -1) { wl_display_cancel_read(display); return -1; } if (wl_display_read_events(display) == -1) return -1; return wl_display_dispatch_queue_pending(display, queue); } /** Dispatch pending events in an event queue * * \param display The display context object * \param queue The event queue to dispatch * \return The number of dispatched events on success or -1 on failure * * Dispatch all incoming events for objects assigned to the given * event queue. On failure -1 is returned and errno set appropriately. * If there are no events queued, this function returns immediately. * * \memberof wl_display * \since 1.0.2 */ WL_EXPORT int wl_display_dispatch_queue_pending(struct wl_display *display, struct wl_event_queue *queue) { int ret; pthread_mutex_lock(&display->mutex); ret = dispatch_queue(display, queue); pthread_mutex_unlock(&display->mutex); return ret; } /** Process incoming events * * \param display The display context object * \return The number of dispatched events on success or -1 on failure * * Dispatch events on the default event queue. * * If the default event queue is empty, this function blocks until there are * events to be read from the display fd. Events are read and queued on * the appropriate event queues. Finally, events on the default event queue * are dispatched. On failure -1 is returned and errno set appropriately. * * In a multi threaded environment, do not manually wait using poll() (or * equivalent) before calling this function, as doing so might cause a dead * lock. If external reliance on poll() (or equivalent) is required, see * wl_display_prepare_read_queue() of how to do so. * * This function is thread safe as long as it dispatches the right queue on the * right thread. It is also compatible with the multi thread event reading * preparation API (see wl_display_prepare_read_queue()), and uses the * equivalent functionality internally. It is not allowed to call this function * while the thread is being prepared for reading events, and doing so will * cause a dead lock. * * \note It is not possible to check if there are events on the queue * or not. For dispatching default queue events without blocking, see \ref * wl_display_dispatch_pending(). * * \sa wl_display_dispatch_pending(), wl_display_dispatch_queue(), * wl_display_read_events() * * \memberof wl_display */ WL_EXPORT int wl_display_dispatch(struct wl_display *display) { return wl_display_dispatch_queue(display, &display->default_queue); } /** Dispatch default queue events without reading from the display fd * * \param display The display context object * \return The number of dispatched events or -1 on failure * * This function dispatches events on the main event queue. It does not * attempt to read the display fd and simply returns zero if the main * queue is empty, i.e., it doesn't block. * * \sa wl_display_dispatch(), wl_display_dispatch_queue(), * wl_display_flush() * * \memberof wl_display */ WL_EXPORT int wl_display_dispatch_pending(struct wl_display *display) { return wl_display_dispatch_queue_pending(display, &display->default_queue); } /** Retrieve the last error that occurred on a display * * \param display The display context object * \return The last error that occurred on \c display or 0 if no error occurred * * Return the last error that occurred on the display. This may be an error sent * by the server or caused by the local client. * * \note Errors are \b fatal. If this function returns non-zero the display * can no longer be used. * * \memberof wl_display */ WL_EXPORT int wl_display_get_error(struct wl_display *display) { int ret; pthread_mutex_lock(&display->mutex); ret = display->last_error; pthread_mutex_unlock(&display->mutex); return ret; } /** Retrieves the information about a protocol error: * * \param display The Wayland display * \param interface if not NULL, stores the interface where the error occurred, * or NULL, if unknown. * \param id if not NULL, stores the object id that generated * the error, or 0, if the object id is unknown. There's no * guarantee the object is still valid; the client must know * if it deleted the object. * \return The error code as defined in the interface specification. * * \code * int err = wl_display_get_error(display); * * if (err == EPROTO) { * code = wl_display_get_protocol_error(display, &interface, &id); * handle_error(code, interface, id); * } * * ... * \endcode * \memberof wl_display */ WL_EXPORT uint32_t wl_display_get_protocol_error(struct wl_display *display, const struct wl_interface **interface, uint32_t *id) { uint32_t ret; pthread_mutex_lock(&display->mutex); ret = display->protocol_error.code; if (interface) *interface = display->protocol_error.interface; if (id) *id = display->protocol_error.id; pthread_mutex_unlock(&display->mutex); return ret; } /** Send all buffered requests on the display to the server * * \param display The display context object * \return The number of bytes sent on success or -1 on failure * * Send all buffered data on the client side to the server. Clients should * always call this function before blocking on input from the display fd. * On success, the number of bytes sent to the server is returned. On * failure, this function returns -1 and errno is set appropriately. * * wl_display_flush() never blocks. It will write as much data as * possible, but if all data could not be written, errno will be set * to EAGAIN and -1 returned. In that case, use poll on the display * file descriptor to wait for it to become writable again. * * \memberof wl_display */ WL_EXPORT int wl_display_flush(struct wl_display *display) { int ret; pthread_mutex_lock(&display->mutex); if (display->last_error) { errno = display->last_error; ret = -1; } else { /* We don't make EPIPE a fatal error here, so that we may try to * read events after the failed flush. When the compositor sends * an error it will close the socket, and if we make EPIPE fatal * here we don't get a chance to process the error. */ ret = wl_connection_flush(display->connection); if (ret < 0 && errno != EAGAIN && errno != EPIPE) display_fatal_error(display, errno); } pthread_mutex_unlock(&display->mutex); return ret; } /** Set the user data associated with a proxy * * \param proxy The proxy object * \param user_data The data to be associated with proxy * * Set the user data associated with \c proxy. When events for this * proxy are received, \c user_data will be supplied to its listener. * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data) { proxy->user_data = user_data; } /** Get the user data associated with a proxy * * \param proxy The proxy object * \return The user data associated with proxy * * \memberof wl_proxy */ WL_EXPORT void * wl_proxy_get_user_data(struct wl_proxy *proxy) { return proxy->user_data; } /** Get the protocol object version of a proxy object * * \param proxy The proxy object * \return The protocol object version of the proxy or 0 * * Gets the protocol object version of a proxy object, or 0 * if the proxy was created with unversioned API. * * A returned value of 0 means that no version information is * available, so the caller must make safe assumptions about * the object's real version. * * wl_display's version will always return 0. * * \memberof wl_proxy */ WL_EXPORT uint32_t wl_proxy_get_version(struct wl_proxy *proxy) { return proxy->version; } /** Get the id of a proxy object * * \param proxy The proxy object * \return The id the object associated with the proxy * * \memberof wl_proxy */ WL_EXPORT uint32_t wl_proxy_get_id(struct wl_proxy *proxy) { return proxy->object.id; } /** Get the interface name (class) of a proxy object * * \param proxy The proxy object * \return The interface name of the object associated with the proxy * * \memberof wl_proxy */ WL_EXPORT const char * wl_proxy_get_class(struct wl_proxy *proxy) { return proxy->object.interface->name; } /** Assign a proxy to an event queue * * \param proxy The proxy object * \param queue The event queue that will handle this proxy or NULL * * Assign proxy to event queue. Events coming from \c proxy will be * queued in \c queue from now. If queue is NULL, then the display's * default queue is set to the proxy. * * \note By default, the queue set in proxy is the one inherited from parent. * * \sa wl_display_dispatch_queue() * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue) { if (queue) proxy->queue = queue; else proxy->queue = &proxy->display->default_queue; } /** Create a proxy wrapper for making queue assignments thread-safe * * \param proxy The proxy object to be wrapped * \return A proxy wrapper for the given proxy or NULL on failure * * A proxy wrapper is type of 'struct wl_proxy' instance that can be used when * sending requests instead of using the original proxy. A proxy wrapper does * not have an implementation or dispatcher, and events received on the * object is still emitted on the original proxy. Trying to set an * implementation or dispatcher will have no effect but result in a warning * being logged. * * Setting the proxy queue of the proxy wrapper will make new objects created * using the proxy wrapper use the set proxy queue. * Even though there is no implementation nor dispatcher, the proxy queue can * be changed. This will affect the default queue of new objects created by * requests sent via the proxy wrapper. * * A proxy wrapper can only be destroyed using wl_proxy_wrapper_destroy(). * * A proxy wrapper must be destroyed before the proxy it was created from. * * If a user reads and dispatches events on more than one thread, it is * necessary to use a proxy wrapper when sending requests on objects when the * intention is that a newly created proxy is to use a proxy queue different * from the proxy the request was sent on, as creating the new proxy and then * setting the queue is not thread safe. * * For example, a module that runs using its own proxy queue that needs to * do display roundtrip must wrap the wl_display proxy object before sending * the wl_display.sync request. For example: * * \code * * struct wl_event_queue *queue = ...; * struct wl_display *wrapped_display; * struct wl_callback *callback; * * wrapped_display = wl_proxy_create_wrapper(display); * wl_proxy_set_queue((struct wl_proxy *) wrapped_display, queue); * callback = wl_display_sync(wrapped_display); * wl_proxy_wrapper_destroy(wrapped_display); * wl_callback_add_listener(callback, ...); * * \endcode * * \memberof wl_proxy */ WL_EXPORT void * wl_proxy_create_wrapper(void *proxy) { struct wl_proxy *wrapped_proxy = proxy; struct wl_proxy *wrapper; wrapper = zalloc(sizeof *wrapper); if (!wrapper) return NULL; pthread_mutex_lock(&wrapped_proxy->display->mutex); wrapper->object.interface = wrapped_proxy->object.interface; wrapper->object.id = wrapped_proxy->object.id; wrapper->version = wrapped_proxy->version; wrapper->display = wrapped_proxy->display; wrapper->queue = wrapped_proxy->queue; wrapper->flags = WL_PROXY_FLAG_WRAPPER; wrapper->refcount = 1; pthread_mutex_unlock(&wrapped_proxy->display->mutex); return wrapper; } /** Destroy a proxy wrapper * \param proxy_wrapper The proxy wrapper to be destroyed * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_wrapper_destroy(void *proxy_wrapper) { struct wl_proxy *wrapper = proxy_wrapper; if (!(wrapper->flags & WL_PROXY_FLAG_WRAPPER)) wl_abort("Tried to destroy non-wrapper proxy with " "wl_proxy_wrapper_destroy\n"); assert(wrapper->refcount == 1); free(wrapper); } WL_EXPORT void wl_log_set_handler_client(wl_log_func_t handler) { wl_log_handler = handler; }