From 2d152db090d283f3f5bc1c8b25a1e881f1e9b4e7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 2 May 2024 10:20:59 +1000 Subject: [PATCH] GHOST/Wayland: use XDG_CURRENT_DESKTOP to detect GNOME This change was made previously [0] but reverted as it caused the title-bar to disappear on Ubuntu (see #121241). Check if the value is set to GNOME delimited by `:`. Previously checking the interfaces was used which has the down-side that any compositor that adds `gtk_shell*` support may hang on startup because of bugs in Blender/LIBDECOR as happened with WAYFIRE, see reply to #76428. [0]: 3a5389d5abe00aa229b5c6d35d346cb8f7cbe649 --- intern/ghost/intern/GHOST_SystemWayland.cc | 90 ++++++++++------------ 1 file changed, 40 insertions(+), 50 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemWayland.cc b/intern/ghost/intern/GHOST_SystemWayland.cc index f7c2eb2e5ce..fc3e218c8f2 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cc +++ b/intern/ghost/intern/GHOST_SystemWayland.cc @@ -191,15 +191,6 @@ static bool use_gnome_confine_hack = false; */ #define USE_KDE_TABLET_HIDDEN_CURSOR_HACK -/** - * When GNOME is found, require `libdecor`. - * This is a hack because it seems there is no way to check if the compositor supports - * server side decorations when initializing WAYLAND. - */ -#ifdef WITH_GHOST_WAYLAND_LIBDECOR -# define USE_GNOME_NEEDS_LIBDECOR_HACK -#endif - /** \} */ /* -------------------------------------------------------------------- */ @@ -1362,12 +1353,6 @@ struct GWL_Display { #ifdef WITH_GHOST_WAYLAND_LIBDECOR GWL_LibDecor_System *libdecor = nullptr; - bool libdecor_required = false; - /** - * When true, behave as if `libdecor_required` is false. - * `libdecor_required` can't simply be set to false because the order of assignment is undefined. - */ - bool libdecor_required_ignore = false; #endif GWL_XDG_Decor_System *xdg_decor = nullptr; @@ -1778,6 +1763,35 @@ static void gwl_registry_entry_update_all(GWL_Display *display, const int interf /** \name Private Utility Functions * \{ */ +static const char *strchr_or_end(const char *str, const char ch) +{ + const char *p = str; + while (!ELEM(*p, ch, '\0')) { + p++; + } + return p; +} + +static bool string_elem_split_by_delim(const char *haystack, const char delim, const char *needle) +{ + /* Local copy of #BLI_string_elem_split_by_delim (would be a bad level call). */ + + /* May be zero, returns true when an empty span exists. */ + const size_t needle_len = strlen(needle); + const char *p = haystack, *p_next; + while (true) { + p_next = strchr_or_end(p, delim); + if ((size_t(p_next - p) == needle_len) && (memcmp(p, needle, needle_len) == 0)) { + return true; + } + if (*p_next == '\0') { + break; + } + p = p_next + 1; + } + return false; +} + static uint64_t sub_abs_u64(const uint64_t a, const uint64_t b) { return a > b ? a - b : b - a; @@ -6985,35 +6999,6 @@ static void global_handle_add(void *data, added = display->registry_entry != registry_entry_prev; } - else { - /* Not found. */ -#ifdef USE_GNOME_NEEDS_LIBDECOR_HACK - /* NOTE(@ideasman42): I'm not happy with the logic here because it's fairly fragile - * and will cause problems whenever any non-GNOME compositor adds support for `gtk_shell*` - * Ideally there would be a way to: - * - Detect when server-side-decorations aren't supported. - * `zxdg_decoration_manager_v1` looks like it *could* be used - * but it's not supported by GNOME. - * - Detect the underlying compositor. - * `XDG_CURRENT_DESKTOP` could be used but isn't always set, see: #121241. - * - * All things considered, inspecting interface names seems least terrible (sigh). - */ - - /* `gtk_shell1` at time of writing. */ - if (STRPREFIX(interface, "gtk_shell")) { - /* Only require `libdecor` when built with X11 support, - * otherwise there is nothing to fall back on. */ - display->libdecor_required = true; - } - /* `zwf_shell_manager_v2` at time of writing. */ - else if (STRPREFIX(interface, "zwf_shell_manager_v")) { - /* Needed when non GNOME compositors provide the `gtk_shell*` interface. - * WAYFIRE in this case. */ - display->libdecor_required_ignore = true; - } -#endif - } CLOG_INFO(LOG, 2, @@ -7171,28 +7156,33 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background) } #ifdef WITH_GHOST_WAYLAND_LIBDECOR - if (display_->libdecor_required_ignore) { - display_->libdecor_required = false; + bool libdecor_required = false; + if (const char *xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP")) { + /* See the free-desktop specifications for details on `XDG_CURRENT_DESKTOP`. + * https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html */ + if (string_elem_split_by_delim(xdg_current_desktop, ':', "GNOME")) { + libdecor_required = true; + } } - if (display_->libdecor_required) { + if (libdecor_required) { /* Ignore windowing requirements when running in background mode, * as it doesn't make sense to fall back to X11 because of windowing functionality * in background mode, also LIBDECOR is crashing in background mode `blender -b -f 1` * for e.g. while it could be fixed, requiring the library at all makes no sense. */ if (background) { - display_->libdecor_required = false; + libdecor_required = false; } # ifdef WITH_GHOST_X11 else if (!has_libdecor && !ghost_wayland_is_x11_available()) { /* Only require LIBDECOR when X11 is available, otherwise there is nothing to fall back to. * It's better to open without window decorations than failing entirely. */ - display_->libdecor_required = false; + libdecor_required = false; } # endif /* WITH_GHOST_X11 */ } - if (display_->libdecor_required) { + if (libdecor_required) { gwl_xdg_decor_system_destroy(display_, display_->xdg_decor); display_->xdg_decor = nullptr;