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 af15dc9002d42d016afcdc93a9cb6ea9af760da7
Author: [email protected] <[email protected]>
AuthorDate: Sat Jun 13 11:41:14 2026 -0600
feat(wl): run Enlightenment behind e_wl_proxy (opt-in via E_WL_PROXY=1)
Integrate the proxy into the Enlightenment startup path. With E_WL_PROXY=1,
enlightenment_start launches e_wl_proxy as a persistent sibling that owns the
public Wayland socket and outlives each Enlightenment restart, and points
Enlightenment at a private backend socket; it waits on a readiness pipe so
clients can connect the moment the session comes up.
Enlightenment then:
- creates its compositor on the private backend socket (E_WL_SOCKET) while
preserving the public WAYLAND_DISPLAY, so spawned clients reach the proxy and
not the backend directly;
- routes its own internal display and internal elm windows onto that same
direct backend connection so surface matching keeps working;
- auto-loads the wl_proxy companion module when running behind the proxy.
Without E_WL_PROXY the original behavior is unchanged.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
src/bin/e_comp_wl.c | 46 ++++++++++++++++++++++++++++++++---
src/bin/e_start_main.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/bin/e_win.c | 39 +++++++++++++++++++++++++++---
3 files changed, 144 insertions(+), 6 deletions(-)
diff --git a/src/bin/e_comp_wl.c b/src/bin/e_comp_wl.c
index 14427dafb..fcd0a2a36 100644
--- a/src/bin/e_comp_wl.c
+++ b/src/bin/e_comp_wl.c
@@ -159,6 +159,23 @@ _e_comp_wl_modules_load(void)
if (mod)
e_module_enable(mod);
}
+
+#ifdef USE_MODULE_WL_PROXY
+ /* The wl_proxy companion mirrors each window's WM-state (geometry, desktop,
+ * stacking, focus) to the e_wl_proxy proxy so it can be restored after a
+ * compositor crash. It is only useful when E runs behind the proxy, which
+ * exports E_WL_PROXY_SOCK (the control socket the module connects to). */
+ if (getenv("E_WL_PROXY_SOCK"))
+ {
+ E_Module *mod = e_module_find("wl_proxy");
+
+ if (!mod)
+ mod = e_module_new("wl_proxy");
+
+ if (mod)
+ e_module_enable(mod);
+ }
+#endif
}
static void
@@ -2792,15 +2809,32 @@ _e_comp_wl_compositor_create(void)
/* set wayland log handler */
/* wl_log_set_handler_server(_e_comp_wl_log_cb_print); */
- /* try to create an ecore_wl2 display */
- cdata->ewd = ecore_wl2_display_create(NULL);
+ /* try to create an ecore_wl2 display. When run behind e_wl_proxy,
+ * E_WL_SOCKET names the private backend socket the proxy connects to;
+ * otherwise NULL keeps the auto-named socket. ecore_wl2_display_create()
+ * overwrites WAYLAND_DISPLAY with the socket name it created, so capture
+ * the proxy's public name first and restore it afterwards — otherwise every
+ * client E spawns would connect straight to the backend, bypassing the
+ * proxy. */
+ const char *backend = getenv("E_WL_SOCKET");
+ char *public_disp = (backend && getenv("WAYLAND_DISPLAY")) ?
+ strdup(getenv("WAYLAND_DISPLAY")) : NULL;
+
+ cdata->ewd = ecore_wl2_display_create(backend);
if (!cdata->ewd)
{
ERR("Could not create a Wayland display");
+ free(public_disp);
free(cdata);
return EINA_FALSE;
}
+ if (public_disp)
+ {
+ e_env_set("WAYLAND_DISPLAY", public_disp);
+ free(public_disp);
+ }
+
cdata->wl.disp = ecore_wl2_display_get(cdata->ewd);
if (!cdata->wl.disp)
{
@@ -2855,7 +2889,13 @@ _e_comp_wl_compositor_create(void)
ERR("Could not initialize input");
goto input_err;
}
- e_comp_wl->wl.client_disp = ecore_wl2_display_connect(NULL);
+ /* Behind e_wl_proxy, connect E's internal display directly to the private
+ * backend socket (E_WL_SOCKET) so all of E's internal wayland traffic — this
+ * connection and the internal elm windows (see e_win.c) — lives on the same
+ * direct connection to E, not split across the proxy. Keeping them unified is
+ * what lets the internal_elm_win machinery match surfaces correctly. getenv
+ * returns NULL without the proxy, preserving the original behavior. */
+ e_comp_wl->wl.client_disp = ecore_wl2_display_connect(getenv("E_WL_SOCKET"));
_e_comp_wl_modules_load();
diff --git a/src/bin/e_start_main.c b/src/bin/e_start_main.c
index 2e7c50ed9..dc26d5b75 100644
--- a/src/bin/e_start_main.c
+++ b/src/bin/e_start_main.c
@@ -517,6 +517,68 @@ done:
return ret;
}
+/* Launch e_wl_proxy as a persistent sibling that owns the public Wayland
+ * socket, and point E at a private backend socket. Opt-in via E_WL_PROXY=1.
+ * The proxy outlives each E restart, so connected clients survive an E crash.
+ * Returns the proxy pid, or -1 if not started. */
+static pid_t
+_e_wl_proxy_start(void)
+{
+ const char *enable = getenv("E_WL_PROXY");
+ char *proxy_bin = NULL;
+ char fdbuf[16];
+ int rdy[2];
+ pid_t pid;
+ char c;
+ ssize_t n;
+
+ if (!enable || strcmp(enable, "1") != 0) return -1;
+
+ /* the name clients will use (default wayland-0), inherited by the session */
+ if (!getenv("WAYLAND_DISPLAY")) env_set("WAYLAND_DISPLAY", "wayland-0");
+ /* the private socket E will create and the proxy will connect to */
+ if (!getenv("E_WL_SOCKET")) env_set("E_WL_SOCKET", "wayland-e");
+ /* control socket the wl_proxy module connects to for WM-state mirroring */
+ if (!getenv("E_WL_PROXY_SOCK")) env_set("E_WL_PROXY_SOCK", "e_wl_proxy-0");
+
+ myasprintf(&proxy_bin, "%s/e_wl_proxy", eina_prefix_bin_get(pfx));
+
+ /* readiness pipe: the proxy writes a byte once its public socket is up, so
+ * we start E only after clients can actually connect (no startup race). */
+ if (pipe(rdy) != 0) return -1;
+
+ pid = fork();
+ if (pid < 0) { close(rdy[0]); close(rdy[1]); return -1; }
+ if (pid == 0)
+ {
+ /* die with enlightenment_start so the proxy never outlives the session */
+#ifdef HAVE_PRCTL
+ prctl(PR_SET_PDEATHSIG, SIGTERM);
+#elif defined(HAVE_PROCCTL)
+ int sig = SIGTERM;
+ procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &sig);
+#endif
+ close(rdy[0]); /* child only writes */
+ snprintf(fdbuf, sizeof(fdbuf), "%d", rdy[1]);
+ env_set("E_WL_PROXY_READY_FD", fdbuf);
+ execl(proxy_bin, proxy_bin, (char *)NULL);
+ _exit(127);
+ }
+
+ /* parent: block until the proxy signals readiness (1 byte) or dies (EOF). */
+ close(rdy[1]); /* parent only reads */
+ n = read(rdy[0], &c, 1);
+ close(rdy[0]);
+ if (n != 1)
+ {
+ fprintf(stderr, "e_wl_proxy did not come up; continuing without it\n");
+ waitpid(pid, NULL, WNOHANG); /* reap if it already exited */
+ return -1;
+ }
+
+ return pid;
+}
+
int
main(int argc, char **argv)
{
@@ -730,6 +792,9 @@ main(int argc, char **argv)
args[argc] = NULL;
}
+ /* start the wayland proxy (if enabled) before the restart loop, so it
+ * persists across E restarts and keeps clients alive across an E crash. */
+ _e_wl_proxy_start();
/* Now looping until */
while (restart)
diff --git a/src/bin/e_win.c b/src/bin/e_win.c
index 0c56afdbc..108383d9f 100644
--- a/src/bin/e_win.c
+++ b/src/bin/e_win.c
@@ -510,16 +510,45 @@ e_win_no_reopen_set(Evas_Object *obj, Eina_Bool no_reopen)
ctx->client->internal_no_reopen = !!no_reopen;
}
+/* Internal windows (E's own dialogs/menus/popups) must connect to E directly,
+ * not via e_wl_proxy: a forwarded connection makes their peer credentials read
+ * as the proxy's pid, so E fails the pid==getpid() internal test and the
+ * internal_elm_win machinery (which assumes a direct connection) desyncs. Point
+ * the elm connect at the private backend socket (E_WL_SOCKET) for its duration;
+ * externally spawned apps keep the proxy's public WAYLAND_DISPLAY and still get
+ * crash recovery. No-op when not running behind the proxy. */
+static char *
+_e_win_disp_to_backend(void)
+{
+ const char *be = getenv("E_WL_SOCKET");
+ char *saved;
+
+ if (!be) return NULL;
+ saved = eina_strdup(getenv("WAYLAND_DISPLAY"));
+ e_util_env_set("WAYLAND_DISPLAY", be);
+ return saved;
+}
+
+static void
+_e_win_disp_restore(char *saved)
+{
+ if (!getenv("E_WL_SOCKET")) return;
+ e_util_env_set("WAYLAND_DISPLAY", saved);
+ free(saved);
+}
+
E_API Evas_Object *
e_elm_win_add(Evas_Object *parent, const char *name, Elm_Win_Type type)
{
- char *eng;
+ char *eng, *wld;
Evas_Object *o;
if (type == ELM_WIN_INLINED_IMAGE) return elm_win_add(parent, name, type);
eng = eina_strdup(getenv("ELM_ACCEL"));
e_util_env_set("ELM_ACCEL", "none");
+ wld = _e_win_disp_to_backend();
o = elm_win_add(parent, name, type);
+ _e_win_disp_restore(wld);
e_util_env_set("ELM_ACCEL", eng);
elm_win_alpha_set(o, 1);
free(eng);
@@ -529,12 +558,14 @@ e_elm_win_add(Evas_Object *parent, const char *name, Elm_Win_Type type)
E_API Evas_Object *
e_elm_win_util_standard_add(const char *name, const char *title)
{
- char *eng;
+ char *eng, *wld;
Evas_Object *o;
eng = eina_strdup(getenv("ELM_ACCEL"));
e_util_env_set("ELM_ACCEL", "none");
+ wld = _e_win_disp_to_backend();
o = elm_win_util_standard_add(name, title);
+ _e_win_disp_restore(wld);
e_util_env_set("ELM_ACCEL", eng);
elm_win_alpha_set(o, 1);
free(eng);
@@ -544,12 +575,14 @@ e_elm_win_util_standard_add(const char *name, const char *title)
E_API Evas_Object *
e_elm_win_util_dialog_add(Evas_Object *parent, const char *name, const char *title)
{
- char *eng;
+ char *eng, *wld;
Evas_Object *o;
eng = eina_strdup(getenv("ELM_ACCEL"));
e_util_env_set("ELM_ACCEL", "none");
+ wld = _e_win_disp_to_backend();
o = elm_win_util_dialog_add(parent, name, title);
+ _e_win_disp_restore(wld);
e_util_env_set("ELM_ACCEL", eng);
elm_win_alpha_set(o, 1);
free(eng);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.