This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch feat/e-wl-proxy-planb
in repository enlightenment.

View the commit online.

commit 00105836d314203774e4794bd15fa31d7838c445
Author: [email protected] <[email protected]>
AuthorDate: Sat Jun 13 11:32:11 2026 -0600

    feat(e_wl_proxy): Wayland wire-protocol parser and interface registry
    
    Introduce the parsing foundation for e_wl_proxy, a proxy that sits between
    Wayland clients and the Enlightenment compositor so clients can survive a
    compositor crash. To rebuild a client's state after a restart the proxy must
    understand the bytes it forwards, so this adds:
    
    - a wire-message header/argument walker driven by libwayland interface
      signatures (e_wl_proxy_wire), with strict bounds checks on every
      length-prefixed field so malformed or hostile input cannot over-read;
    - an interface registry mapping interface names to the libwayland metadata
      the walker needs (e_wl_proxy_protocol);
    - a dense object-id -> node map keyed on the client/server id ranges
      (e_wl_proxy_objmap).
    
    These are pure, side-effect-free building blocks with no transport or policy;
    later layers build the shadow tree and translation on top of them.
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
 src/bin/e_wl_proxy/e_wl_proxy.h          | 138 +++++++++++++++++++++++++++++++
 src/bin/e_wl_proxy/e_wl_proxy_objmap.c   | 110 ++++++++++++++++++++++++
 src/bin/e_wl_proxy/e_wl_proxy_objmap.h   |  23 ++++++
 src/bin/e_wl_proxy/e_wl_proxy_protocol.c |  51 ++++++++++++
 src/bin/e_wl_proxy/e_wl_proxy_protocol.h |  13 +++
 src/bin/e_wl_proxy/e_wl_proxy_wire.c     |  99 ++++++++++++++++++++++
 src/bin/e_wl_proxy/e_wl_proxy_wire.h     |  38 +++++++++
 7 files changed, 472 insertions(+)

