<p dir="ltr">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.</p>

<p dir="ltr">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.</p>

<p dir="ltr">That said, I'm open to other suggestions.<br>
--Jason Ekstrand</p>
<div class="gmail_quote">On Apr 2, 2014 12:28 AM, "Jason Ekstrand" <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
This provides a standardized mechanism for tracking protocol object<br>
versions in client code.  The wl_display object is created with version 1.<br>
Every time an object is created from within wl_registry_bind, it gets the<br>
bound version.  Every other time an object is created, it simply inherits<br>
it's version from the parent object that created it.<br>
<br>
<br>
---<br>
I've been meaning to scratch this itch for a while.  I've left it as an RFC<br>
for now because it builds, but I don't have any code to test it yet.  I've<br>
got something I'm hoping to hack on this weekend that will use it.  For<br>
now, feel free to comment.<br>
<br>
 src/scanner.c        |  29 +++++++++----<br>
 src/wayland-client.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++----<br>
 src/wayland-client.h |  13 ++++++<br>
 3 files changed, 139 insertions(+), 15 deletions(-)<br>
<br>
diff --git a/src/scanner.c b/src/scanner.c<br>
index e8bfc7c..43b3acf 100644<br>
--- a/src/scanner.c<br>
+++ b/src/scanner.c<br>
@@ -627,6 +627,14 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)<br>
               interface->name, interface->name, interface->name,<br>
               interface->name);<br>
<br>
+       printf("static inline uint32_t\n"<br>
+              "%s_get_version(struct %s *%s)\n"<br>
+              "{\n"<br>
+              "\treturn wl_proxy_get_version((struct wl_proxy *) %s);\n"<br>
+              "}\n\n",<br>
+              interface->name, interface->name, interface->name,<br>
+              interface->name);<br>
+<br>
        has_destructor = 0;<br>
        has_destroy = 0;<br>
        wl_list_for_each(m, message_list, link) {<br>
@@ -698,20 +706,25 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)<br>
<br>
                printf(")\n"<br>
                       "{\n");<br>
-               if (ret) {<br>
+               if (ret && ret->interface_name == NULL) {<br>
                        printf("\tstruct wl_proxy *%s;\n\n"<br>
-                              "\t%s = wl_proxy_marshal_constructor("<br>
+                              "\t%s = wl_proxy_marshal_constructor_versioned("<br>
                               "(struct wl_proxy *) %s,\n"<br>
-                              "\t\t\t %s_%s, ",<br>
+                              "\t\t\t %s_%s, interface, version",<br>
                               ret->name, ret->name,<br>
                               interface->name,<br>
                               interface->uppercase_name,<br>
                               m->uppercase_name);<br>
-<br>
-                       if (ret->interface_name == NULL)<br>
-                               printf("interface");<br>
-                       else<br>
-                               printf("&%s_interface", ret->interface_name);<br>
+               } else if (ret) {<br>
+                       printf("\tstruct wl_proxy *%s;\n\n"<br>
+                              "\t%s = wl_proxy_marshal_constructor("<br>
+                              "(struct wl_proxy *) %s,\n"<br>
+                              "\t\t\t %s_%s, &%s_interface",<br>
+                              ret->name, ret->name,<br>
+                              interface->name,<br>
+                              interface->uppercase_name,<br>
+                              m->uppercase_name,<br>
+                              ret->interface_name);<br>
                } else {<br>
                        printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"<br>
                               "\t\t\t %s_%s",<br>
diff --git a/src/wayland-client.c b/src/wayland-client.c<br>
index bd40313..5608564 100644<br>
--- a/src/wayland-client.c<br>
+++ b/src/wayland-client.c<br>
@@ -59,6 +59,7 @@ struct wl_proxy {<br>
        int refcount;<br>
        void *user_data;<br>
        wl_dispatcher_func_t dispatcher;<br>
+       uint32_t version;<br>
 };<br>
<br>
 struct wl_global {<br>
@@ -195,7 +196,8 @@ wl_display_create_queue(struct wl_display *display)<br>
 }<br>
<br>
 static struct wl_proxy *<br>
-proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)<br>
+proxy_create(struct wl_proxy *factory, const struct wl_interface *interface,<br>
+            uint32_t version)<br>
 {<br>
        struct wl_proxy *proxy;<br>
        struct wl_display *display = factory->display;<br>
@@ -211,6 +213,7 @@ proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)<br>
        proxy->queue = factory->queue;<br>
        proxy->flags = 0;<br>
        proxy->refcount = 1;<br>
+       proxy->version = version;<br>
<br>
        proxy-><a href="http://object.id" target="_blank">object.id</a> = wl_map_insert_new(&display->objects, 0, proxy);<br>
<br>
@@ -243,7 +246,7 @@ wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)<br>
        struct wl_proxy *proxy;<br>
<br>
        pthread_mutex_lock(&display->mutex);<br>
