[PATCH wayland 4/7 v3] Add support for custom dispatchers

Jason Ekstrand jason at jlekstrand.net
Tue Feb 19 14:09:21 PST 2013


Signed-off-by: Jason Ekstrand <jason at jlekstrand.net>
---
This version contains the documentation changes as requested by Pekka Paalanen
as well as the if-statement change suggested by Bill Spitzak.

 src/connection.c        | 15 +++++++++----
 src/wayland-client.c    | 13 +++++++++--
 src/wayland-private.h   |  3 ++-
 src/wayland-server.c    |  9 +++++++-
 src/wayland-util.h      | 35 +++++++++++++++++++++++++++--
 tests/dispatcher-test.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 125 insertions(+), 10 deletions(-)

diff --git a/src/connection.c b/src/connection.c
index 7c5916b..6fa2219 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -809,11 +809,18 @@ wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects)
 
 void
 wl_closure_invoke(struct wl_closure *closure,
-		  struct wl_object *target, uint32_t opcode, void *data)
+		  struct wl_object *target, uint32_t opcode, void *data,
+		  wl_interface_dispatcher_func_t dispatcher)
 {
-	wl_interface_default_dispatcher(target, opcode,
-					closure->message,
-					data, closure->args);
+	if (dispatcher) {
+		(*dispatcher)(target, opcode, closure->message,
+			      data, closure->args);
+	} else {
+		wl_interface_default_dispatcher(target, opcode,
+						closure->message,
+						data, closure->args);
+	}
+
 }
 
 static int
diff --git a/src/wayland-client.c b/src/wayland-client.c
index e8cf7a2..7e34bf9 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -806,6 +806,7 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
 {
 	struct wl_closure *closure;
 	struct wl_proxy *proxy;
+	const struct wl_interface *interface;
 	int opcode;
 	bool proxy_destroyed;
 
@@ -836,8 +837,16 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
 		if (wl_debug)
 			wl_closure_print(closure, &proxy->object, false);
 
-		wl_closure_invoke(closure, &proxy->object, opcode,
-				  proxy->user_data);
+		interface = proxy->object.interface;
+		if ((interface->version >> 16) > 0) {
+			/* If it supports dispatchers */
+			wl_closure_invoke(closure, &proxy->object, opcode,
+					  proxy->user_data,
+					  interface->event_dispatcher);
+		} else {
+			wl_closure_invoke(closure, &proxy->object, opcode,
+					  proxy->user_data, NULL);
+		}
 	}
 
 	wl_closure_destroy(closure);
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 79e5ec7..6aac040 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -120,7 +120,8 @@ wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects);
 
 void
 wl_closure_invoke(struct wl_closure *closure,
-		  struct wl_object *target, uint32_t opcode, void *data);
+		  struct wl_object *target, uint32_t opcode, void *data,
+		  wl_interface_dispatcher_func_t dispatcher);
 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 e45b880..104f9a6 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -277,7 +277,14 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
 		if (wl_debug)
 			wl_closure_print(closure, object, false);
 
-		wl_closure_invoke(closure, object, opcode, client);
+		if ((object->interface->version >> 16) > 0) {
+			/* If it supports dispatchers */
+			wl_closure_invoke(closure, object, opcode, client,
+					  object->interface->method_dispatcher);
+		} else {
+			wl_closure_invoke(closure, object, opcode, client,
+					  NULL);
+		}
 
 		wl_closure_destroy(closure);
 
diff --git a/src/wayland-util.h b/src/wayland-util.h
index df7b384..2d3367f 100644
--- a/src/wayland-util.h
+++ b/src/wayland-util.h
@@ -46,18 +46,49 @@ struct wl_message {
 	const struct wl_interface **types;
 };
 
