[RFC wayland 10/18] scanner: Add the concept of "pre hooks"

Derek Foreman derekf at osg.samsung.com
Tue Feb 9 16:55:57 UTC 2016


A pre hook is a wayland library call made on the client side before the
request is sent.

Until now the wayland library has simply passed requests on without any
knowledge of what they mean, and the receiving compositor has all the
logic.  For network transparency to be truly transparent, the library
needs to intercept some things on the client side (buffer set-up, damage
posting) and send along additional information.

pre-hooks make that possible.

Signed-off-by: Derek Foreman <derekf at osg.samsung.com>
---
 protocol/wayland.dtd      |   1 +
 src/scanner.c             | 108 +++++++++++++++++++++++++++++++++++++++++++---
 src/wayland-client-core.h |  10 +++++
 src/wayland-client.c      |  13 ++++++
 4 files changed, 126 insertions(+), 6 deletions(-)

diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd
index 15f20ab..15ca9cc 100644
--- a/protocol/wayland.dtd
+++ b/protocol/wayland.dtd
@@ -8,6 +8,7 @@
   <!ATTLIST request name CDATA #REQUIRED>
   <!ATTLIST request type CDATA #IMPLIED>
   <!ATTLIST request since CDATA #IMPLIED>
+  <!ATTLIST request hooked CDATA #IMPLIED>
 <!ELEMENT event (description?,arg*)>
   <!ATTLIST event name CDATA #REQUIRED>
   <!ATTLIST event since CDATA #IMPLIED>
diff --git a/src/scanner.c b/src/scanner.c
index 9a74e93..e598200 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -170,6 +170,7 @@ struct message {
 	int destructor;
 	int since;
 	struct description *description;
+	bool hooked;
 };
 
 enum arg_type {
@@ -609,6 +610,7 @@ start_element(void *data, const char *element_name, const char **atts)
 	const char *allow_null = NULL;
 	const char *enumeration_name = NULL;
 	const char *bitfield = NULL;
+	const char *hooked = NULL;
 	int i, version = 0;
 
 	ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
@@ -636,6 +638,8 @@ start_element(void *data, const char *element_name, const char **atts)
 			enumeration_name = atts[i + 1];
 		if (strcmp(atts[i], "bitfield") == 0)
 			bitfield = atts[i + 1];
+		if (strcmp(atts[i], "hooked") == 0)
+			hooked = atts[i + 1];
 	}
 
 	ctx->character_data_length = 0;
@@ -665,6 +669,15 @@ start_element(void *data, const char *element_name, const char **atts)
 
 		message = create_message(ctx->loc, name);
 
+		if (hooked) {
+			if (strcmp(hooked, "true") == 0)
+				message->hooked = true;
+			else if (strcmp(hooked, "false") != 0)
+				fail(&ctx->loc,
+				     "invalid value for hooked attribute (%s)",
+				     hooked);
+		}
+
 		if (strcmp(element_name, "request") == 0)
 			wl_list_insert(ctx->interface->request_list.prev,
 				       &message->link);
@@ -938,6 +951,79 @@ emit_type(struct arg *a)
 }
 
 static void
