[PATCH wayland 1/2] Add support for server-side language bindings

Jason Ekstrand jason at jlekstrand.net
Mon Apr 8 07:30:57 PDT 2013


This commit adds support for server-side languages bindings.  This is done in
two ways:

1. Adding versions of wl_client_add_object and wl_client_new_object that take
a dispatcher and dispatcher-specific implementation pointer.  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 at jlekstrand.net>
---
 src/connection.c      |   8 ++++
 src/wayland-private.h |  15 +++----
 src/wayland-server.c  | 114 ++++++++++++++++++++++++++++++++++++++++++++------
 src/wayland-server.h  |  15 +++++++
 src/wayland-util.h    |  40 ++++++++++++++++++
 5 files changed, 170 insertions(+), 22 deletions(-)

In order to detect that a resource is dispatched, I set the implementation
pointer to the resource.  Really, it doesn't matter what "implementation" is
used to denote that a resource is dispatched.  The only thing that matters is
that it is detectable and that it would be complete nonsense as as
implementation.  Users of libwayland should NEVER make any assumptions about
what will be used to denote a dispatched resource.  They should only know that
they created it as a dispatched resource and leave the implementation field
alone.

diff --git a/src/connection.c b/src/connection.c
index dca134b..9425ca6 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -887,6 +887,14 @@ wl_closure_invoke(struct wl_closure *closure, uint32_t flags,
 	ffi_call(&cif, implementation[opcode], NULL, ffi_args);
 }
 
+void
+wl_closure_dispatch(struct wl_closure *closure, struct wl_dispatcher *dispatch,
+		    struct wl_object *target, uint32_t opcode)
+{
+	dispatch->dispatcher(dispatch->data, target, opcode,
+			     closure->message, closure->args);
+}
+
 static int
 copy_fds_to_connection(struct wl_closure *closure,
 		       struct wl_connection *connection)
diff --git a/src/wayland-private.h b/src/wayland-private.h
index c4ce6b0..3d5131a 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -74,15 +74,9 @@ int wl_connection_write(struct wl_connection *connection, const void *data, size
 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_dispatcher {
+	wl_dispatcher_func_t dispatcher;
+	const void *data;
 };
 
 struct wl_closure {
@@ -137,6 +131,9 @@ enum wl_closure_invoke_flag {
 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, struct wl_dispatcher *dispatch,
+		    struct wl_object *target, uint32_t opcode);
 int
 wl_closure_send(struct wl_closure *closure, struct wl_connection *connection);
 int
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 2109674..490b24a 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -102,6 +102,11 @@ struct wl_global {
 	struct wl_list link;
 };
 
+struct wl_dispatched_resource {
+	struct wl_resource resource;
+	struct wl_dispatcher dispatcher;
+};
+
 static int wl_debug = 0;
 
 static void
@@ -113,16 +118,14 @@ destroy_client(void *data)
 }
 
 WL_EXPORT void
-wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
+wl_resource_post_event_a(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)
 		return;
@@ -137,19 +140,31 @@ wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
 	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_a(resource, opcode, args);
+}
+
+WL_EXPORT void
+wl_resource_queue_event_a(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)
 		return;
 
@@ -164,6 +179,21 @@ wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)
 }
 
 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_a(resource, opcode, args);
+}
+
+WL_EXPORT void
 wl_resource_post_error(struct wl_resource *resource,
 		       uint32_t code, const char *msg, ...)
 {
@@ -197,6 +227,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
 	struct wl_client *client = data;
 	struct wl_connection *connection = client->connection;
 	struct wl_resource *resource;
+	struct wl_dispatched_resource *dispatched_resource;
 	struct wl_object *object;
 	struct wl_closure *closure;
 	const struct wl_message *message;
@@ -277,8 +308,16 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
 		if (wl_debug)
 			wl_closure_print(closure, object, false);
 
-		wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, object,
-				  opcode, client);
+		if (object->implementation == (void *)resource) {
+			dispatched_resource =
+				(struct wl_dispatched_resource *)resource;
+			wl_closure_dispatch(closure,
+					    &dispatched_resource->dispatcher,
+					    object, opcode);
+		} else {
+			wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER,
+					  object, opcode, client);
+		}
 
 		wl_closure_destroy(closure);
 