diff --git a/src/bin/e_wl_proxy/e_wl_proxy.h b/src/bin/e_wl_proxy/e_wl_proxy.h
new file mode 100644
index 000000000..19223def4
--- /dev/null
+++ b/src/bin/e_wl_proxy/e_wl_proxy.h
@@ -0,0 +1,138 @@
+#ifndef E_WL_PROXY_H
+#define E_WL_PROXY_H
+
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+/* Diagnostic log file ($XDG_RUNTIME_DIR/e_wl_proxy.log), opened in main(). The
+ * proxy's stderr is unreliable (enlightenment_start redirects it), so recovery
+ * tracing goes here. NULL until opened; callers fall back to stderr. */
+extern FILE *e_wl_proxy_logf;
+
+/* Matches libwayland MAX_FDS_OUT; the most fds one flush carries. We size the
+ * recvmsg control buffer generously above this to tolerate batched reads. */
+#define E_WL_PROXY_MAX_FDS  64
+#define E_WL_PROXY_BUF_SIZE 4096
+
+/* reserved high client id for the replay sync barrier (real clients allocate
+ * densely from 2 and never approach this) */
+#define E_WL_PROXY_REPLAY_SYNC_ID 0xfeff0000u
+
+/* ---- socket helpers (e_wl_proxy_socket.c) ---- */
+
+/* Build "$XDG_RUNTIME_DIR/<name>" into buf. Returns 0 on success, -1 if the
+ * name is invalid or the path would not fit. */
+int e_wl_proxy_socket_path(const char *name, char *buf, size_t buflen);
+
+/* Create, bind and listen a unix socket named <name> under XDG_RUNTIME_DIR,
+ * taking a <name>.lock first and unlinking a stale socket. Returns the
+ * listening fd (non-blocking, CLOEXEC) or -1. */
+int e_wl_proxy_listen(const char *name);
+
+/* Connect to the unix socket named <name> under XDG_RUNTIME_DIR. Returns a
+ * connected fd (non-blocking, CLOEXEC) or -1. */
+int e_wl_proxy_connect(const char *name);
+
+/* ---- forwarder (e_wl_proxy_pipe.c) ---- */
+
+/* One direction's output buffer. fds are only held when a send could not place
+ * any bytes yet; once any byte of a read is sent its fds have been delivered. */
+typedef struct _E_Wl_Proxy_Pipe
+{
+   char buf[E_WL_PROXY_BUF_SIZE];
+   int  len;                       /* pending bytes in buf */
+   int  off;                       /* bytes already flushed from buf */
+   int  fds[E_WL_PROXY_MAX_FDS];
+   int  nfds;                      /* pending fds (only when off == 0) */
+} E_Wl_Proxy_Pipe;
+
+/* Flush any pending bytes/fds in pipe to fd `to`. Returns 0 if fully drained,
+ * 1 if bytes remain (EAGAIN), -1 on error. */
+int e_wl_proxy_pipe_flush(int to, E_Wl_Proxy_Pipe *pipe);
+
+/* Read one chunk from `from` and forward it to `to`, buffering any unsent
+ * remainder in pipe. Returns: >0 bytes read, 0 nothing available (EAGAIN),
+ * -1 the READ side (`from`) hit EOF/error, -2 the WRITE side (`to`) failed.
+ * The split lets the caller react per direction: on the client->backend path a
+ * -2 means the backend (E) died (freeze the client) while -1 means the client
+ * closed (tear down); on backend->client it is the mirror. pipe must be empty
+ * (len == 0) on entry — call e_wl_proxy_pipe_flush() first if it is not.
+ *
+ * If out_fds is non-NULL, a dup() of each fd that arrived with this chunk is
+ * written to out_fds[0..*out_nfds) (capacity E_WL_PROXY_MAX_FDS) and ownership
+ * of those dups passes to the caller (it must close or retain them). The
+ * forwarded originals are owned by the transport and closed once delivered.
+ * Pass out_fds = NULL when the direction does not retain fds. */
+ssize_t e_wl_proxy_forward(int from, int to, E_Wl_Proxy_Pipe *pipe,
+                           int *out_fds, int *out_nfds);
+
+/* ---- per-client connection (e_wl_proxy_conn.c) ---- */
+typedef struct _E_Wl_Proxy_Conn E_Wl_Proxy_Conn;
+
+/* Take an accepted client fd, connect upstream to <backend>, and start
+ * forwarding both ways. Returns NULL (and closes client_fd) on failure. */
+E_Wl_Proxy_Conn *e_wl_proxy_conn_add(int client_fd, const char *backend);
+void             e_wl_proxy_conn_del(E_Wl_Proxy_Conn *conn);
+
+/* ---- control protocol + WM-state blob store (e_wl_proxy_ctl.c) ---- */
+
+#include "../e_wl_proxy_proto.h"
+
+/* a parsed message; uuid/blob point into the caller's buffer (zero-copy). */
+typedef struct _E_Wl_Proxy_Ctl_Msg
+{
+   E_Wl_Proxy_Ctl_Type type;
+   const char         *uuid;
+   uint32_t            uuid_len;
+   const void         *blob;
+   uint32_t            blob_len;
+} E_Wl_Proxy_Ctl_Msg;
+
+/* Parse one frame from buf[0..len). On a complete frame: fills msg, sets
+ * *consumed to the frame size, returns 1. If more bytes are needed: returns 0.
+ * On a malformed frame (bad type or oversize lengths): returns -1. */
+int e_wl_proxy_ctl_parse(const void *buf, size_t len,
+                         E_Wl_Proxy_Ctl_Msg *msg, size_t *consumed);
+
+/* Serialize a frame into out[0..outcap). Returns the number of bytes written,
+ * or -1 if it would not fit. uuid/blob may be NULL when their len is 0. */
+ssize_t e_wl_proxy_ctl_serialize(E_Wl_Proxy_Ctl_Type type,
+                                 const char *uuid, uint32_t uuid_len,
+                                 const void *blob, uint32_t blob_len,
+                                 void *out, size_t outcap);
+
+/* ---- the uuid -> blob store ---- */
+typedef struct _E_Wl_Proxy_Store E_Wl_Proxy_Store;
+
+E_Wl_Proxy_Store *e_wl_proxy_store_new(void);
+void              e_wl_proxy_store_free(E_Wl_Proxy_Store *st);
+/* Copy len bytes of blob under uuid (uuid_len bytes), replacing any prior. */
+int               e_wl_proxy_store_put(E_Wl_Proxy_Store *st,
+                                       const char *uuid, uint32_t uuid_len,
+                                       const void *blob, uint32_t blob_len);
+void              e_wl_proxy_store_forget(E_Wl_Proxy_Store *st,
+                                          const char *uuid, uint32_t uuid_len);
+/* Look up; returns blob pointer and sets *len, or NULL if absent. */
+const void       *e_wl_proxy_store_get(E_Wl_Proxy_Store *st,
+                                       const char *uuid, uint32_t uuid_len,
+                                       uint32_t *len);
+unsigned int      e_wl_proxy_store_count(E_Wl_Proxy_Store *st);
+/* Call cb for every entry. uuid is NUL-terminated; blob/len are the stored bytes. */
+void              e_wl_proxy_store_foreach(E_Wl_Proxy_Store *st,
+                                           void (*cb)(const char *uuid,
+                                                      const void *blob,
+                                                      uint32_t len, void *data),
+                                           void *data);
+
+/* ---- control connection (e_wl_proxy_ctl_conn.c) ---- */
+typedef struct _E_Wl_Proxy_Ctl_Conn E_Wl_Proxy_Ctl_Conn;
+
+/* Take an accepted control-socket fd. The connection reads frames and applies
+ * them to the shared store `st` (WM_STATE upsert, WM_FORGET drop, HELLO -> dump
+ * all stored blobs back to the module). `st` is owned by the caller and shared
+ * across connections. Returns NULL (and closes fd) on failure. */
+E_Wl_Proxy_Ctl_Conn *e_wl_proxy_ctl_conn_add(int fd, E_Wl_Proxy_Store *st);
+void                 e_wl_proxy_ctl_conn_del(E_Wl_Proxy_Ctl_Conn *c);
+
+#endif
diff --git a/src/bin/e_wl_proxy/e_wl_proxy_objmap.c b/src/bin/e_wl_proxy/e_wl_proxy_objmap.c
new file mode 100644
index 000000000..5941129a5
--- /dev/null
+++ b/src/bin/e_wl_proxy/e_wl_proxy_objmap.c
@@ -0,0 +1,110 @@
+#include "config.h"
+#include "e_wl_proxy_objmap.h"
+#include <stdlib.h>
+
+/* Client-allocated ids start at 2 and grow densely; server ids start at
+ * 0xff000000. We index the client range directly and keep server ids in a
+ * second dense array offset from 0xff000000. */
+#define SERVER_ID_BASE 0xff000000u
+#define MAX_CLIENT_IDS 0x10000u    /* 64k objects per client is ample */
+#define MAX_SERVER_IDS 0x10000u
+
+struct _E_Wl_Proxy_Objmap
+{
+   void   **client;   /* index = id */
+   uint32_t client_cap;
+   void   **server;   /* index = id - SERVER_ID_BASE */
+   uint32_t server_cap;
+};
+
+E_Wl_Proxy_Objmap *
+e_wl_proxy_objmap_new(void)
+{
+   return calloc(1, sizeof(E_Wl_Proxy_Objmap));
+}
+
+static int
+_resolve(E_Wl_Proxy_Objmap *m, uint32_t id, void ****arr, uint32_t **cap, uint32_t *idx, uint32_t *max)
+{
+   if (id >= SERVER_ID_BASE)
+     {
+        *idx = id - SERVER_ID_BASE;
+        if (*idx >= MAX_SERVER_IDS) return -1;
+        *arr = &m->server; *cap = &m->server_cap; *max = MAX_SERVER_IDS;
+     }
+   else
+     {
+        *idx = id;
+        if (*idx >= MAX_CLIENT_IDS) return -1;
+        *arr = &m->client; *cap = &m->client_cap; *max = MAX_CLIENT_IDS;
+     }
+   return 0;
+}
+
+static int
+_ensure(void ***arr, uint32_t *cap, uint32_t idx, uint32_t max)
+{
+   uint32_t ncap, i;
+   void **n;
+   if (idx < *cap) return 0;
+   ncap = *cap ? *cap * 2 : 16;
+   while (ncap <= idx) ncap *= 2;
+   if (ncap > max) ncap = max;
+   n = realloc(*arr, ncap * sizeof(void *));
+   if (!n) return -1;
+   for (i = *cap; i < ncap; i++) n[i] = NULL;
+   *arr = n; *cap = ncap;
+   return 0;
+}
+
+void *
+e_wl_proxy_objmap_get(E_Wl_Proxy_Objmap *m, uint32_t id)
+{
+   void ***arr; uint32_t *cap, idx, max;
+   if (!m || _resolve(m, id, &arr, &cap, &idx, &max) < 0) return NULL;
+   if (idx >= *cap) return NULL;
+   return (*arr)[idx];
+}
+
+int
+e_wl_proxy_objmap_set(E_Wl_Proxy_Objmap *m, uint32_t id, void *node)
+{
+   void ***arr; uint32_t *cap, idx, max;
+   if (!m || _resolve(m, id, &arr, &cap, &idx, &max) < 0) return -1;
+   if (_ensure(arr, cap, idx, max) < 0) return -1;
+   (*arr)[idx] = node;
+   return 0;
+}
+
+void
+e_wl_proxy_objmap_del(E_Wl_Proxy_Objmap *m, uint32_t id)
+{
+   void ***arr; uint32_t *cap, idx, max;
+   if (!m || _resolve(m, id, &arr, &cap, &idx, &max) < 0) return;
+   if (idx < *cap) (*arr)[idx] = NULL;
+}
+
+void
+e_wl_proxy_objmap_free(E_Wl_Proxy_Objmap *m, void (*free_cb)(void *))
+{
+   uint32_t i;
+   if (!m) return;
+   if (free_cb)
+     {
+        for (i = 0; i < m->client_cap; i++) if (m->client[i]) free_cb(m->client[i]);
+        for (i = 0; i < m->server_cap; i++) if (m->server[i]) free_cb(m->server[i]);
+     }
+   free(m->client); free(m->server); free(m);
+}
+
+void
+e_wl_proxy_objmap_foreach(E_Wl_Proxy_Objmap *m,
+                          void (*cb)(uint32_t, void *, void *), void *data)
+{
+   uint32_t i;
+   if (!m || !cb) return;
+   for (i = 0; i < m->client_cap; i++)
+     if (m->client[i]) cb(i, m->client[i], data);
+   for (i = 0; i < m->server_cap; i++)
+     if (m->server[i]) cb(SERVER_ID_BASE + i, m->server[i], data);
+}
diff --git a/src/bin/e_wl_proxy/e_wl_proxy_objmap.h b/src/bin/e_wl_proxy/e_wl_proxy_objmap.h
new file mode 100644
index 000000000..ca24076f8
--- /dev/null
+++ b/src/bin/e_wl_proxy/e_wl_proxy_objmap.h
@@ -0,0 +1,23 @@
+#ifndef E_WL_PROXY_OBJMAP_H
+#define E_WL_PROXY_OBJMAP_H
+
+#include <stdint.h>
+
+typedef struct _E_Wl_Proxy_Objmap E_Wl_Proxy_Objmap;
+
+E_Wl_Proxy_Objmap *e_wl_proxy_objmap_new(void);
+/* free the map; calls free_cb(node) for each non-NULL entry if free_cb != NULL */
+void e_wl_proxy_objmap_free(E_Wl_Proxy_Objmap *m, void (*free_cb)(void *node));
+
+void *e_wl_proxy_objmap_get(E_Wl_Proxy_Objmap *m, uint32_t id);
+/* store node at id (grows as needed). Returns 0 on success, -1 on OOM/bad id. */
+int   e_wl_proxy_objmap_set(E_Wl_Proxy_Objmap *m, uint32_t id, void *node);
+void  e_wl_proxy_objmap_del(E_Wl_Proxy_Objmap *m, uint32_t id);  /* sets entry to NULL */
+
+/* Call cb(id, node, data) for every live (non-NULL) entry, in ascending id
+ * order within each bank (client ids first, then server ids). */
+void e_wl_proxy_objmap_foreach(E_Wl_Proxy_Objmap *m,
+                               void (*cb)(uint32_t id, void *node, void *data),
+                               void *data);
+
+#endif
diff --git a/src/bin/e_wl_proxy/e_wl_proxy_protocol.c b/src/bin/e_wl_proxy/e_wl_proxy_protocol.c
new file mode 100644
index 000000000..13e230e1b
--- /dev/null
+++ b/src/bin/e_wl_proxy/e_wl_proxy_protocol.c
@@ -0,0 +1,51 @@
+#include "config.h"
+#include "e_wl_proxy_protocol.h"
+#include <string.h>
+#include <wayland-client-protocol.h>   /* declares wl_*_interface externs */
+#include "xdg-shell-client-protocol.h"
+#include "xdg-foreign-unstable-v1-client-protocol.h"
+#include "relative-pointer-unstable-v1-client-protocol.h"
+#include "pointer-constraints-unstable-v1-client-protocol.h"
+#include "linux-dmabuf-unstable-v1-client-protocol.h"
+#include "session-recovery-client-protocol.h"
+#include "action_route-client-protocol.h"
+#include "efl-aux-hints-client-protocol.h"
+
+static const struct wl_interface *_ifaces[] = {
+   &wl_display_interface, &wl_registry_interface, &wl_callback_interface,
+   &wl_compositor_interface, &wl_shm_pool_interface, &wl_shm_interface,
+   &wl_buffer_interface, &wl_data_offer_interface, &wl_data_source_interface,
+   &wl_data_device_interface, &wl_data_device_manager_interface,
+   &wl_surface_interface, &wl_seat_interface, &wl_pointer_interface,
+   &wl_keyboard_interface, &wl_touch_interface, &wl_output_interface,
+   &wl_region_interface, &wl_subcompositor_interface, &wl_subsurface_interface,
+   &xdg_wm_base_interface, &xdg_positioner_interface, &xdg_surface_interface,
+   &xdg_toplevel_interface, &xdg_popup_interface,
+   &zxdg_exporter_v1_interface, &zxdg_exported_v1_interface,
+   &zxdg_importer_v1_interface, &zxdg_imported_v1_interface,
+   &zwp_relative_pointer_manager_v1_interface, &zwp_relative_pointer_v1_interface,
+   &zwp_pointer_constraints_v1_interface, &zwp_locked_pointer_v1_interface,
+   &zwp_confined_pointer_v1_interface,
+   &zwp_linux_dmabuf_v1_interface, &zwp_linux_buffer_params_v1_interface,
+   &zwp_linux_dmabuf_feedback_v1_interface,
+   &zwp_e_session_recovery_interface,
+   &action_route_interface, &action_route_bind_interface,
+   &action_route_key_grab_interface,
+   &efl_aux_hints_interface,
+};
+
+const struct wl_interface *
+e_wl_proxy_iface_by_name(const char *name)
+{
+   unsigned int i;
+   if (!name) return NULL;
+   for (i = 0; i < sizeof(_ifaces) / sizeof(_ifaces[0]); i++)
+     if (!strcmp(_ifaces[i]->name, name)) return _ifaces[i];
+   return NULL;
+}
+
+const struct wl_interface *
+e_wl_proxy_iface_display(void)
+{
+   return &wl_display_interface;
+}
diff --git a/src/bin/e_wl_proxy/e_wl_proxy_protocol.h b/src/bin/e_wl_proxy/e_wl_proxy_protocol.h
new file mode 100644
index 000000000..4079e470a
--- /dev/null
+++ b/src/bin/e_wl_proxy/e_wl_proxy_protocol.h
@@ -0,0 +1,13 @@
+#ifndef E_WL_PROXY_PROTOCOL_H
+#define E_WL_PROXY_PROTOCOL_H
+
+#include <wayland-util.h>   /* struct wl_interface, struct wl_message */
+
+/* Look up a core/extension interface by its protocol name (e.g. "wl_surface").
+ * Returns NULL if unknown. */
+const struct wl_interface *e_wl_proxy_iface_by_name(const char *name);
+
+/* The wl_display interface — object id 1 on every connection. */
+const struct wl_interface *e_wl_proxy_iface_display(void);
+
+#endif
diff --git a/src/bin/e_wl_proxy/e_wl_proxy_wire.c b/src/bin/e_wl_proxy/e_wl_proxy_wire.c
new file mode 100644
index 000000000..76d3c8eff
--- /dev/null
+++ b/src/bin/e_wl_proxy/e_wl_proxy_wire.c
@@ -0,0 +1,99 @@
+#include "config.h"
+#include "e_wl_proxy_wire.h"
+#include <string.h>
+
+int
+e_wl_proxy_wire_hdr(const void *buf, size_t len, E_Wl_Proxy_Hdr *hdr)
+{
+   uint32_t w[2];
+   if (len < 8) return 0;
+   memcpy(w, buf, 8);
+   hdr->object_id = w[0];
+   hdr->opcode = (uint16_t)(w[1] & 0xffff);
+   hdr->size = (uint16_t)(w[1] >> 16);
+   return 1;
+}
+
+/* round n up to a 4-byte boundary */
+static inline size_t _pad4(size_t n) { return (n + 3) & ~((size_t)3); }
+
+int
+e_wl_proxy_wire_args(const struct wl_message *msg, const void *body,
+                     size_t body_len, E_Wl_Proxy_Args *out)
+{
+   const char *sig = msg->signature;
+   const unsigned char *p = body;
+   const unsigned char *last_str = NULL;   /* most recent 's' arg (bind iface) */
+   uint32_t last_str_len = 0;
+   size_t off = 0;
+   int arg = 0;
+   const char *c;
+
+   memset(out, 0, sizeof(*out));
+
+   for (c = sig; *c; c++)
+     {
+        if (*c >= '0' && *c <= '9') continue;   /* since-version digits */
+        if (*c == '?') continue;                /* nullable marker */
+
+        switch (*c)
+          {
+           case 'i': case 'u': case 'f':
+             if (off + 4 > body_len) return -1;
+             off += 4;
+             break;
+           case 'o':
+             if (off + 4 > body_len) return -1;
+             if (out->n_obj_refs < 8)
+               {
+                  uint32_t oid;
+                  memcpy(&oid, p + off, 4);   /* body is char*: avoid unaligned load */
+                  if (oid) out->obj_refs[out->n_obj_refs++] = oid;
+               }
+             off += 4;
+             break;
+           case 'n':
+             if (off + 4 > body_len) return -1;
+             memcpy(&out->new_id, p + off, 4);
+             off += 4;
+             if (msg->types[arg] != NULL)
+               out->new_iface = msg->types[arg];   /* typed new_id */
+             else
+               {
+                  /* generic new_id: the signature is expanded (e.g. bind
+                   * "usun"), so the interface is the preceding 's' arg and the
+                   * 4 bytes just read are the id. */
+                  out->has_generic_new_id = 1;
+                  if (last_str && last_str_len > 0)
+                    {
+                       size_t copy = last_str_len - 1; /* drop trailing NUL */
+                       if (copy >= sizeof(out->new_iface_name)) copy = sizeof(out->new_iface_name) - 1;
+                       memcpy(out->new_iface_name, last_str, copy);
+                       out->new_iface_name[copy] = '\0';
+                    }
+               }
+             arg++;
+             continue;
+           case 's': case 'a':
+             {
+                uint32_t alen;
+                if (off + 4 > body_len) return -1;
+                memcpy(&alen, p + off, 4); off += 4;
+                /* check alen alone first (off <= body_len here) so _pad4 can't
+                 * overflow size_t and slip past the bounds check on 32-bit. */
+                if (alen > body_len - off) return -1;
+                if (off + _pad4(alen) > body_len) return -1;
+                if (*c == 's') { last_str = p + off; last_str_len = alen; }
+                off += _pad4(alen);
+             }
+             break;
+           case 'h':
+             out->fd_count++;   /* fd is out-of-band, no body bytes */
+             break;
+           default:
+             return -1;         /* unknown signature char */
+          }
+        arg++;
+     }
+   return 0;
+}
diff --git a/src/bin/e_wl_proxy/e_wl_proxy_wire.h b/src/bin/e_wl_proxy/e_wl_proxy_wire.h
new file mode 100644
index 000000000..a2c1a6188
--- /dev/null
+++ b/src/bin/e_wl_proxy/e_wl_proxy_wire.h
@@ -0,0 +1,38 @@
+#ifndef E_WL_PROXY_WIRE_H
+#define E_WL_PROXY_WIRE_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <wayland-util.h>
+
+typedef struct _E_Wl_Proxy_Hdr
+{
+   uint32_t object_id;
+   uint16_t opcode;
+   uint16_t size;        /* total message size incl. the 8-byte header */
+} E_Wl_Proxy_Hdr;
+
+/* Parse the 8-byte header from buf[0..len). Returns 1 if a full header is
+ * present (len >= 8) and fills hdr; 0 if fewer than 8 bytes. */
+int e_wl_proxy_wire_hdr(const void *buf, size_t len, E_Wl_Proxy_Hdr *hdr);
+
+typedef struct _E_Wl_Proxy_Args
+{
+   uint32_t                   new_id;      /* 0 if the message creates no object */
+   const struct wl_interface *new_iface;   /* interface of the new object, or NULL */
+   char                       new_iface_name[64]; /* for generic new_id (bind): the name */
+   int                        has_generic_new_id;  /* 1 if new_iface must be resolved by name */
+   int                        fd_count;    /* number of 'h' args (fds consumed) */
+   uint32_t                   obj_refs[8]; /* object ('o') arg ids referenced (capped) */
+   int                        n_obj_refs;
+} E_Wl_Proxy_Args;
+
+/* Walk the args of one message. `msg` is the wl_message (from the sender object's
+ * interface methods[opcode]); `body` points just past the 8-byte header; body_len
+ * is hdr.size - 8. Fills `out`. Returns 0 on success, -1 if the body is malformed
+ * (truncated arg). For a generic new_id, sets has_generic_new_id and copies the
+ * interface name into new_iface_name (caller resolves via the registry). */
+int e_wl_proxy_wire_args(const struct wl_message *msg, const void *body,
+                         size_t body_len, E_Wl_Proxy_Args *out);
+
+#endif

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to