+union wl_argument;
+struct wl_object;
+
+typedef void (*wl_interface_dispatcher_func_t)(struct wl_object *, uint32_t,
+					       const struct wl_message *,
+					       void *, union wl_argument *);
+/**
+ * wl_interface - object method interface
+ *
+ * This structure has been extended since libwayland version 1.  The version
+ * field now represents both an interface version and a structure version.
+ * The upper 16 bits represent the version of the structure with the original
+ * version being version 0.  The lower 16 bits represent the interface version
+ * as specified in the interface XML file.  This way, as long as the version
+ * number is something sane and we always check the version number before
+ * reading any fields that are not in the original structure, we should be
+ * fine.
+ *
+ * Special care must, however, be taken with the auto-generated instances of
+ * wl_interface created by the scanner.  Because each of the generated
+ * interfaces is a global extern variable, the memory for them may be allocated
+ * by the client-code and not by the library.  Because the client code
+ * allocates only allocates enough memory for the size it knows about, any
+ * fields unknown to the client cannot be trusted. Therefore, increasing the
+ * interface version of wl_interface globals generated by the scanner
+ * constitutes an ABI break.
+ */
 struct wl_interface {
 	const char *name;
-	int version;
+	uint32_t version;
 	int method_count;
 	const struct wl_message *methods;
 	int event_count;
 	const struct wl_message *events;
+
+	/* Added in version 1 */
+	wl_interface_dispatcher_func_t method_dispatcher;
+	wl_interface_dispatcher_func_t event_dispatcher;
 };
 
 struct wl_object {
 	const struct wl_interface *interface;
-	void (* const * implementation)(void);
+	const void *implementation;
 	uint32_t id;
 };
 
diff --git a/tests/dispatcher-test.c b/tests/dispatcher-test.c
index d38e7cb..ef82d9f 100644
--- a/tests/dispatcher-test.c
+++ b/tests/dispatcher-test.c
@@ -93,3 +93,63 @@ TEST(default_dispatcher)
 	assert(args_in[7].h == args_out[7].h);
 	assert(args_out[8].o == &target);
 }
+
+static void
+test_implementation_func(void *data, struct wl_object *target, int32_t i)
+{
+	*(int *)data = -i;
+}
+
+static void
+test_dispatcher_func(struct wl_object *obj, uint32_t opcode,
+		     const struct wl_message *message, void *data,
+		     union wl_argument *args)
+{
+	*(int *)data = args[0].i + opcode;
+}
+
+static void
+run_dispatcher_test(int *result, struct wl_interface *interface,
+		    void *implementation, uint32_t opcode, int value,
+		    wl_interface_dispatcher_func_t dispatcher)
+{
+	struct wl_object sender = { interface, implementation, 1234 };
+	struct wl_object target = { interface, implementation, 1234 };
+	struct wl_closure *closure;
+	union wl_argument arg;
+
+	arg.i = value;
+	implementation = &test_implementation_func;
+	closure = wl_closure_marshal(&sender, opcode, &arg, interface->events);
+	wl_closure_invoke(closure, &target, opcode, result, dispatcher);
+	wl_closure_destroy(closure);
+}
+
+TEST(custom_dispatcher)
+{
+	struct wl_message message = { "test", "i", NULL };
+	struct wl_interface interface = {
+		"test",
+		1,
+		1, &message,
+		1, &message,
+		NULL, NULL
+	};
+	void (*implementation_func)(void *, struct wl_object *, int32_t);
+	int i;
+
+	implementation_func = &test_implementation_func;
+
+
+	run_dispatcher_test(&i, &interface, &implementation_func, 0, 1234,
+			    NULL);
+	assert(i == -1234);
+
+	run_dispatcher_test(&i, &interface, NULL, 0, 1234,
+			    test_dispatcher_func);
+	assert(i == 1234);
+
+	run_dispatcher_test(&i, &interface, NULL, 42, 1234,
+			    test_dispatcher_func);
+	assert(i == 1234 + 42);
+}
-- 
1.8.1.2



More information about the wayland-devel mailing list