[RFC wayland 10/18] scanner: Add the concept of "pre hooks"
Mike Blumenkrantz
zmike at samsung.com
Tue Feb 9 17:50:01 UTC 2016
On Tue, 09 Feb 2016 10:55:57 -0600
Derek Foreman <derekf at osg.samsung.com> wrote:
> 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
Is "hook" the best term? I think I like "intercept" better in this case: consider that something here is "intercepting" the marshallization process and modifying it to contain an additional payload rather than "hooking" it to perform an action.
More information about the wayland-devel
mailing list