[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