[RFC libwayland] Track protocol object versions inside wl_proxy.
Jason Ekstrand
jason at jlekstrand.net
Wed Apr 2 07:48:29 PDT 2014
It's worth noting that there is one small backwards-compatability issue
here. Namely, if the client is built against protocol stubs from an
earlier version of libwayland but links against a library built against a
newer version, then all objects created by the client will report a version
of 1. This is because the old api uses wl_proxy_marshal_constructor in
wl_registry_bind so all objects will inherit the protocol version of
wl_display which is 1. The library the client linked against is aware of
the wl_proxy_version function but has no way of knowing that the library
does not.
One possible solution for this is to set the version of wl_display to zero
and use zero to mean "unversioned". Then, if a library wants to use
something that's not strictly backwards-compatable, it can check for zero
and use whatever it's non-versioned fallback is.
That said, I'm open to other suggestions.
--Jason Ekstrand
On Apr 2, 2014 12:28 AM, "Jason Ekstrand" <jason at jlekstrand.net> wrote:
> This provides a standardized mechanism for tracking protocol object
> versions in client code. The wl_display object is created with version 1.
> Every time an object is created from within wl_registry_bind, it gets the
> bound version. Every other time an object is created, it simply inherits
> it's version from the parent object that created it.
>
>
> ---
> I've been meaning to scratch this itch for a while. I've left it as an RFC
> for now because it builds, but I don't have any code to test it yet. I've
> got something I'm hoping to hack on this weekend that will use it. For
> now, feel free to comment.
>
> src/scanner.c | 29 +++++++++----
> src/wayland-client.c | 112
> +++++++++++++++++++++++++++++++++++++++++++++++----
> src/wayland-client.h | 13 ++++++
> 3 files changed, 139 insertions(+), 15 deletions(-)
>
> diff --git a/src/scanner.c b/src/scanner.c
> index e8bfc7c..43b3acf 100644
> --- a/src/scanner.c
> +++ b/src/scanner.c
> @@ -627,6 +627,14 @@ emit_stubs(struct wl_list *message_list, struct
> interface *interface)
> interface->name, interface->name, interface->name,
> interface->name);
>
> + printf("static inline uint32_t\n"
> + "%s_get_version(struct %s *%s)\n"
> + "{\n"
> + "\treturn wl_proxy_get_version((struct wl_proxy *) %s);\n"
> + "}\n\n",
> + interface->name, interface->name, interface->name,
> + interface->name);
> +
> has_destructor = 0;
> has_destroy = 0;
> wl_list_for_each(m, message_list, link) {
> @@ -698,20 +706,25 @@ emit_stubs(struct wl_list *message_list, struct
> interface *interface)
>
> printf(")\n"
> "{\n");
> - if (ret) {
> + if (ret && ret->interface_name == NULL) {
> printf("\tstruct wl_proxy *%s;\n\n"
> - "\t%s = wl_proxy_marshal_constructor("
> + "\t%s =
> wl_proxy_marshal_constructor_versioned("
> "(struct wl_proxy *) %s,\n"
> - "\t\t\t %s_%s, ",
> + "\t\t\t %s_%s, interface, version",
> ret->name, ret->name,
> interface->name,
> interface->uppercase_name,
> m->uppercase_name);
> -
> - if (ret->interface_name == NULL)
> - printf("interface");
> - else
> - printf("&%s_interface",
> ret->interface_name);
> + } else if (ret) {
> + printf("\tstruct wl_proxy *%s;\n\n"
> + "\t%s = wl_proxy_marshal_constructor("
> + "(struct wl_proxy *) %s,\n"
> + "\t\t\t %s_%s, &%s_interface",
> + ret->name, ret->name,
> + interface->name,
> + interface->uppercase_name,
> + m->uppercase_name,
> + ret->interface_name);
> } else {
> printf("\twl_proxy_marshal((struct wl_proxy *)
> %s,\n"
> "\t\t\t %s_%s",
> diff --git a/src/wayland-client.c b/src/wayland-client.c
> index bd40313..5608564 100644
> --- a/src/wayland-client.c
> +++ b/src/wayland-client.c
> @@ -59,6 +59,7 @@ struct wl_proxy {
> int refcount;
> void *user_data;
> wl_dispatcher_func_t dispatcher;
> + uint32_t version;
> };
>
> struct wl_global {
> @@ -195,7 +196,8 @@ wl_display_create_queue(struct wl_display *display)
> }
>
> static struct wl_proxy *
> -proxy_create(struct wl_proxy *factory, const struct wl_interface
> *interface)
> +proxy_create(struct wl_proxy *factory, const struct wl_interface
> *interface,
> + uint32_t version)
> {
> struct wl_proxy *proxy;
> struct wl_display *display = factory->display;
> @@ -211,6 +213,7 @@ proxy_create(struct wl_proxy *factory, const struct
> wl_interface *interface)
> proxy->queue = factory->queue;
> proxy->flags = 0;
> proxy->refcount = 1;
> + proxy->version = version;
>
> proxy->object.id = wl_map_insert_new(&display->objects, 0, proxy);
>
> @@ -243,7 +246,7 @@ wl_proxy_create(struct wl_proxy *factory, const struct
> wl_interface *interface)
> struct wl_proxy *proxy;
>
> pthread_mutex_lock(&display->mutex);
> - proxy = proxy_create(factory, interface);
> + proxy = proxy_create(factory, interface, factory->version);
> pthread_mutex_unlock(&display->mutex);
>
> return proxy;
> @@ -269,6 +272,7 @@ wl_proxy_create_for_id(struct wl_proxy *factory,
> proxy->queue = factory->queue;
> proxy->flags = 0;
> proxy->refcount = 1;
> + proxy->version = factory->version;
>
> wl_map_insert_at(&display->objects, 0, id, proxy);
>
> @@ -396,7 +400,7 @@ wl_proxy_add_dispatcher(struct wl_proxy *proxy,
> static struct wl_proxy *
> create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message
> *message,
> union wl_argument *args,
> - const struct wl_interface *interface)
> + const struct wl_interface *interface, uint32_t
> version)
> {
> int i, count;
> const char *signature;
> @@ -410,7 +414,7 @@ create_outgoing_proxy(struct wl_proxy *proxy, const
> struct wl_message *message,
>
> switch (arg.type) {
> case 'n':
> - new_proxy = proxy_create(proxy, interface);
> + new_proxy = proxy_create(proxy, interface,
> version);
> if (new_proxy == NULL)
> return NULL;
>
> @@ -435,7 +439,8 @@ create_outgoing_proxy(struct wl_proxy *proxy, const
> struct wl_message *message,
> *
> * For new-id arguments, this function will allocate a new wl_proxy
> * and send the ID to the server. The new wl_proxy will be returned
> - * on success or NULL on errror with errno set accordingly.
> + * on success or NULL on errror with errno set accordingly. The newly
> + * created proxy will inherit their version from their parent.
> *
> * \note This is intended to be used by language bindings and not in
> * non-generated code.
> @@ -449,6 +454,43 @@ wl_proxy_marshal_array_constructor(struct wl_proxy
> *proxy,
> uint32_t opcode, union wl_argument
> *args,
> const struct wl_interface *interface)
> {
> + return wl_proxy_marshal_array_constructor_versioned(proxy, opcode,
> + args,
> interface,
> +
> proxy->version);
> +}
> +
> +
> +/** Prepare a request to be sent to the compositor
> + *
> + * \param proxy The proxy object
> + * \param opcode Opcode of the request to be sent
> + * \param args Extra arguments for the given request
> + * \param interface The interface to use for the new proxy
> + * \param version The protocol object version for the new proxy
> + *
> + * Translates the request given by opcode and the extra arguments into the
> + * wire format and write it to the connection buffer. This version takes
> an
> + * array of the union type wl_argument.
> + *
> + * For new-id arguments, this function will allocate a new wl_proxy
> + * and send the ID to the server. The new wl_proxy will be returned
> + * on success or NULL on errror with errno set accordingly. The newly
> + * created proxy will have the version specified.
> + *
> + * \note This is intended to be used by language bindings and not in
> + * non-generated code.
> + *
> + * \sa wl_proxy_marshal()
> + *
> + * \memberof wl_proxy
> + */
> +WL_EXPORT struct wl_proxy *
> +wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,
> + uint32_t opcode,
> + union wl_argument *args,
> + const struct wl_interface
> *interface,
> + uint32_t version)
> +{
> struct wl_closure *closure;
> struct wl_proxy *new_proxy = NULL;
> const struct wl_message *message;
> @@ -458,7 +500,8 @@ wl_proxy_marshal_array_constructor(struct wl_proxy
> *proxy,
> message = &proxy->object.interface->methods[opcode];
> if (interface) {
> new_proxy = create_outgoing_proxy(proxy, message,
> - args, interface);
> + args, interface,
> + version);
> if (new_proxy == NULL)
> goto err_unlock;
> }
> @@ -528,7 +571,8 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t
> opcode, ...)
> *
> * For new-id arguments, this function will allocate a new wl_proxy
> * and send the ID to the server. The new wl_proxy will be returned
> - * on success or NULL on errror with errno set accordingly.
> + * on success or NULL on errror with errno set accordingly. The newly
> + * created proxy will inherit their version from their parent.
> *
> * \note This should not normally be used by non-generated code.
> *
> @@ -550,6 +594,46 @@ wl_proxy_marshal_constructor(struct wl_proxy *proxy,
> uint32_t opcode,
> args, interface);
> }
>
> +
> +/** Prepare a request to be sent to the compositor
> + *
> + * \param proxy The proxy object
> + * \param opcode Opcode of the request to be sent
> + * \param interface The interface to use for the new proxy
> + * \param version The protocol object version of the new proxy
> + * \param ... Extra arguments for the given request
> + * \return A new wl_proxy for the new_id argument or NULL on error
> + *
> + * Translates the request given by opcode and the extra arguments into the
> + * wire format and write it to the connection buffer.
> + *
> + * For new-id arguments, this function will allocate a new wl_proxy
> + * and send the ID to the server. The new wl_proxy will be returned
> + * on success or NULL on errror with errno set accordingly. The newly
> + * created proxy will have the version specified.
> + *
> + * \note This should not normally be used by non-generated code.
> + *
> + * \memberof wl_proxy
> + */
> +WL_EXPORT struct wl_proxy *
> +wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy, uint32_t
> opcode,
> + const struct wl_interface
> *interface,
> + uint32_t version, ...)
> +{
> + union wl_argument args[WL_CLOSURE_MAX_ARGS];
> + va_list ap;
> +
> + va_start(ap, version);
> +
> wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature,
> + args, WL_CLOSURE_MAX_ARGS, ap);
> + va_end(ap);
> +
> + return wl_proxy_marshal_array_constructor_versioned(proxy, opcode,
> + args,
> interface,
> + version);
> +}
> +
> /** Prepare a request to be sent to the compositor
> *
> * \param proxy The proxy object
> @@ -730,6 +814,7 @@ wl_display_connect_to_fd(int fd)
> display->proxy.queue = &display->default_queue;
> display->proxy.flags = 0;
> display->proxy.refcount = 1;
> + display->proxy.version = 1;
>
> display->connection = wl_connection_create(display->fd);
> if (display->connection == NULL)
> @@ -1556,6 +1641,19 @@ wl_proxy_get_user_data(struct wl_proxy *proxy)
> return proxy->user_data;
> }
>
> +/** Get the protocol object version of a proxy object
> + *
> + * \param proxy The proxy object
> + * \return The protocol object version of the proxy
> + *
> + * \memberof wl_proxy
> + */
> +WL_EXPORT uint32_t
> +wl_proxy_get_version(struct wl_proxy *proxy)
> +{
> + return proxy->version;
> +}
> +
> /** Get the id of a proxy object
> *
> * \param proxy The proxy object
> diff --git a/src/wayland-client.h b/src/wayland-client.h
> index 2a32785..c47b8bf 100644
> --- a/src/wayland-client.h
> +++ b/src/wayland-client.h
> @@ -130,10 +130,22 @@ struct wl_proxy *wl_proxy_marshal_constructor(struct
> wl_proxy *proxy,
> uint32_t opcode,
> const struct wl_interface
> *interface,
> ...);
> +
> +struct wl_proxy *wl_proxy_marshal_constructor_versioned(struct wl_proxy
> *proxy,
> + uint32_t opcode,
> + const struct
> wl_interface *interface,
> + uint32_t version,
> + ...);
> struct wl_proxy *
> wl_proxy_marshal_array_constructor(struct wl_proxy *proxy,
> uint32_t opcode, union wl_argument
> *args,
> const struct wl_interface *interface);
> +struct wl_proxy *
> +wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,
> + uint32_t opcode,
> + union wl_argument *args,
> + const struct wl_interface
> *interface,
> + uint32_t version);
>
> void wl_proxy_destroy(struct wl_proxy *proxy);
> int wl_proxy_add_listener(struct wl_proxy *proxy,
> @@ -144,6 +156,7 @@ int wl_proxy_add_dispatcher(struct wl_proxy *proxy,
> const void * dispatcher_data, void *data);
> void wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data);
> void *wl_proxy_get_user_data(struct wl_proxy *proxy);
> +uint32_t wl_proxy_get_version(struct wl_proxy *proxy);
> uint32_t wl_proxy_get_id(struct wl_proxy *proxy);
> const char *wl_proxy_get_class(struct wl_proxy *proxy);
> void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue
> *queue);
> --
> 1.9.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20140402/787d451d/attachment-0001.html>
More information about the wayland-devel
mailing list