[RFC libwayland] Track protocol object versions inside wl_proxy.
Jason Ekstrand
jason at jlekstrand.net
Wed Apr 2 08:04:52 PDT 2014
On Wed, Apr 2, 2014 at 9:51 AM, Jasper St. Pierre <jstpierre at mecheye.net>wrote:
> Does this help clean up client code? Can you give an example of how a
> client would use this?
>
Without this, the client has to track versions of everything if it's going
to do anything version-dependent with a protocol object. If it's just the
one client and no waylandy libraries, it's no big deal; you just record the
version number of each of the globals as you bind them. However, as soon
as you have a wayland-based library, you need a way to communicate
versions. Obviously, you could just build that into the library API, but
it's extra clutter and people are bound to leave things unversioned when
they pass them. This vastly simplifies the process because the version is
simply carried around with the proxy and clients don't have to do anything
to support it except rebuild.
As long as the client is built against a version of libwayland that
supports it (and has properly generated stubs), it's extremely simple. To
get the versions set correctly, do nothing. Then, when you need to do
something version-dependant:
if (wl_surface_get_version(surface) >= 3)
/* Do something */
else
/* Do something else */
In particular, there's a wl_surface.damage issue that we haven't sorted
out. In the solution that I think we're ultimately going to go with,
clients will have to submit damage differently based on the surface version
number.
I hope that makes it more clear.
--Jason Ekstrand
>
> 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/f6b5e14a/attachment-0001.html>
More information about the wayland-devel
mailing list