-       proxy = proxy_create(factory, interface);<br>
+       proxy = proxy_create(factory, interface, factory->version);<br>
        pthread_mutex_unlock(&display->mutex);<br>
<br>
        return proxy;<br>
@@ -269,6 +272,7 @@ wl_proxy_create_for_id(struct wl_proxy *factory,<br>
        proxy->queue = factory->queue;<br>
        proxy->flags = 0;<br>
        proxy->refcount = 1;<br>
+       proxy->version = factory->version;<br>
<br>
        wl_map_insert_at(&display->objects, 0, id, proxy);<br>
<br>
@@ -396,7 +400,7 @@ wl_proxy_add_dispatcher(struct wl_proxy *proxy,<br>
 static struct wl_proxy *<br>
 create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message,<br>
                      union wl_argument *args,<br>
-                     const struct wl_interface *interface)<br>
+                     const struct wl_interface *interface, uint32_t version)<br>
 {<br>
        int i, count;<br>
        const char *signature;<br>
@@ -410,7 +414,7 @@ create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message,<br>
<br>
                switch (arg.type) {<br>
                case 'n':<br>
-                       new_proxy = proxy_create(proxy, interface);<br>
+                       new_proxy = proxy_create(proxy, interface, version);<br>
                        if (new_proxy == NULL)<br>
                                return NULL;<br>
<br>
@@ -435,7 +439,8 @@ create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message,<br>
  *<br>
  * For new-id arguments, this function will allocate a new wl_proxy<br>
  * and send the ID to the server.  The new wl_proxy will be returned<br>
- * on success or NULL on errror with errno set accordingly.<br>
+ * on success or NULL on errror with errno set accordingly.  The newly<br>
+ * created proxy will inherit their version from their parent.<br>
  *<br>
  * \note This is intended to be used by language bindings and not in<br>
  * non-generated code.<br>
@@ -449,6 +454,43 @@ wl_proxy_marshal_array_constructor(struct wl_proxy *proxy,<br>
                                   uint32_t opcode, union wl_argument *args,<br>
                                   const struct wl_interface *interface)<br>
 {<br>
+       return wl_proxy_marshal_array_constructor_versioned(proxy, opcode,<br>
+                                                           args, interface,<br>
+                                                           proxy->version);<br>
+}<br>
+<br>
+<br>
+/** Prepare a request to be sent to the compositor<br>
+ *<br>
+ * \param proxy The proxy object<br>
+ * \param opcode Opcode of the request to be sent<br>
+ * \param args Extra arguments for the given request<br>
+ * \param interface The interface to use for the new proxy<br>
+ * \param version The protocol object version for the new proxy<br>
+ *<br>
+ * Translates the request given by opcode and the extra arguments into the<br>
+ * wire format and write it to the connection buffer.  This version takes an<br>
+ * array of the union type wl_argument.<br>
+ *<br>
+ * For new-id arguments, this function will allocate a new wl_proxy<br>
+ * and send the ID to the server.  The new wl_proxy will be returned<br>
+ * on success or NULL on errror with errno set accordingly.  The newly<br>
+ * created proxy will have the version specified.<br>
+ *<br>
+ * \note This is intended to be used by language bindings and not in<br>
+ * non-generated code.<br>
+ *<br>
+ * \sa wl_proxy_marshal()<br>
+ *<br>
+ * \memberof wl_proxy<br>
+ */<br>
+WL_EXPORT struct wl_proxy *<br>
+wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,<br>
+                                            uint32_t opcode,<br>
+                                            union wl_argument *args,<br>
+                                            const struct wl_interface *interface,<br>
+                                            uint32_t version)<br>
+{<br>
        struct wl_closure *closure;<br>
        struct wl_proxy *new_proxy = NULL;<br>
        const struct wl_message *message;<br>
@@ -458,7 +500,8 @@ wl_proxy_marshal_array_constructor(struct wl_proxy *proxy,<br>
        message = &proxy->object.interface->methods[opcode];<br>
        if (interface) {<br>
                new_proxy = create_outgoing_proxy(proxy, message,<br>
-                                                 args, interface);<br>
+                                                 args, interface,<br>
+                                                 version);<br>
                if (new_proxy == NULL)<br>
                        goto err_unlock;<br>
        }<br>
@@ -528,7 +571,8 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)<br>
  *<br>
  * For new-id arguments, this function will allocate a new wl_proxy<br>
  * and send the ID to the server.  The new wl_proxy will be returned<br>
- * on success or NULL on errror with errno set accordingly.<br>
+ * on success or NULL on errror with errno set accordingly.  The newly<br>
+ * created proxy will inherit their version from their parent.<br>
  *<br>
  * \note This should not normally be used by non-generated code.<br>
  *<br>
@@ -550,6 +594,46 @@ wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode,<br>
                                                  args, interface);<br>
 }<br>
