This is an automated email from the git hooks/post-receive script.
git pushed a commit to reference refs/pull/135/head
in repository enlightenment.
View the commit online.
commit 14d50e7170d444c7b0654eefecf79b439b878ef0
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.