summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Ekstrand <jason@jlekstrand.net>2013-07-17 21:58:46 -0500
committerKristian Høgsberg <krh@bitplanet.net>2013-08-19 16:23:08 -0700
commitc44090908db1c4f1b0e87bda2e4fdaa6bc15c0d1 (patch)
tree0685fb9542a2693899bc04d4fdc9efefe8ca82ff
parent6b8eef962f4d662d64c46439fc7b09278ccf2e0d (diff)
Add support for server-side language bindings
This commit adds support for server-side languages bindings. This is done in two ways: 1. Adding a wl_resource_set_dispatcher function that corresponds to wl_resource_set_interface. The only difference between the two functions is that the new version takes a dispatcher along with the implementation, data, and destructor. This allows for runtime calling of native language functions for callbacks instead of having to generate function pointers. 2. Adding versions of wl_resource_post_event and wl_resource_queue_event that take an array of wl_argument instead of a variable argument list. This allows for easier run-time argument conversion and removes the need for libffi-based calling of variadic functions. Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
-rw-r--r--src/connection.c9
-rw-r--r--src/wayland-private.h14
-rw-r--r--src/wayland-server.c72
-rw-r--r--src/wayland-server.h10
-rw-r--r--src/wayland-util.h40
5 files changed, 120 insertions, 25 deletions
diff --git a/src/connection.c b/src/connection.c
index 9bb850c..451b93e 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -888,13 +888,12 @@ convert_arguments_to_ffi(const char *signature, uint32_t flags,
assert(0);
break;
}
}
}
-
void
wl_closure_invoke(struct wl_closure *closure, uint32_t flags,
struct wl_object *target, uint32_t opcode, void *data)
{
int count;
ffi_cif cif;
@@ -916,12 +915,20 @@ wl_closure_invoke(struct wl_closure *closure, uint32_t flags,
count + 2, &ffi_type_void, ffi_types);
implementation = target->implementation;
ffi_call(&cif, implementation[opcode], NULL, ffi_args);
}
+void
+wl_closure_dispatch(struct wl_closure *closure, wl_dispatcher_func_t dispatcher,
+ struct wl_object *target, uint32_t opcode)
+{
+ dispatcher(target->implementation, target, opcode, closure->message,
+ closure->args);
+}
+
static int
copy_fds_to_connection(struct wl_closure *closure,
struct wl_connection *connection)
{
const struct wl_message *message = closure->message;
uint32_t i, count;
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 7f8c12c..67e8783 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -94,23 +94,12 @@ int wl_connection_flush(struct wl_connection *connection);
int wl_connection_read(struct wl_connection *connection);
int wl_connection_write(struct wl_connection *connection, const void *data, size_t count);
int wl_connection_queue(struct wl_connection *connection,
const void *data, size_t count);
-union wl_argument {
- int32_t i;
- uint32_t u;
- wl_fixed_t f;
- const char *s;
- struct wl_object *o;
- uint32_t n;
- struct wl_array *a;
- int32_t h;
-};
-
struct wl_closure {
int count;
const struct wl_message *message;
uint32_t opcode;
uint32_t sender_id;
union wl_argument args[WL_CLOSURE_MAX_ARGS];
@@ -160,12 +149,15 @@ enum wl_closure_invoke_flag {
WL_CLOSURE_INVOKE_SERVER = (1 << 1)
};
void
wl_closure_invoke(struct wl_closure *closure, uint32_t flags,
struct wl_object *target, uint32_t opcode, void *data);
+void
+wl_closure_dispatch(struct wl_closure *closure, wl_dispatcher_func_t dispatcher,
+ struct wl_object *target, uint32_t opcode);
int
wl_closure_send(struct wl_closure *closure, struct wl_connection *connection);
int
wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection);
void
wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send);
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 771309f..a1d69e5 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -111,27 +111,26 @@ struct wl_resource {
wl_resource_destroy_func_t destroy;
struct wl_list link;
struct wl_signal destroy_signal;
struct wl_client *client;
void *data;
int version;
+ wl_dispatcher_func_t dispatcher;
};
static int wl_debug = 0;
WL_EXPORT void
-wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
+wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode,
+ union wl_argument *args)
{
struct wl_closure *closure;
struct wl_object *object = &resource->object;
- va_list ap;
- va_start(ap, opcode);
- closure = wl_closure_vmarshal(object, opcode, ap,
- &object->interface->events[opcode]);
- va_end(ap);
+ closure = wl_closure_marshal(object, opcode, args,
+ &object->interface->events[opcode]);
if (closure == NULL) {
resource->client->error = 1;
return;
}
@@ -141,25 +140,38 @@ wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
if (wl_debug)
wl_closure_print(closure, object, true);
wl_closure_destroy(closure);
}
-
WL_EXPORT void
-wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)
+wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
{
- struct wl_closure *closure;
+ union wl_argument args[WL_CLOSURE_MAX_ARGS];
struct wl_object *object = &resource->object;
va_list ap;
va_start(ap, opcode);
- closure = wl_closure_vmarshal(object, opcode, ap,
- &object->interface->events[opcode]);
+ wl_argument_from_va_list(object->interface->events[opcode].signature,
+ args, WL_CLOSURE_MAX_ARGS, ap);
va_end(ap);
+ wl_resource_post_event_array(resource, opcode, args);
+}
+
+
+WL_EXPORT void
+wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode,
+ union wl_argument *args)
+{
+ struct wl_closure *closure;
+ struct wl_object *object = &resource->object;
+
+ closure = wl_closure_marshal(object, opcode, args,
+ &object->interface->events[opcode]);
+
if (closure == NULL) {
resource->client->error = 1;
return;
}
if (wl_closure_queue(closure, resource->client->connection))
@@ -169,12 +181,27 @@ wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)
wl_closure_print(closure, object, true);
wl_closure_destroy(closure);
}
WL_EXPORT void
+wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)
+{
+ union wl_argument args[WL_CLOSURE_MAX_ARGS];
+ struct wl_object *object = &resource->object;
+ va_list ap;
+
+ va_start(ap, opcode);
+ wl_argument_from_va_list(object->interface->events[opcode].signature,
+ args, WL_CLOSURE_MAX_ARGS, ap);
+ va_end(ap);
+
+ wl_resource_queue_event_array(resource, opcode, args);
+}
+
+WL_EXPORT void
wl_resource_post_error(struct wl_resource *resource,
uint32_t code, const char *msg, ...)
{
struct wl_client *client = resource->client;
char buffer[128];
va_list ap;
@@ -297,14 +324,20 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
break;
}
if (wl_debug)
wl_closure_print(closure, object, false);
- wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, object,
- opcode, client);
+ if ((resource_flags & WL_MAP_ENTRY_LEGACY) ||
+ resource->dispatcher == NULL) {
+ wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER,
+ object, opcode, client);
+ } else {
+ wl_closure_dispatch(closure, resource->dispatcher,
+ object, opcode);
+ }
wl_closure_destroy(closure);
if (client->error)
break;
}
@@ -1029,14 +1062,26 @@ wl_resource_set_implementation(struct wl_resource *resource,
const void *implementation,
void *data, wl_resource_destroy_func_t destroy)
{
resource->object.implementation = implementation;
resource->data = data;
resource->destroy = destroy;
+ resource->dispatcher = NULL;
}
+WL_EXPORT void
+wl_resource_set_dispatcher(struct wl_resource *resource,
+ wl_dispatcher_func_t dispatcher,
+ const void *implementation,
+ void *data, wl_resource_destroy_func_t destroy)
+{
+ resource->dispatcher = dispatcher;
+ resource->object.implementation = implementation;
+ resource->data = data;
+ resource->destroy = destroy;
+}
WL_EXPORT struct wl_resource *
wl_resource_create(struct wl_client *client,
const struct wl_interface *interface,
int version, uint32_t id)
{
@@ -1056,12 +1101,13 @@ wl_resource_create(struct wl_client *client,
wl_signal_init(&resource->destroy_signal);
resource->destroy = NULL;
resource->client = client;
resource->data = NULL;
resource->version = version;
+ resource->dispatcher = NULL;
if (wl_map_insert_at(&client->objects, 0, resource->object.id, resource) < 0) {
wl_resource_post_error(client->display_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"invalid new id %d",
resource->object.id);
diff --git a/src/wayland-server.h b/src/wayland-server.h
index e5e0ed8..d77050d 100644
--- a/src/wayland-server.h
+++ b/src/wayland-server.h
@@ -238,14 +238,18 @@ wl_display_remove_global(struct wl_display *display,
* - type=fd: int, that is an open file descriptor
* - type=new_id: (struct wl_object *) or (struct wl_resource *)
* - type=object: (struct wl_object *) or (struct wl_resource *)
*/
void wl_resource_post_event(struct wl_resource *resource,
uint32_t opcode, ...);
+void wl_resource_post_event_array(struct wl_resource *resource,
+ uint32_t opcode, union wl_argument *args);
void wl_resource_queue_event(struct wl_resource *resource,
uint32_t opcode, ...);
+void wl_resource_queue_event_array(struct wl_resource *resource,
+ uint32_t opcode, union wl_argument *args);
/* msg is a printf format string, variable args are its args. */
void wl_resource_post_error(struct wl_resource *resource,
uint32_t code, const char *msg, ...)
__attribute__ ((format (printf, 3, 4)));
void wl_resource_post_no_memory(struct wl_resource *resource);
@@ -261,12 +265,18 @@ wl_resource_create(struct wl_client *client,
int version, uint32_t id);
void
wl_resource_set_implementation(struct wl_resource *resource,
const void *implementation,
void *data,
wl_resource_destroy_func_t destroy);
+void
+wl_resource_set_dispatcher(struct wl_resource *resource,
+ wl_dispatcher_func_t dispatcher,
+ const void *implementation,
+ void *data,
+ wl_resource_destroy_func_t destroy);
void
wl_resource_destroy(struct wl_resource *resource);
uint32_t
wl_resource_get_id(struct wl_resource *resource);
struct wl_list *
diff --git a/src/wayland-util.h b/src/wayland-util.h
index 53d3282..e5e4e25 100644
--- a/src/wayland-util.h
+++ b/src/wayland-util.h
@@ -196,12 +196,52 @@ static inline int wl_fixed_to_int(wl_fixed_t f)
}
static inline wl_fixed_t wl_fixed_from_int(int i)
{
return i * 256;
}
+/**
+ * \brief A union representing all of the basic data types that can be passed
+ * along the wayland wire format.
+ *
+ * This union represents all of the basic data types that can be passed in the
+ * wayland wire format. It is used by dispatchers and runtime-friendly
+ * versions of the event and request marshaling functions.
+ */
+union wl_argument {
+ int32_t i; /**< signed integer */
+ uint32_t u; /**< unsigned integer */
+ wl_fixed_t f; /**< fixed point */
+ const char *s; /**< string */
+ struct wl_object *o; /**< object */
+ uint32_t n; /**< new_id */
+ struct wl_array *a; /**< array */
+ int32_t h; /**< file descriptor */
+};
+
+/**
+ * \brief A function pointer type for a dispatcher.
+ *
+ * A dispatcher is a function that handles the emitting of callbacks in client
+ * code. For programs directly using the C library, this is done by using
+ * libffi to call function pointers. When binding to languages other than C,
+ * dispatchers provide a way to abstract the function calling process to be
+ * friendlier to other function calling systems.
+ *
+ * A dispatcher takes five arguments: The first is the dispatcher-specific
+ * implementation data associated with the target object. The second is the
+ * object on which the callback is being invoked (either wl_proxy or
+ * wl_resource). The third and fourth arguments are the opcode the wl_messsage
+ * structure corresponding to the callback being emitted. The final argument
+ * is an array of arguments recieved from the other process via the wire
+ * protocol.
+ */
+typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t,
+ const struct wl_message *,
+ union wl_argument *);
+
typedef void (*wl_log_func_t)(const char *, va_list);
#ifdef __cplusplus
}
#endif