@@ -1438,6 +1477,55 @@ wl_client_add_object(struct wl_client *client,
 }
 
 WL_EXPORT struct wl_resource *
+wl_client_add_dispatched_object(struct wl_client *client,
+				const struct wl_interface *interface,
+				wl_dispatcher_func_t dispatcher_func,
+				const void *dispatch_data,
+				uint32_t id, void *data)
+{
+	struct wl_dispatched_resource *dispatched_resource;
+	struct wl_resource *resource;
+
+	dispatched_resource = malloc(sizeof *dispatched_resource);
+	if (dispatched_resource == NULL) {
+		wl_resource_post_no_memory(client->display_resource);
+		return NULL;
+	}
+	resource = &dispatched_resource->resource;
+
+	wl_resource_init(resource, interface, resource, id, data);
+	resource->client = client;
+	resource->destroy = (void *) free;
+
+	dispatched_resource->dispatcher.dispatcher = dispatcher_func;
+	dispatched_resource->dispatcher.data = dispatch_data;
+
+	if (wl_map_insert_at(&client->objects, resource->object.id, resource) < 0) {
+		wl_resource_post_error(client->display_resource,
+				       WL_DISPLAY_ERROR_INVALID_OBJECT,
+				       "invalid new id %d",
+				       resource->object.id);
+		free(resource);
+		return NULL;
+	}
+
+	return resource;
+}
+
+WL_EXPORT struct wl_resource *
+wl_client_new_dispatched_object(struct wl_client *client,
+				const struct wl_interface *interface,
+				wl_dispatcher_func_t dispatcher,
+				const void *dispatch_data, void *data)
+{
+	uint32_t id;
+
+	id = wl_map_insert_new(&client->objects, WL_MAP_SERVER_SIDE, NULL);
+	return wl_client_add_dispatched_object(client, interface, dispatcher,
+					       dispatch_data, id, data);
+}
+
+WL_EXPORT struct wl_resource *
 wl_client_new_object(struct wl_client *client,
 		     const struct wl_interface *interface,
 		     const void *implementation, void *data)
diff --git a/src/wayland-server.h b/src/wayland-server.h
index af2be62..c8cb441 100644
--- a/src/wayland-server.h
+++ b/src/wayland-server.h
@@ -137,6 +137,17 @@ wl_client_new_object(struct wl_client *client,
 		     const struct wl_interface *interface,
 		     const void *implementation, void *data);
 struct wl_resource *
+wl_client_add_dispatched_object(struct wl_client *client,
+				const struct wl_interface *interface,
+				wl_dispatcher_func_t dispatcher,
+				const void *dispatch_data,
+				uint32_t id, void *data);
+struct wl_resource *
+wl_client_new_dispatched_object(struct wl_client *client,
+				const struct wl_interface *interface,
+				wl_dispatcher_func_t dispatcher,
+				const void *dispatch_data, void *data);
+struct wl_resource *
 wl_client_get_object(struct wl_client *client, uint32_t id);
 
 struct wl_listener {
@@ -403,8 +414,12 @@ struct wl_seat {
  * - type=new_id:	(struct wl_object *) or (struct wl_resource *)
  * - type=object:	(struct wl_object *) or (struct wl_resource *)
  */
+void wl_resource_post_event_a(struct wl_resource *resource,
+			      uint32_t opcode, union wl_argument *args);
 void wl_resource_post_event(struct wl_resource *resource,
 			    uint32_t opcode, ...);
+void wl_resource_queue_event_a(struct wl_resource *resource,
+			       uint32_t opcode, union wl_argument *args);
 void wl_resource_queue_event(struct wl_resource *resource,
 			     uint32_t opcode, ...);
 
diff --git a/src/wayland-util.h b/src/wayland-util.h
index dbe05a5..a3020e2 100644
--- a/src/wayland-util.h
+++ b/src/wayland-util.h
@@ -198,6 +198,46 @@ 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
-- 
1.8.1.4



More information about the wayland-devel mailing list