About fixing the untyped new_id issue
Jan Bruns
code at abnuto.de
Mon Sep 28 05:33:34 UTC 2020
Hallo.
Here's an untested wip/low quality patch that probably solves the new_id
issue of libwayland.
The problem:
The wayland-scanner tool generates code that reflects a protocol
different from the protocol XML defintion.
Wherever a protocol-XML describes argument-lists that contain objects of
unknown type to be created (args with type="new_id", but without
interface="..."), the scanner-tool adds additional arguments about
object type information (not only to the C API, but also to the
wire-protocol. For example, registry.bind() gets a "usun"-signature,
whereas the XML clearly defines a "un" signature).
This is presumably caused by the "fully managed"-style of the libwayland
C API, that hides things like object-id management from applications and
compositors, combined with the relativley unclear separation of
libwayland exports vs. libwayland C-header based API. And it also is a
very rare special case, so that fixing this issue must have been very
unattractive over the years. For the core protocol, there's only
registry.bind(), and most popular additional protocols are not affected
at all.
The suggested fix is to correct the scanner tool and the core protocol
xml in parallel. This way, the effective wire protocol doesn't depend on
wether or not the patch was applied, the C API remains the same (at
least for the mainstream protocol XMLs), and even the binary libwayland
.so files could remain unchanged for the changes to take effect (because
the point of change happens in header files included by
applications/compositors).
The single change to the core wayland.xml is for the registry interface
<request name="bind">
<arg name="name" type="uint" summary="unique numeric name of the
object"/>
<arg name="id" type="new_id" summary="bounded object"/>
</request>
which now reads
<request name="bind">
<arg name="name" type="uint" summary="unique numeric name of the
object"/>
<arg name="iface" type="string" interface="true"
summary="interface implemented by the object"/>
<arg name="version" type="uint" summary="interface version"/>
<arg name="id" type="new_id" summary="bounded object"/>
</request>
note that the 2nd arg of type string has a new interface="true"
attribute, hinting scanner-tools about where in the API to put the
non-wire information about proxy types to create. This tranlates from
static inline void *
wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const
struct wl_interface *interface, uint32_t version)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor_versioned((struct wl_proxy *)
wl_registry,
WL_REGISTRY_BIND, interface, version, name,
interface->name, version, NULL);
return (void *) id;
}
to
static inline void *
wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const
struct wl_interface *iface, uint32_t version)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor_versioned((struct wl_proxy *)
wl_registry,
WL_REGISTRY_BIND, iface, iface->version, name,
iface->name, version, NULL);
return (void *) id;
}
Since compiling C apps/compositors with header overrides diffrent from
sys-defaults isn't part of my personal workflow, I cannot even tell if
this patch really works. All I know about that is the wayland-1.18.0
makefiles still work with it, and generate libs that seem to work for
precompiled apps, but expect to see lots of C-related fine-tuning tasks
to still remain.
Gruss
Jan Bruns
diff -ru wayland-1.18.0/protocol/wayland.xml p3/protocol/wayland.xml
--- wayland-1.18.0/protocol/wayland.xml 2020-02-12 00:46:03.000000000
+0100
+++ p3/protocol/wayland.xml 2020-09-28 05:26:27.840960000 +0200
@@ -140,6 +140,8 @@
specified name as the identifier.
</description>
<arg name="name" type="uint" summary="unique numeric name of the
object"/>
+ <arg name="iface" type="string" interface="true"
summary="interface implemented by the object"/>
+ <arg name="version" type="uint" summary="interface version"/>
<arg name="id" type="new_id" summary="bounded object"/>
</request>
diff -ru wayland-1.18.0/src/scanner.c p3/src/scanner.c
--- wayland-1.18.0/src/scanner.c 2020-02-12 00:46:03.000000000 +0100
+++ p3/src/scanner.c 2020-09-28 06:16:41.972962000 +0200
@@ -816,6 +816,11 @@
arg->interface_name = xstrdup(interface_name);
}
break;
+ case STRING:
+ if (interface_name) {
+ arg->interface_name = xstrdup(interface_name);
+ };
+ break;
default:
if (interface_name != NULL)
fail(&ctx->loc, "interface attribute not allowed for
type %s", type);
@@ -1125,6 +1130,7 @@
struct message *m;
struct arg *a, *ret;
int has_destructor, has_destroy;
+ char * ifnam;
printf("/** @ingroup iface_%s */\n", interface->name);
printf("static inline void\n"
@@ -1216,15 +1222,23 @@
interface->name, m->name,
interface->name, interface->name);
+ ifnam = NULL;
wl_list_for_each(a, &m->arg_list, link) {
- if (a->type == NEW_ID && a->interface_name == NULL) {
- printf(", const struct wl_interface *interface"
- ", uint32_t version");
- continue;
- } else if (a->type == NEW_ID)
+// if (a->type == NEW_ID && a->interface_name == NULL) {
+// printf(", const struct wl_interface *interface"
+// ", uint32_t version");
+// continue;
+// } else
+ if (a->type == NEW_ID)
continue;
printf(", ");
- emit_type(a);
+ if ((a->type==STRING)&&(a->interface_name!=NULL))
+ {
+ printf("const struct wl_interface *");
+ ifnam=a->name;
+ } else {
+ emit_type(a);
+ }
printf("%s", a->name);
}
@@ -1233,14 +1247,23 @@
if (ret && ret->interface_name == NULL) {
/* an arg has type ="new_id" but interface is not
* provided, such as in wl_registry.bind */
+// printf("\tstruct wl_proxy *%s;\n\n"
+// "\t%s = wl_proxy_marshal_constructor_versioned("
+// "(struct wl_proxy *) %s,\n"
+// "\t\t\t %s_%s, interface, version",
+// ret->name, ret->name,
+// interface->name,
+// interface->uppercase_name,
+// m->uppercase_name);
printf("\tstruct wl_proxy *%s;\n\n"
"\t%s = wl_proxy_marshal_constructor_versioned("
"(struct wl_proxy *) %s,\n"
- "\t\t\t %s_%s, interface, version",
+ "\t\t\t %s_%s, %s, %s->version",
ret->name, ret->name,
interface->name,
interface->uppercase_name,
- m->uppercase_name);
+ m->uppercase_name,
+ ifnam,ifnam);
} else if (ret) {
/* Normal factory case, an arg has type="new_id" and
* an interface is provided */
@@ -1264,11 +1287,15 @@
wl_list_for_each(a, &m->arg_list, link) {
if (a->type == NEW_ID) {
- if (a->interface_name == NULL)
- printf(", interface->name, version");
+// if (a->interface_name == NULL)
+// printf(", interface->name, version");
printf(", NULL");
} else {
- printf(", %s", a->name);
+ if ((a->type==STRING)&&(a->interface_name!=NULL))
+ { printf(", %s->name", a->name);
+ } else {
+ printf(", %s", a->name);
+ }
}
}
printf(");\n");
@@ -1456,8 +1483,8 @@
if (side == SERVER && a->type == OBJECT)
printf("struct wl_resource *");
- else if (side == SERVER && a->type == NEW_ID &&
a->interface_name == NULL)
- printf("const char *interface, uint32_t version,
uint32_t ");
+// else if (side == SERVER && a->type == NEW_ID &&
a->interface_name == NULL)
+// printf("const char *interface, uint32_t version,
uint32_t ");
else if (side == CLIENT && a->type == OBJECT &&
a->interface_name == NULL)
printf("void *");
@@ -1761,8 +1788,8 @@
printf("i");
break;
case NEW_ID:
- if (a->interface_name == NULL)
- printf("su");
+ //if (a->interface_name == NULL)
+ // printf("su");
printf("n");
break;
case UNSIGNED:
diff -ru wayland-1.18.0/src/wayland-client.c p3/src/wayland-client.c
--- wayland-1.18.0/src/wayland-client.c 2020-02-12 00:46:03.000000000
+0100
+++ p3/src/wayland-client.c 2020-09-28 05:26:27.840960000 +0200
@@ -572,6 +572,33 @@
return 0;
}
+/** Set a proxy's interface and version
+ *
+ * \param proxy The proxy object
+ * \param interface The interface to set
+ * \param version The interface-version to set
+ * \return 0 on success or -1 or -2 on failure
+ *
+ * Set proxy's interface to \c interface in case
+ * it wasn't already set. To be used in application
+ * event handlers for untyped new_id args.
+ *
+ */
+WL_EXPORT int
+wl_proxy_set_interface(struct wl_proxy *proxy,
+ const struct wl_interface *interface, uint32_t version)
+{
+ if (proxy)
+ { if (proxy->object.interface)
+ return -2;
+ proxy->object.interface = interface;
+ proxy->version = version;
+ return 0;
+ };
+ return -1;
+}
+
+
/** Get a proxy's listener
*
* \param proxy The proxy object
diff -ru wayland-1.18.0/src/wayland-client-core.h
p3/src/wayland-client-core.h
--- wayland-1.18.0/src/wayland-client-core.h 2020-02-12
00:46:03.000000000 +0100
+++ p3/src/wayland-client-core.h 2020-09-28 05:26:27.840960000 +0200
@@ -171,6 +171,10 @@
wl_proxy_add_listener(struct wl_proxy *proxy,
void (**implementation)(void), void *data);
+int
+wl_proxy_set_interface(struct wl_proxy *proxy,
+ const struct wl_interface *interface, uint32_t version);
+
const void *
wl_proxy_get_listener(struct wl_proxy *proxy);
More information about the wayland-devel
mailing list