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 8f1a3244d8fafa6e46aba4e5ef0c45fb9297c669
Author: [email protected] <[email protected]>
AuthorDate: Sat Jun 13 11:40:50 2026 -0600

    feat(e_wl_proxy): stable per-toplevel session uuids
    
    Window position restore needs a stable identity for each toplevel that
    survives a compositor crash. Enlightenment already restores per-window state
    keyed on a session-recovery uuid, but that protocol mints a fresh uuid on each
    get_uuid, so it does not survive a restart. This adds the proxy-side support to
    mint a stable uuid per toplevel and drive Enlightenment's
    zwp_e_session_recovery.set_uuid on its behalf:
    
    - deterministic uuid generation from (pid, connection, sequence);
    - the set_uuid request / create_uuid event wire codec;
    - a per-connection table mapping surfaces and their xdg roles to uuids,
      tracking which toplevels still need a uuid injected.
    
    This is the data layer only; the connection state machine wires it into the
    live and recovery paths.
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
 src/bin/e_wl_proxy/e_wl_proxy_session.c | 200 ++++++++++++++++++++++++++++++++
 src/bin/e_wl_proxy/e_wl_proxy_session.h |  73 ++++++++++++
 2 files changed, 273 insertions(+)

diff --git a/src/bin/e_wl_proxy/e_wl_proxy_session.c b/src/bin/e_wl_proxy/e_wl_proxy_session.c
new file mode 100644
index 000000000..df798d7bc
--- /dev/null
+++ b/src/bin/e_wl_proxy/e_wl_proxy_session.c
@@ -0,0 +1,200 @@
+#include "config.h"
+#include "e_wl_proxy_session.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+static inline size_t _pad4(size_t n) { return (n + 3) & ~((size_t)3); }
+
+size_t
+e_wl_proxy_session_uuid(char *out, size_t cap, int pid, unsigned int conn_id,
+                        unsigned int seq)
+{
+   int n = snprintf(out, cap, "wlproxy-%08x-%08x-%08x",
+                    (unsigned)pid, conn_id, seq);
+   if (n <= 0 || (size_t)n >= cap) { if (cap) out[0] = '\0'; return 0; }
+   return (size_t)n;
+}
+
+size_t
+e_wl_proxy_session_build_set_uuid(unsigned char *buf, size_t cap,
+                                  uint32_t sr_id, uint32_t surface_id,
+                                  const char *uuid)
+{
+   size_t slen = uuid ? strlen(uuid) + 1 : 1;   /* include NUL */
+   size_t size = 8 + 4 + 4 + _pad4(slen);
+   uint32_t w;
+
+   if (!buf || size > cap || size > 0xffff) return 0;
+   memcpy(buf, &sr_id, 4);
+   w = ((uint32_t)size << 16) | 1u;             /* opcode 1 = set_uuid */
+   memcpy(buf + 4, &w, 4);
+   memcpy(buf + 8, &surface_id, 4);
+   w = (uint32_t)slen;
+   memcpy(buf + 12, &w, 4);
+   memset(buf + 16, 0, _pad4(slen));            /* zero pad (incl NUL) */
+   if (uuid) memcpy(buf + 16, uuid, slen - 1);
+   return size;
+}
+
+int
+e_wl_proxy_session_parse_create_uuid(const void *body, size_t body_len,
+                                     uint32_t *surface_id, char *uuid_out,
+                                     size_t uuid_cap)
+{
+   const unsigned char *p = body;
+   uint32_t surface, slen;
+
+   if (body_len < 8) return -1;                 /* surface(4) + strlen(4) */
+   memcpy(&surface, p, 4);
+   memcpy(&slen, p + 4, 4);
+   if (slen == 0 || (size_t)8 + slen > body_len) return -1;
+   if (slen > uuid_cap) return -1;
+   memcpy(uuid_out, p + 8, slen - 1);
+   uuid_out[slen - 1] = '\0';
+   if (surface_id) *surface_id = surface;
+   return 0;
+}
+
+/* ---- per-connection window-identity table ---- */
+
+typedef struct _Win
+{
+   uint32_t surface_id;
+   char     uuid[E_WL_PROXY_SESSION_UUID_MAX];
+   Eina_Bool is_toplevel;
+   Eina_Bool uuid_sent;
+} Win;
+
+struct _E_Wl_Proxy_Session
+{
+   int           pid;
+   unsigned int  conn_id;
+   unsigned int  seq;            /* uuid generation counter */
+   Eina_Hash    *wins;           /* surface_id -> Win* */
+   Eina_Hash    *xdg2surf;       /* xdg_surface_id -> surface_id (as uintptr) */
+};
+
+static Win *
+_win_ensure(E_Wl_Proxy_Session *s, uint32_t surface_id)
+{
+   Win *w = eina_hash_find(s->wins, &surface_id);
+   if (w) return w;
+   w = calloc(1, sizeof(*w));
+   if (!w) return NULL;
+   w->surface_id = surface_id;
+   eina_hash_add(s->wins, &surface_id, w);
+   return w;
+}
+
+E_Wl_Proxy_Session *
+e_wl_proxy_session_new(int pid, unsigned int conn_id)
+{
+   E_Wl_Proxy_Session *s = calloc(1, sizeof(*s));
+   if (!s) return NULL;
+   s->pid = pid; s->conn_id = conn_id;
+   s->wins = eina_hash_int32_new(free);
+   s->xdg2surf = eina_hash_int32_new(NULL);
+   if (!s->wins || !s->xdg2surf) { e_wl_proxy_session_free(s); return NULL; }
+   return s;
+}
+
+void
+e_wl_proxy_session_free(E_Wl_Proxy_Session *s)
+{
+   if (!s) return;
+   if (s->wins) eina_hash_free(s->wins);
+   if (s->xdg2surf) eina_hash_free(s->xdg2surf);
+   free(s);
+}
+
+void
+e_wl_proxy_session_link_xdg(E_Wl_Proxy_Session *s, uint32_t xdg_id, uint32_t surface_id)
+{
+   if (!s) return;
+   eina_hash_set(s->xdg2surf, &xdg_id, (void *)(uintptr_t)surface_id);
+}
+
+uint32_t
+e_wl_proxy_session_mark_toplevel(E_Wl_Proxy_Session *s, uint32_t xdg_id)
+{
+   uintptr_t sid;
+   Win *w;
+   if (!s) return 0;
+   sid = (uintptr_t)eina_hash_find(s->xdg2surf, &xdg_id);
+   if (!sid) return 0;
+   w = _win_ensure(s, (uint32_t)sid);
+   if (!w) return 0;
+   w->is_toplevel = EINA_TRUE;
+   if (w->uuid[0] == '\0')
+     e_wl_proxy_session_uuid(w->uuid, sizeof(w->uuid), s->pid, s->conn_id, s->seq++);
+   return (uint32_t)sid;
+}
+
+void
+e_wl_proxy_session_capture_uuid(E_Wl_Proxy_Session *s, uint32_t surface_id, const char *uuid)
+{
+   Win *w;
+   if (!s || !uuid) return;
+   w = _win_ensure(s, surface_id);
+   if (!w) return;
+   w->is_toplevel = EINA_TRUE;
+   snprintf(w->uuid, sizeof(w->uuid), "%s", uuid);
+   w->uuid_sent = EINA_TRUE;   /* client drove it; don't inject our own */
+}
+
+const char *
+e_wl_proxy_session_commit_needs_uuid(E_Wl_Proxy_Session *s, uint32_t surface_id)
+{
+   Win *w = s ? eina_hash_find(s->wins, &surface_id) : NULL;
+   if (!w || !w->is_toplevel || w->uuid_sent || w->uuid[0] == '\0') return NULL;
+   w->uuid_sent = EINA_TRUE;
+   return w->uuid;
+}
+
+void
+e_wl_proxy_session_drop_surface(E_Wl_Proxy_Session *s, uint32_t surface_id)
+{
+   if (s) eina_hash_del(s->wins, &surface_id, NULL);
+}
+
+void
+e_wl_proxy_session_drop_xdg(E_Wl_Proxy_Session *s, uint32_t xdg_id)
+{
+   if (s) eina_hash_del(s->xdg2surf, &xdg_id, NULL);
+}
+
+void
+e_wl_proxy_session_reset_sent(E_Wl_Proxy_Session *s)
+{
+   Eina_Iterator *it;
+   Win *w;
+   if (!s) return;
+   it = eina_hash_iterator_data_new(s->wins);
+   EINA_ITERATOR_FOREACH(it, w) w->uuid_sent = EINA_FALSE;
+   eina_iterator_free(it);
+}
+
+const char *
+e_wl_proxy_session_uuid_of(E_Wl_Proxy_Session *s, uint32_t surface_id)
+{
+   Win *w = s ? eina_hash_find(s->wins, &surface_id) : NULL;
+   return (w && w->uuid[0]) ? w->uuid : NULL;
+}
+
+typedef struct _TlCtx { void (*cb)(uint32_t, const char *, void *); void *data; } TlCtx;
+static Eina_Bool
+_tl_each(const Eina_Hash *h EINA_UNUSED, const void *key EINA_UNUSED, void *val, void *fdata)
+{
+   Win *w = val; TlCtx *c = fdata;
+   if (w->is_toplevel && w->uuid[0]) c->cb(w->surface_id, w->uuid, c->data);
+   return EINA_TRUE;
+}
+
+void
+e_wl_proxy_session_foreach_toplevel(E_Wl_Proxy_Session *s,
+        void (*cb)(uint32_t, const char *, void *), void *data)
+{
+   TlCtx c = { cb, data };
+   if (s && cb) eina_hash_foreach(s->wins, _tl_each, &c);
+}
diff --git a/src/bin/e_wl_proxy/e_wl_proxy_session.h b/src/bin/e_wl_proxy/e_wl_proxy_session.h
new file mode 100644
index 000000000..1bbb09e99
--- /dev/null
+++ b/src/bin/e_wl_proxy/e_wl_proxy_session.h
@@ -0,0 +1,73 @@
+#ifndef E_WL_PROXY_SESSION_H
+#define E_WL_PROXY_SESSION_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <Eina.h>
+
+/* The longest uuid string we store/transmit (E treats it as an opaque key).
+ * 37 = 36 chars + NUL, matching libuuid's unparse buffer. */
+#define E_WL_PROXY_SESSION_UUID_MAX 37
+
+/* ---- pure helpers (no state) ---- */
+
+/* Write a stable, unique window uuid into out[0..cap) as a NUL-terminated
+ * string. Unique per (pid, conn_id, seq); opaque to E. Returns the string
+ * length (excluding NUL), or 0 if cap is too small. */
+size_t e_wl_proxy_session_uuid(char *out, size_t cap,
+                               int pid, unsigned int conn_id, unsigned int seq);
+
+/* Build a zwp_e_session_recovery.set_uuid(surface, uuid) request (opcode 1) into
+ * buf[0..cap): header{sr_id, size, op=1} + surface(4) + string(uuid). Both ids
+ * are already in backend space. Returns the message length, or 0 if it would
+ * not fit. */
+size_t e_wl_proxy_session_build_set_uuid(unsigned char *buf, size_t cap,
+                                         uint32_t sr_id, uint32_t surface_id,
+                                         const char *uuid);
+
+/* Parse a zwp_e_session_recovery.create_uuid(surface, uuid) event BODY (the
+ * bytes after the 8-byte header). Writes the surface id to *surface_id and the
+ * uuid into uuid_out[0..uuid_cap). Returns 0 on success, -1 if malformed. */
+int e_wl_proxy_session_parse_create_uuid(const void *body, size_t body_len,
+                                         uint32_t *surface_id,
+                                         char *uuid_out, size_t uuid_cap);
+
+/* ---- per-connection window-identity table (client-space ids) ---- */
+typedef struct _E_Wl_Proxy_Session E_Wl_Proxy_Session;
+
+/* `pid`/`conn_id` seed the uuid generator; ids are client-space wl_surface ids. */
+E_Wl_Proxy_Session *e_wl_proxy_session_new(int pid, unsigned int conn_id);
+void                e_wl_proxy_session_free(E_Wl_Proxy_Session *s);
+
+/* get_xdg_surface(new_id xdg_surface, object wl_surface): record the link. */
+void e_wl_proxy_session_link_xdg(E_Wl_Proxy_Session *s, uint32_t xdg_id, uint32_t surface_id);
+
+/* get_toplevel on xdg_surface `xdg_id`: mark its wl_surface a toplevel and (if
+ * not already) generate its uuid. Returns the wl_surface id, or 0 if unknown. */
+uint32_t e_wl_proxy_session_mark_toplevel(E_Wl_Proxy_Session *s, uint32_t xdg_id);
+
+/* Record a client-driven uuid (captured from create_uuid) for a wl_surface, and
+ * mark it a toplevel. Marks it uuid_sent so the proxy won't inject its own. */
+void e_wl_proxy_session_capture_uuid(E_Wl_Proxy_Session *s, uint32_t surface_id,
+                                     const char *uuid);
+
+/* For a wl_surface that received a commit: if it is a toplevel whose uuid has
+ * not yet been sent to E, returns its uuid and marks it sent; else NULL. */
+const char *e_wl_proxy_session_commit_needs_uuid(E_Wl_Proxy_Session *s, uint32_t surface_id);
+
+/* Forget a destroyed wl_surface (or xdg_surface). No-op if absent. */
+void e_wl_proxy_session_drop_surface(E_Wl_Proxy_Session *s, uint32_t surface_id);
+void e_wl_proxy_session_drop_xdg(E_Wl_Proxy_Session *s, uint32_t xdg_id);
+
+/* Clear the "uuid_sent" flag on every toplevel (call at the start of a recovery
+ * so set_uuid is re-emitted to the fresh E). */
+void e_wl_proxy_session_reset_sent(E_Wl_Proxy_Session *s);
+
+/* Invoke cb(surface_id, uuid, data) for every toplevel with a uuid. */
+void e_wl_proxy_session_foreach_toplevel(E_Wl_Proxy_Session *s,
+        void (*cb)(uint32_t surface_id, const char *uuid, void *data), void *data);
+
+/* test/query: uuid of a wl_surface, or NULL. */
+const char *e_wl_proxy_session_uuid_of(E_Wl_Proxy_Session *s, uint32_t surface_id);
+
+#endif

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

Reply via email to