From 00bccf9b2d6e188edf3cd90e94e8a7e807bd4956 Mon Sep 17 00:00:00 2001 From: Lam Wei Lun Date: Mon, 12 Oct 2026 11:46:31 +0800 Subject: [PATCH] Linux: only disable WebKit compositing for WebKitGTK older than 2.42 The default Wayland path set WEBKIT_DISABLE_COMPOSITING_MODE=1 whenever the session had both DISPLAY and WAYLAND_DISPLAY, i.e. any Wayland session with XWayland. That forces WebKitGTK accelerated compositing off and also disables threaded scrolling, so the Device tab web view (Mainsail/Fluidd) lagged unless the app was launched with GDK_BACKEND=x11, the only path that skipped the variable. Disabling compositing also turns off threaded scrolling. The XWayland compositing bug the fallback worked around is fixed in WebKitGTK >= 2.42, so apply it only for older WebKit. WebView::NeedsCompositingWorkaround() reads the runtime WebKitGTK version; the X11 opt-in path is unchanged. Behavior is unchanged on WebKit < 2.42, on pure X11, and on native Wayland without XWayland. The wxWidgets skill reference is updated to match. --- .../orca-wxwidgets/references/platforms.md | 3 ++- .../references/webview-gl-aui-media.md | 21 ++++++++++++------- src/OrcaSlicer.cpp | 18 +++++++++------- src/slic3r/GUI/Widgets/WebView.cpp | 16 ++++++++++++++ src/slic3r/GUI/Widgets/WebView.hpp | 5 +++++ 5 files changed, 46 insertions(+), 17 deletions(-) diff --git a/.claude/skills/orca-wxwidgets/references/platforms.md b/.claude/skills/orca-wxwidgets/references/platforms.md index f391aecf27..c8360cd2e6 100644 --- a/.claude/skills/orca-wxwidgets/references/platforms.md +++ b/.claude/skills/orca-wxwidgets/references/platforms.md @@ -572,7 +572,8 @@ on the **first** call. So: **Before GTK starts**, only the environment exists. `CLI::run` (`src/OrcaSlicer.cpp`) branches on `GDK_BACKEND` (an `x11` prefix means the X11 opt-in). On the default path it forces `GDK_BACKEND=x11` when wx lacks EGL and `WAYLAND_DISPLAY` is set. It sets `WEBKIT_DISABLE_COMPOSITING_MODE=1` -(non-replacing) only when both `DISPLAY` and `WAYLAND_DISPLAY` are set, and calls `XInitThreads()` +(non-replacing) only when both `DISPLAY` and `WAYLAND_DISPLAY` are set and the linked WebKitGTK is +older than 2.42, and calls `XInitThreads()` only when `DISPLAY` is set. With neither variable set, the GUI refuses to start ("Neither DISPLAY nor WAYLAND_DISPLAY set"). The details and the WebKit rule (c12912e0df) are in `references/webview-gl-aui-media.md` §WebKitGTK on Linux sessions. diff --git a/.claude/skills/orca-wxwidgets/references/webview-gl-aui-media.md b/.claude/skills/orca-wxwidgets/references/webview-gl-aui-media.md index b8856b21ca..39356d5f2b 100644 --- a/.claude/skills/orca-wxwidgets/references/webview-gl-aui-media.md +++ b/.claude/skills/orca-wxwidgets/references/webview-gl-aui-media.md @@ -61,7 +61,8 @@ available; GTK2/WebKit1 is an opt-out configuration the GUI does not support. 11. A web host that re-themes in place handles `EVT_WEBVIEW_RECREATED` without `Skip()`; one that needs a reload lets it through. §[Orca wrapper](#orca-webview-wrapper-widgetswebview) 12. Keep `WebViewWebKit`'s destructor removing the `"wx"` handler. §[Orca wrapper](#orca-webview-wrapper-widgetswebview) -13. Do not widen `WEBKIT_DISABLE_COMPOSITING_MODE` beyond Orca's default-path XWayland case, and never +13. Do not widen `WEBKIT_DISABLE_COMPOSITING_MODE` beyond Orca's default-path XWayland case for + WebKitGTK older than 2.42, and never make a page's progress depend only on a C++→JS callback. §[WebKitGTK on Linux](#webkitgtk-on-linux-sessions) 14. GL attribute lists: legacy `int[]` lists end with `0` and spell out `WX_GL_RGBA` and `WX_GL_DOUBLEBUFFER`; `wxGLAttributes`/`wxGLContextAttrs` end with `EndList()`; MSAA is requested @@ -570,7 +571,8 @@ vue-resize workaround script and sets a persistent SQLite cookie store on the vi branches on `GDK_BACKEND`: - **Default path** (`GDK_BACKEND` unset or not starting with `x11`): if wx lacks EGL (`!wxHAS_EGL`) and `WAYLAND_DISPLAY` is set, it forces `GDK_BACKEND=x11`; it sets `WEBKIT_DISABLE_COMPOSITING_MODE=1` - non-replacing **only** when both `DISPLAY` and `WAYLAND_DISPLAY` are non-empty (a Wayland session with + non-replacing **only** when the linked WebKitGTK predates 2.42 (`WebView::NeedsCompositingWorkaround()`) + **and** both `DISPLAY` and `WAYLAND_DISPLAY` are non-empty (a Wayland session with XWayland available — the session, not the backend GTK will pick); `XInitThreads()` runs only when `DISPLAY` is set. - **`GDK_BACKEND=x11…` opt-in path**: sets `DRI_PRIME=1` (and the NVIDIA PRIME variables when @@ -584,16 +586,19 @@ Runtime backend detection elsewhere uses Orca's `is_running_on_wayland()` / `is_ **Pitfall.** - **Rule:** Set `WEBKIT_DISABLE_COMPOSITING_MODE` only on the default path in Wayland sessions, non-replacing (`setenv(..., false)`, so a value the user already exported wins), before GTK - initialises; never unconditionally. Keep JS-side fallbacks so a page never + initialises; never unconditionally, and only for the WebKitGTK releases that need it (older than + 2.42, `WebView::NeedsCompositingWorkaround()`). Keep JS-side fallbacks so a page never waits forever for a C++→JS call. - **Why:** WebKit2GTK accelerated compositing could fail silently under XWayland, leaving web views - blank (Setup Wizard stuck on "Loading..."); disabling it everywhere needlessly drops hardware - acceleration; without the JS timeout the user is stuck when the signal is lost. + **Why:** WebKit2GTK accelerated compositing could fail silently under XWayland before 2.42, leaving + web views blank (Setup Wizard stuck on "Loading..."); the variable also turns off threaded scrolling, + so applying it on a newer WebKit needlessly drops both GPU compositing and async scrolling (the + Device tab loses its smoothness); without the JS timeout the user is stuck when the signal is lost. ```cpp // Wrong: unconditional, kills HW acceleration everywhere ::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", false); - // Right (default path only): non-replacing, before GTK init, Wayland session with XWayland - if (display && *display && wayland && *wayland) + // Right (default path only): non-replacing, before GTK init, WebKitGTK < 2.42, + // Wayland session with XWayland + if (WebView::NeedsCompositingWorkaround() && display && *display && wayland && *wayland) ::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", /*replace*/ false); ``` Cite: c12912e0df (`src/OrcaSlicer.cpp`; `resources/web/guide/0/load.js` `OnInit` diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 1b764fe468..7e6c571134 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -161,6 +161,7 @@ using json = nlohmann::json; #include #endif #include +#include "slic3r/GUI/Widgets/WebView.hpp" #endif #ifdef SLIC3R_GUI @@ -1153,8 +1154,9 @@ int CLI::run(int argc, char **argv) // opt-in path. The ~2020-era WebKit2GTK XWayland compositor bug it // worked around appears fixed in WebKit2GTK >= 2.42; leaving it // unset preserves WebKit hardware acceleration on Device / Setup - // Wizard / login / store. The default path still applies it on - // XWayland sessions as a conservative fallback for older WebKit. + // Wizard / login / store. The default path applies it only on + // XWayland sessions and only when the linked WebKitGTK predates the + // fix (< 2.42), as a conservative fallback for older WebKit. // ------------------------------------------------------------------ { const char* gdk_backend = ::getenv("GDK_BACKEND"); @@ -1205,15 +1207,15 @@ int CLI::run(int argc, char **argv) } #endif - // WebKit2GTK compositing can fail under XWayland on older - // WebKit releases. Disable it only when both DISPLAY and - // WAYLAND_DISPLAY are set (i.e. an XWayland session is in - // use). On pure X11 or native Wayland, compositing is left - // enabled so WebKit retains HW acceleration. + // WebKit2GTK accelerated compositing could fail under XWayland + // on WebKit releases before 2.42. Disable it only then, and only + // when both DISPLAY and WAYLAND_DISPLAY are set (an XWayland + // session). Disabling it also turns off threaded scrolling, so on + // newer WebKit it only costs performance. { const char* display_env_wk = ::getenv("DISPLAY"); const char* wayland_env_wk = ::getenv("WAYLAND_DISPLAY"); - if (display_env_wk && *display_env_wk && wayland_env_wk && *wayland_env_wk) { + if (WebView::NeedsCompositingWorkaround() && display_env_wk && *display_env_wk && wayland_env_wk && *wayland_env_wk) { ::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", /* replace */ false); } } diff --git a/src/slic3r/GUI/Widgets/WebView.cpp b/src/slic3r/GUI/Widgets/WebView.cpp index 498fa4ec43..191b849a42 100644 --- a/src/slic3r/GUI/Widgets/WebView.cpp +++ b/src/slic3r/GUI/Widgets/WebView.cpp @@ -69,6 +69,10 @@ webkit_web_view_run_javascript_finish (WebKitWebView GError **error); WEBKIT_API void webkit_javascript_result_unref (WebKitJavascriptResult *js_result); +WEBKIT_API guint +webkit_get_major_version (void); +WEBKIT_API guint +webkit_get_minor_version (void); } #endif @@ -401,6 +405,18 @@ bool WebView::NeedsRecreateOnShow() return false; #endif } + +bool WebView::NeedsCompositingWorkaround() +{ +#ifdef __linux__ + const guint major = webkit_get_major_version(); + const guint minor = webkit_get_minor_version(); + return major < 2 || (major == 2 && minor < 42); +#else + return false; +#endif +} + #if wxUSE_WEBVIEW_EDGE bool WebView::CheckWebViewRuntime() { diff --git a/src/slic3r/GUI/Widgets/WebView.hpp b/src/slic3r/GUI/Widgets/WebView.hpp index cdd885f9bd..ac4aaab0b3 100644 --- a/src/slic3r/GUI/Widgets/WebView.hpp +++ b/src/slic3r/GUI/Widgets/WebView.hpp @@ -30,6 +30,11 @@ public: // ignoring every navigation. A panel that gets true here recreates its view on first Show(). static bool NeedsRecreateOnShow(); + // True when the linked WebKitGTK predates the fix for the XWayland accelerated + // compositing bug (< 2.42), so accelerated compositing must be forced off. False + // on every other platform. Safe to call before GTK initialises. + static bool NeedsCompositingWorkaround(); + static void RecreateAll(); };