[RFC libwayland] Track protocol object versions inside wl_proxy.
Jasper St. Pierre
jstpierre at mecheye.net
Wed Apr 2 07:51:14 PDT 2014
Does this help clean up client code? Can you give an example of how a
client would use this?
On Wed, Apr 2, 2014 at 10:48 AM, Jason Ekstrand <jason at jlekstrand.net>wrote:
> 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
>>
>>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
>
--
Jasper
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20140402/f3236621/attachment-0001.html>
More information about the wayland-devel
mailing list