From 8eddbf7b6ae2f46e48ff94d80716190d634da3c5 Mon Sep 17 00:00:00 2001 From: davey Date: Fri, 6 Nov 2026 22:24:31 +0100 Subject: [PATCH] x11: load libXss at run time Closes #20018 --- .github/workflows/Linux-aarch64.yml | 7 ++- Makefile.common | 3 - gfx/common/x11_common.c | 92 +++++++++++++++++++++++++++-- qb/config.libs.sh | 3 +- 4 files changed, 94 insertions(+), 11 deletions(-) diff --git a/.github/workflows/Linux-aarch64.yml b/.github/workflows/Linux-aarch64.yml index aee47ba6ef..2f3a5ebb2c 100644 --- a/.github/workflows/Linux-aarch64.yml +++ b/.github/workflows/Linux-aarch64.yml @@ -77,8 +77,9 @@ jobs: - name: Configure run: | - ./configure --disable-qt --disable-ffmpeg --disable-cg --disable-xscrnsaver --enable-openxr + ./configure --disable-qt --disable-ffmpeg --disable-cg --enable-openxr grep -q '^HAVE_OPENXR = 1' config.mk + grep -q '^HAVE_XSCRNSAVER = 1' config.mk - name: Compile RA run: make -j$(getconf _NPROCESSORS_ONLN) @@ -86,6 +87,10 @@ jobs: - name: Check and strip run: | ./retroarch --version + if readelf -d retroarch | grep -q 'libXss'; then + echo 'retroarch must load libXss at run time, not link it' + exit 1 + fi strip retroarch - name: Get short SHA diff --git a/Makefile.common b/Makefile.common index f0c2f4aa8e..12b3380d1a 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1374,9 +1374,6 @@ ifeq ($(HAVE_X11), 1) LIBS += -lXi DEFINES += -DHAVE_XI2 endif - ifeq ($(HAVE_XSCRNSAVER),1) - LIBS += -lXss - endif ifneq ($(HAVE_OPENGLES), 1) OBJ += gfx/drivers_context/x_ctx.o endif diff --git a/gfx/common/x11_common.c b/gfx/common/x11_common.c index 56e3be1e3e..1432eaa1dc 100644 --- a/gfx/common/x11_common.c +++ b/gfx/common/x11_common.c @@ -284,10 +284,90 @@ void x11_set_window_attr(Display *dpy, Window win) x11_set_window_pid(dpy, win); } -#ifdef HAVE_XSCRNSAVER -#include +#if defined(HAVE_XSCRNSAVER) && defined(HAVE_DYLIB) +#include + +typedef Bool (*xss_query_extension_t)(Display*, int*, int*); +typedef Status (*xss_query_version_t)(Display*, int*, int*); +typedef void (*xss_suspend_t)(Display*, Bool); + +typedef struct +{ + dylib_t lib; + xss_query_extension_t query_extension; + xss_query_version_t query_version; + xss_suspend_t suspend; +} xss_t; + +/* libXss is loaded on first use, so the binary starts where it is + * absent. A threaded video driver asks from its own thread; whoever + * loads first publishes. */ +#ifdef RETRO_ATOMIC_HAS_PTR +static retro_atomic_ptr_t xss_published; +#else +static xss_t *xss_published; +#endif + +#define XSS_SYM(field, name) \ + if (!(sym = dylib_proc(t->lib, name))) \ + goto fail; \ + memcpy(&t->field, &sym, sizeof(sym)) + +static xss_t *xss_load(void) +{ + function_t sym; + xss_t *t = (xss_t*)calloc(1, sizeof(*t)); + + if (!t) + return NULL; + t->lib = dylib_load("libXss.so.1"); +#ifdef __OpenBSD__ + /* OpenBSD's sonames carry its own version numbers. */ + if (!t->lib) + t->lib = dylib_load("libXss.so"); +#endif + if (!t->lib) + { + free(t); + return NULL; + } + + XSS_SYM(query_extension, "XScreenSaverQueryExtension"); + XSS_SYM(query_version, "XScreenSaverQueryVersion"); + XSS_SYM(suspend, "XScreenSaverSuspend"); + return t; + +fail: + dylib_close(t->lib); + free(t); + return NULL; +} + +static const xss_t *xss_get(void) +{ + xss_t *t; +#ifdef RETRO_ATOMIC_HAS_PTR + if ((t = (xss_t*)retro_atomic_load_acquire_ptr(&xss_published))) + return t; + if (!(t = xss_load())) + return NULL; + if (!retro_atomic_cas_ptr(&xss_published, NULL, t)) + { + dylib_close(t->lib); + free(t); + return (const xss_t*)retro_atomic_load_acquire_ptr(&xss_published); + } + return t; +#else + if (!xss_published) + xss_published = xss_load(); + return xss_published; +#endif +} + static bool xss_screensaver_inhibit(Display *dpy, bool enable) { + const xss_t *xss; int dummy, min, maj; /* Guard against being called with a NULL Display. This * happens with the SDL2 video driver under HAVE_X11 + @@ -302,14 +382,14 @@ static bool xss_screensaver_inhibit(Display *dpy, bool enable) * offset off the NULL display pointer. Surfaced by the * ASan+UBSan CI workflow's headless SDL2 smoke (b9777c8 + * d967813), where dbus-1 isn't apt-installed but libXss is. */ - if (!dpy) + if (!dpy || !(xss = xss_get())) return false; - if ( !XScreenSaverQueryExtension(dpy, &dummy, &dummy) - || !XScreenSaverQueryVersion(dpy, &maj, &min) + if ( !xss->query_extension(dpy, &dummy, &dummy) + || !xss->query_version(dpy, &maj, &min) || (maj < 1) || (maj == 1 && min < 1)) return false; - XScreenSaverSuspend(dpy, enable); + xss->suspend(dpy, enable); XResetScreenSaver(dpy); return true; } diff --git a/qb/config.libs.sh b/qb/config.libs.sh index ed297c5b13..083f3e5224 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -830,12 +830,13 @@ if [ "$HAVE_X11" != 'no' ]; then check_val '' XEXT -lXext '' xext '' '' false check_val '' XF86VM -lXxf86vm '' xxf86vm '' '' false - check_val '' XSCRNSAVER -lXss '' xscrnsaver '' '' false check_val '' XI2 -lXi '' xi '' '' false else die : 'Notice: X11 not present. Skipping X11 code paths.' fi +check_enabled X11 XSCRNSAVER XScrnSaver 'X11 is' true +check_enabled DYLIB XSCRNSAVER XScrnSaver 'Dynamic loading is' true check_enabled X11 XINERAMA Xinerama 'Xinerama is' false check_enabled X11 XSHM XShm 'XShm is' false check_enabled X11 XRANDR Xrandr 'Xrandr is' false