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