/*
|
* 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 <stdlib.h>
|
#include <stdint.h>
|
#include <stddef.h>
|
#include <stdio.h>
|
#include <stdbool.h>
|
#include <errno.h>
|
#include <string.h>
|
#include <unistd.h>
|
#include <sys/socket.h>
|
#include <sys/un.h>
|
#include <ctype.h>
|
#include <assert.h>
|
#include <fcntl.h>
|
#include <poll.h>
|
#include <pthread.h>
|
|
#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;
|
}
|