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" <[email protected]> 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 [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