<br>
+<br>
+/** Prepare a request to be sent to the compositor<br>
+ *<br>
+ * \param proxy The proxy object<br>
+ * \param opcode Opcode of the request to be sent<br>
+ * \param interface The interface to use for the new proxy<br>
+ * \param version The protocol object version of the new proxy<br>
+ * \param ... Extra arguments for the given request<br>
+ * \return A new wl_proxy for the new_id argument or NULL on error<br>
+ *<br>
+ * Translates the request given by opcode and the extra arguments into the<br>
+ * wire format and write it to the connection buffer.<br>
+ *<br>
+ * For new-id arguments, this function will allocate a new wl_proxy<br>
+ * and send the ID to the server.  The new wl_proxy will be returned<br>
+ * on success or NULL on errror with errno set accordingly.  The newly<br>
+ * created proxy will have the version specified.<br>
+ *<br>
+ * \note This should not normally be used by non-generated code.<br>
+ *<br>
+ * \memberof wl_proxy<br>
+ */<br>
+WL_EXPORT struct wl_proxy *<br>
+wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy, uint32_t opcode,<br>
+                                      const struct wl_interface *interface,<br>
+                                      uint32_t version, ...)<br>
+{<br>
+       union wl_argument args[WL_CLOSURE_MAX_ARGS];<br>
+       va_list ap;<br>
+<br>
+       va_start(ap, version);<br>
+       wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature,<br>
+                                args, WL_CLOSURE_MAX_ARGS, ap);<br>
+       va_end(ap);<br>
+<br>
+       return wl_proxy_marshal_array_constructor_versioned(proxy, opcode,<br>
+                                                           args, interface,<br>
+                                                           version);<br>
+}<br>
+<br>
 /** Prepare a request to be sent to the compositor<br>
  *<br>
  * \param proxy The proxy object<br>
@@ -730,6 +814,7 @@ wl_display_connect_to_fd(int fd)<br>
        display->proxy.queue = &display->default_queue;<br>
        display->proxy.flags = 0;<br>
        display->proxy.refcount = 1;<br>
+       display->proxy.version = 1;<br>
<br>
        display->connection = wl_connection_create(display->fd);<br>
        if (display->connection == NULL)<br>
@@ -1556,6 +1641,19 @@ wl_proxy_get_user_data(struct wl_proxy *proxy)<br>
        return proxy->user_data;<br>
 }<br>
<br>
+/** Get the protocol object version of a proxy object<br>
+ *<br>
+ * \param proxy The proxy object<br>
+ * \return The protocol object version of the proxy<br>
+ *<br>
+ * \memberof wl_proxy<br>
+ */<br>
+WL_EXPORT uint32_t<br>
+wl_proxy_get_version(struct wl_proxy *proxy)<br>
+{<br>
+       return proxy->version;<br>
+}<br>
+<br>
 /** Get the id of a proxy object<br>
  *<br>
  * \param proxy The proxy object<br>
diff --git a/src/wayland-client.h b/src/wayland-client.h<br>
index 2a32785..c47b8bf 100644<br>
--- a/src/wayland-client.h<br>
+++ b/src/wayland-client.h<br>
@@ -130,10 +130,22 @@ struct wl_proxy *wl_proxy_marshal_constructor(struct wl_proxy *proxy,<br>
                                              uint32_t opcode,<br>
                                              const struct wl_interface *interface,<br>
                                              ...);<br>
+<br>
+struct wl_proxy *wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy,<br>
+                                                       uint32_t opcode,<br>
+                                                       const struct wl_interface *interface,<br>
+                                                       uint32_t version,<br>
+                                                       ...);<br>
 struct wl_proxy *<br>
 wl_proxy_marshal_array_constructor(struct wl_proxy *proxy,<br>
                                   uint32_t opcode, union wl_argument *args,<br>
                                   const struct wl_interface *interface);<br>
+struct wl_proxy *<br>
+wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,<br>
+                                            uint32_t opcode,<br>
+                                            union wl_argument *args,<br>
+                                            const struct wl_interface *interface,<br>
+                                            uint32_t version);<br>
<br>
 void wl_proxy_destroy(struct wl_proxy *proxy);<br>
 int wl_proxy_add_listener(struct wl_proxy *proxy,<br>
@@ -144,6 +156,7 @@ int wl_proxy_add_dispatcher(struct wl_proxy *proxy,<br>
                            const void * dispatcher_data, void *data);<br>
 void wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data);<br>
 void *wl_proxy_get_user_data(struct wl_proxy *proxy);<br>
+uint32_t wl_proxy_get_version(struct wl_proxy *proxy);<br>
 uint32_t wl_proxy_get_id(struct wl_proxy *proxy);<br>
 const char *wl_proxy_get_class(struct wl_proxy *proxy);<br>
 void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue);<br>
--<br>
1.9.0<br>
<br>
</blockquote></div>