+emit_pre_hook_prototype(struct message *m, struct interface *interface, struct arg *r)
+{
+	struct arg *a;
+
+	if (r)
+		printf("void *\n");
+	else
+		printf("void\n");
+
+	printf("%s_%s_pre_hook(struct %s *",
+	       interface->name, m->name, interface->name);
+	wl_list_for_each(a, &m->arg_list, link) {
+		if (a->type == NEW_ID && a->interface_name == NULL) {
+			printf(", const struct wl_interface *interface"
+			       ", uint32_t version");
+			continue;
+		} else if (a->type == NEW_ID)
+			continue;
+		printf(", ");
+		emit_type(a);
+		printf("%s", a->name);
+	}
+	printf(");");
+}
+
+static void
+emit_pre_hooks(struct wl_list *message_list, struct interface *interface)
+{
+	struct message *m;
+	int hooks = 0;
+
+	if (wl_list_empty(message_list))
+		return;
+	wl_list_for_each(m, message_list, link) {
+		struct arg *a, *ret = NULL;
+
+		if (!m->hooked)
+			continue;
+
+		wl_list_for_each(a, &m->arg_list, link) {
+			if (a->type == NEW_ID)
+				ret = a;
+		}
+
+		emit_pre_hook_prototype(m, interface, ret);
+		hooks++;
+	}
+	if (hooks)
+		printf("\n");
+}
+
+static void emit_call_pre_hook(struct interface *interface, struct arg *ret, struct message *m)
+{
+	struct arg *a;
+
+	if (ret) {
+		printf("\tvoid *hook_data = %s_%s_pre_hook(%s", interface->name, m->name, interface->name);
+	} else
+		printf("\t%s_%s_pre_hook(%s", interface->name, m->name, interface->name);
+	wl_list_for_each(a, &m->arg_list, link) {
+		if (a->type == NEW_ID && a->interface_name == NULL) {
+			printf(", interface"
+			       ", version");
+			continue;
+		} else if (a->type == NEW_ID)
+			continue;
+		printf(", ");
+		printf("%s", a->name);
+	}
+	printf(");\n");
+}
+
+static void
 emit_stubs(struct wl_list *message_list, struct interface *interface)
 {
 	struct message *m;
@@ -1042,27 +1128,33 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
 		if (ret && ret->interface_name == NULL) {
 			/* an arg has type ="new_id" but interface is not
 			 * provided, such as in wl_registry.bind */
-			printf("\tstruct wl_proxy *%s;\n\n"
-			       "\t%s = wl_proxy_marshal_constructor_versioned("
+			printf("\tstruct wl_proxy *%s;\n\n", ret->name);
+			if (m->hooked)
+				emit_call_pre_hook(interface, ret, m);
+			printf("\t%s = wl_proxy_marshal_constructor_versioned("
 			       "(struct wl_proxy *) %s,\n"
 			       "\t\t\t %s_%s, interface, version",
-			       ret->name, ret->name,
+			       ret->name,
 			       interface->name,
 			       interface->uppercase_name,
 			       m->uppercase_name);
 		} else if (ret) {
 			/* Normal factory case, an arg has type="new_id" and
 			 * an interface is provided */
-			printf("\tstruct wl_proxy *%s;\n\n"
-			       "\t%s = wl_proxy_marshal_constructor("
+			printf("\tstruct wl_proxy *%s;\n\n", ret->name);
+			if (m->hooked)
+				emit_call_pre_hook(interface, ret, m);
+			printf("\t%s = wl_proxy_marshal_constructor("
 			       "(struct wl_proxy *) %s,\n"
 			       "\t\t\t %s_%s, &%s_interface",
-			       ret->name, ret->name,
+			       ret->name,
 			       interface->name,
 			       interface->uppercase_name,
 			       m->uppercase_name,
 			       ret->interface_name);
 		} else {
+			if (m->hooked)
+				emit_call_pre_hook(interface, ret, m);
 			/* No args have type="new_id" */
 			printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
 			       "\t\t\t %s_%s",
@@ -1087,6 +1179,9 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
 			       "(struct wl_proxy *) %s);\n",
 			       interface->name);
 
+		if (ret && m->hooked)
+			printf("\twl_proxy_set_hook_data(id, hook_data);\n");
+
 		if (ret && ret->interface_name == NULL)
 			printf("\n\treturn (void *) %s;\n", ret->name);
 		else if (ret)
@@ -1434,6 +1529,7 @@ emit_header(struct protocol *protocol, enum side side)
 			emit_structs(&i->event_list, i, side);
 			emit_opcodes(&i->request_list, i);
 			emit_opcode_versions(&i->request_list, i);
+			emit_pre_hooks(&i->request_list, i);
 			emit_stubs(&i->request_list, i);
 		}
 
diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
index 91f7e7b..782b736 100644
--- a/src/wayland-client-core.h
+++ b/src/wayland-client-core.h
@@ -28,6 +28,7 @@
 
 #include "wayland-util.h"
 #include "wayland-version.h"
+#include <stdbool.h>
 
 #ifdef  __cplusplus
 extern "C" {
@@ -176,6 +177,15 @@ wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data);
 void *
 wl_proxy_get_user_data(struct wl_proxy *proxy);
 
+void
+wl_proxy_set_hook_data(struct wl_proxy *proxy, void *hook_data);
+
+void *
+wl_proxy_get_hook_data(struct wl_proxy *proxy);
+
+bool
+wl_proxy_get_remote(struct wl_proxy *proxy);
+
 uint32_t
 wl_proxy_get_version(struct wl_proxy *proxy);
 
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 5c5ecd3..8e7f612 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -63,6 +63,7 @@ struct wl_proxy {
 	void *user_data;
 	wl_dispatcher_func_t dispatcher;
 	uint32_t version;
+	void *hook_data;
 };
 
 struct wl_global {
@@ -1856,6 +1857,12 @@ wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data)
 	proxy->user_data = user_data;
 }
 
+WL_EXPORT void
+wl_proxy_set_hook_data(struct wl_proxy *proxy, void *hook_data)
+{
+	proxy->hook_data = hook_data;
+}
+
 /** Get the user data associated with a proxy
  *
  * \param proxy The proxy object
@@ -1891,6 +1898,12 @@ wl_proxy_get_version(struct wl_proxy *proxy)
 	return proxy->version;
 }
 
+WL_EXPORT void *
+wl_proxy_get_hook_data(struct wl_proxy *proxy)
+{
+	return proxy->hook_data;
+}
+
 /** Get the id of a proxy object
  *
  * \param proxy The proxy object
-- 
2.7.0



More information about the wayland-devel mailing list