[RFC libwayland] Track protocol object versions inside wl_proxy.

Jason Ekstrand jason at jlekstrand.net
Tue Apr 1 22:28:22 PDT 2014


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



More information about the wayland-devel mailing list