[RFC wayland] Add server-side dispatchers support

Jason Ekstrand jason at jlekstrand.net
Sat Mar 23 11:33:11 PDT 2013


Devs,
This patch adds support on the server half of the library for dispatchers.
While being a bit of a hack, it adds dispatchers without touching any exposed
structures so it does not break API or ABI.  The one downside is that programs
taking advantage of this cannot edit the dispatching information after the
resource is created.  However, I don't think we really care about supporting
this anyway.

Comments welcome!
--Jason Ekstrand

---
 src/connection.c      |  8 ++++++
 src/wayland-private.h | 15 +++++-------
 src/wayland-server.c  | 67 +++++++++++++++++++++++++++++++++++++++++++++++++--
 src/wayland-server.h  | 11 +++++++++
 src/wayland-util.h    | 15 ++++++++++++
 5 files changed, 105 insertions(+), 11 deletions(-)

diff --git a/src/connection.c b/src/connection.c
index dca134b..381c05e 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, void *data)
+{
+	dispatch->dispatcher(dispatch->data, target, opcode,
+			     closure->message, data, 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..c5ebbf5 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, void *data);
 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 dcb4435..53ef007 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
@@ -197,6 +202,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 +283,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 ((struct wl_resource *)object->implementation == resource) {
+			dispatched_resource =
+				(struct wl_dispatched_resource *)resource;
+			wl_closure_dispatch(closure,
+					    &dispatched_resource->dispatcher,
+					    object, opcode, client);
+		} else {
+			wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER,
+					  object, opcode, client);
+		}
 
 		wl_closure_destroy(closure);
 
@@ -1413,6 +1427,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 38b8303..c908134 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 {
diff --git a/src/wayland-util.h b/src/wayland-util.h
index 257a5d1..34c39ca 100644
--- a/src/wayland-util.h
+++ b/src/wayland-util.h
@@ -198,6 +198,21 @@ static inline wl_fixed_t wl_fixed_from_int(int i)
 	return i * 256;
 }
 
+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;
+};
+
+typedef void (*wl_dispatcher_func_t)(const void *, struct wl_object *,
+				     uint32_t, const struct wl_message *,
+				     void *, 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