diff options
author | Campbell Barton <campbell@blender.org> | 2022-10-12 08:54:31 +0300 |
---|---|---|
committer | Campbell Barton <campbell@blender.org> | 2022-10-12 09:01:52 +0300 |
commit | f0e1089a33f4054998c96a50b92503251a47aa97 (patch) | |
tree | 66eee14b091d73b2b52445799bacca932cfa3a7a | |
parent | 0f60872461e19282d8d058c6edc5e2cebd4f5c7e (diff) |
GHOST/Wayland: only require libdecor when running in gnome-shell
- Support switching between libdecor and xdg_shell at run-time.
- Require libdecor when using gnome-shell, otherwise use xdg_shell.
- Gnome-shell detection checks for a gtk_shell* interface which
isn't ideal however it's not possible to check server-side-decorations
are supported without first creating a window.
- Unload Wayland libraries when Wayland fails to load.
-rw-r--r-- | intern/ghost/CMakeLists.txt | 20 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_ISystem.cpp | 8 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWayland.cpp | 217 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWayland.h | 19 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWayland.cpp | 286 |
5 files changed, 364 insertions, 186 deletions
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 9e3a15dd543..2f8ea1f9065 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -349,16 +349,16 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) ${INC_DST} ) - if(NOT WITH_GHOST_WAYLAND_LIBDECOR) - # `xdg-shell`. - generate_protocol_bindings( - "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml" - ) - # `xdg-decoration`. - generate_protocol_bindings( - "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" - ) - endif() + # Used when: LIBDECOR is not needed. + # `xdg-shell`. + generate_protocol_bindings( + "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml" + ) + # `xdg-decoration`. + generate_protocol_bindings( + "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" + ) + # End LIBDECOR alternative. # `xdg-output`. generate_protocol_bindings( diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp index 0a35d1af5a4..8e2859ca1e1 100644 --- a/intern/ghost/intern/GHOST_ISystem.cpp +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -48,7 +48,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose) /* Pass. */ #elif defined(WITH_GHOST_WAYLAND) # if defined(WITH_GHOST_WAYLAND_DYNLOAD) - const bool has_wayland_libraries = ghost_wl_dynload_libraries(); + const bool has_wayland_libraries = ghost_wl_dynload_libraries_init(); # else const bool has_wayland_libraries = true; # endif @@ -66,6 +66,9 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose) catch (const std::runtime_error &) { delete m_system; m_system = nullptr; +# ifdef WITH_GHOST_WAYLAND_DYNLOAD + ghost_wl_dynload_libraries_exit(); +# endif } } else { @@ -101,6 +104,9 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose) catch (const std::runtime_error &) { delete m_system; m_system = nullptr; +# ifdef WITH_GHOST_WAYLAND_DYNLOAD + ghost_wl_dynload_libraries_exit(); +# endif } } else { diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 7e56ed0affb..44b20ae2aef 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -54,6 +54,11 @@ #include <tablet-unstable-v2-client-protocol.h> #include <xdg-output-unstable-v1-client-protocol.h> +/* Decorations `xdg_decor`. */ +#include <xdg-decoration-unstable-v1-client-protocol.h> +#include <xdg-shell-client-protocol.h> +/* End `xdg_decor`. */ + #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> @@ -64,6 +69,15 @@ /* Logging, use `ghost.wl.*` prefix. */ #include "CLG_log.h" +#ifdef WITH_GHOST_WAYLAND_LIBDECOR +static bool use_libdecor = true; +# ifdef WITH_GHOST_WAYLAND_DYNLOAD +static bool has_libdecor = false; +# else +static bool has_libdecor = true; +# endif +#endif + static void keyboard_handle_key_repeat_cancel(struct GWL_Seat *seat); static void output_handle_done(void *data, struct wl_output *wl_output); @@ -106,6 +120,13 @@ static bool use_gnome_confine_hack = false; */ #define USE_GNOME_KEYBOARD_SUPPRESS_WARNING +/** + * 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. + */ +#define USE_GNOME_NEEDS_LIBDECOR_HACK + /** \} */ /* -------------------------------------------------------------------- */ @@ -357,6 +378,36 @@ struct WGL_KeyboardDepressedState { int16_t mods[GHOST_KEY_MODIFIER_NUM] = {0}; }; +#ifdef WITH_GHOST_WAYLAND_LIBDECOR +struct WGL_LibDecor_System { + struct libdecor *context = nullptr; +}; + +static void wgl_libdecor_system_destroy(WGL_LibDecor_System *decor) +{ + if (decor->context) { + libdecor_unref(decor->context); + } + delete decor; +} +#endif + +struct WGL_XDG_Decor_System { + struct xdg_wm_base *shell = nullptr; + struct zxdg_decoration_manager_v1 *manager = nullptr; +}; + +static void wgl_xdg_decor_system_destroy(WGL_XDG_Decor_System *decor) +{ + if (decor->manager) { + zxdg_decoration_manager_v1_destroy(decor->manager); + } + if (decor->shell) { + xdg_wm_base_destroy(decor->shell); + } + delete decor; +} + struct GWL_Seat { GHOST_SystemWayland *system = nullptr; @@ -455,11 +506,10 @@ struct GWL_Display { struct wl_compositor *compositor = nullptr; #ifdef WITH_GHOST_WAYLAND_LIBDECOR - struct libdecor *decor_context = nullptr; -#else - struct xdg_wm_base *xdg_shell = nullptr; - struct zxdg_decoration_manager_v1 *xdg_decoration_manager = nullptr; + WGL_LibDecor_System *libdecor = nullptr; + bool libdecor_required = false; #endif + WGL_XDG_Decor_System *xdg_decor = nullptr; struct zxdg_output_manager_v1 *xdg_output_manager = nullptr; struct wl_shm *shm = nullptr; @@ -626,19 +676,19 @@ static void display_destroy(GWL_Display *d) } #ifdef WITH_GHOST_WAYLAND_LIBDECOR - if (d->decor_context) { - libdecor_unref(d->decor_context); + if (use_libdecor) { + if (d->libdecor) { + wgl_libdecor_system_destroy(d->libdecor); + } } -#else - if (d->xdg_decoration_manager) { - zxdg_decoration_manager_v1_destroy(d->xdg_decoration_manager); + else +#endif + { + if (d->xdg_decor) { + wgl_xdg_decor_system_destroy(d->xdg_decor); + } } - if (d->xdg_shell) { - xdg_wm_base_destroy(d->xdg_shell); - } -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */ - if (eglGetDisplay) { ::eglTerminate(eglGetDisplay(EGLNativeDisplayType(d->display))); } @@ -2903,10 +2953,8 @@ static const struct wl_output_listener output_listener = { /** \name Listener (XDG WM Base), #xdg_wm_base_listener * \{ */ -#ifndef WITH_GHOST_WAYLAND_LIBDECOR - static CLG_LogRef LOG_WL_XDG_WM_BASE = {"ghost.wl.handle.xdg_wm_base"}; -# define LOG (&LOG_WL_XDG_WM_BASE) +#define LOG (&LOG_WL_XDG_WM_BASE) static void shell_handle_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, @@ -2920,9 +2968,7 @@ static const struct xdg_wm_base_listener shell_listener = { shell_handle_ping, }; -# undef LOG - -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */ +#undef LOG /** \} */ @@ -2978,19 +3024,17 @@ static void global_handle_add(void *data, display->compositor = static_cast<wl_compositor *>( wl_registry_bind(wl_registry, name, &wl_compositor_interface, 3)); } -#ifdef WITH_GHOST_WAYLAND_LIBDECOR - /* Pass. */ -#else else if (STREQ(interface, xdg_wm_base_interface.name)) { - display->xdg_shell = static_cast<xdg_wm_base *>( + WGL_XDG_Decor_System &decor = *display->xdg_decor; + decor.shell = static_cast<xdg_wm_base *>( wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1)); - xdg_wm_base_add_listener(display->xdg_shell, &shell_listener, nullptr); + xdg_wm_base_add_listener(decor.shell, &shell_listener, nullptr); } else if (STREQ(interface, zxdg_decoration_manager_v1_interface.name)) { - display->xdg_decoration_manager = static_cast<zxdg_decoration_manager_v1 *>( + WGL_XDG_Decor_System &decor = *display->xdg_decor; + decor.manager = static_cast<zxdg_decoration_manager_v1 *>( wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1)); } -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */ else if (STREQ(interface, zxdg_output_manager_v1_interface.name)) { display->xdg_output_manager = static_cast<zxdg_output_manager_v1 *>( wl_registry_bind(wl_registry, name, &zxdg_output_manager_v1_interface, 2)); @@ -3048,6 +3092,18 @@ static void global_handle_add(void *data, } else { found = false; + +#ifdef USE_GNOME_NEEDS_LIBDECOR_HACK +# ifdef WITH_GHOST_X11 +# ifdef WITH_GHOST_WAYLAND_LIBDECOR + if (STRPREFIX(interface, "gtk_shell")) { /* `gtk_shell1` at time of writing. */ + /* Only require libdecor when built with X11 support, + * otherwise there is nothing to fall back on. */ + display->libdecor_required = true; + } +# endif /* WITH_GHOST_WAYLAND_LIBDECOR */ +# endif /* WITH_GHOST_X11 */ +#endif /* USE_GNOME_NEEDS_LIBDECOR_HACK */ } CLOG_INFO(LOG, @@ -3102,6 +3158,9 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new GWL_Display) throw std::runtime_error("Wayland: unable to connect to display!"); } + /* This may be removed later if decorations are required, needed as part of registration. */ + d->xdg_decor = new WGL_XDG_Decor_System; + /* Register interfaces. */ struct wl_registry *registry = wl_display_get_registry(d->display); wl_registry_add_listener(registry, ®istry_listener, d); @@ -3112,17 +3171,45 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new GWL_Display) wl_registry_destroy(registry); #ifdef WITH_GHOST_WAYLAND_LIBDECOR - d->decor_context = libdecor_new(d->display, &libdecor_interface); - if (!d->decor_context) { - display_destroy(d); - throw std::runtime_error("Wayland: unable to create window decorations!"); + if (d->libdecor_required) { + wgl_xdg_decor_system_destroy(d->xdg_decor); + d->xdg_decor = nullptr; + + if (!has_libdecor) { +# ifdef WITH_GHOST_X11 + /* LIBDECOR was the only reason X11 was used, let the user know they need it installed. */ + fprintf(stderr, + "WAYLAND found but libdecor was not, install libdecor for Wayland support, " + "falling back to X11\n"); +# endif + display_destroy(d); + throw std::runtime_error("Wayland: unable to find libdecor!"); + } } -#else - if (!d->xdg_shell) { - display_destroy(d); - throw std::runtime_error("Wayland: unable to access xdg_shell!"); + else { + use_libdecor = false; } +#endif /* WITH_GHOST_WAYLAND_LIBDECOR */ + +#ifdef WITH_GHOST_WAYLAND_LIBDECOR + if (use_libdecor) { + d->libdecor = new WGL_LibDecor_System; + WGL_LibDecor_System &decor = *d->libdecor; + decor.context = libdecor_new(d->display, &libdecor_interface); + if (!decor.context) { + display_destroy(d); + throw std::runtime_error("Wayland: unable to create window decorations!"); + } + } + else #endif + { + WGL_XDG_Decor_System &decor = *d->xdg_decor; + if (!decor.shell) { + display_destroy(d); + throw std::runtime_error("Wayland: unable to access xdg_shell!"); + } + } /* Register data device per seat for IPC between Wayland clients. */ if (d->data_device_manager) { @@ -4052,24 +4139,26 @@ wl_compositor *GHOST_SystemWayland::compositor() #ifdef WITH_GHOST_WAYLAND_LIBDECOR -libdecor *GHOST_SystemWayland::decor_context() +libdecor *GHOST_SystemWayland::libdecor_context() { - return d->decor_context; + GHOST_ASSERT(use_libdecor, "X"); + GHOST_ASSERT(d->libdecor != nullptr, "X"); + return d->libdecor->context; } -#else /* WITH_GHOST_WAYLAND_LIBDECOR */ +#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */ -xdg_wm_base *GHOST_SystemWayland::xdg_shell() +xdg_wm_base *GHOST_SystemWayland::xdg_decor_shell() { - return d->xdg_shell; + return d->xdg_decor->shell; } -zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decoration_manager() +zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decor_manager() { - return d->xdg_decoration_manager; + return d->xdg_decor->manager; } -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */ +/* End `xdg_decor`. */ const std::vector<GWL_Output *> &GHOST_SystemWayland::outputs() const { @@ -4317,8 +4406,15 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod return GHOST_kSuccess; } +#ifdef WITH_GHOST_WAYLAND_LIBDECOR +bool GHOST_SystemWayland::use_libdecor_runtime() +{ + return use_libdecor; +} +#endif + #ifdef WITH_GHOST_WAYLAND_DYNLOAD -bool ghost_wl_dynload_libraries() +bool ghost_wl_dynload_libraries_init() { # ifdef WITH_GHOST_X11 /* When running in WAYLAND, let the user know when a missing library is the only reason @@ -4329,38 +4425,33 @@ bool ghost_wl_dynload_libraries() bool verbose = true; # endif /* !WITH_GHOST_X11 */ -# ifdef WITH_GHOST_WAYLAND_LIBDECOR - int8_t libdecor_init = -1; -# endif - if (wayland_dynload_client_init(verbose) && /* `libwayland-client`. */ wayland_dynload_cursor_init(verbose) && /* `libwayland-cursor`. */ - wayland_dynload_egl_init(verbose) && /* `libwayland-egl`. */ + wayland_dynload_egl_init(verbose) /* `libwayland-egl`. */ + ) { # ifdef WITH_GHOST_WAYLAND_LIBDECOR - (libdecor_init = wayland_dynload_libdecor_init(verbose)) && /* `libdecor-0`. */ + has_libdecor = wayland_dynload_libdecor_init(verbose); /* `libdecor-0`. */ # endif - true) { return true; } -# if defined(WITH_GHOST_WAYLAND_LIBDECOR) && defined(WITH_GHOST_X11) - if (libdecor_init == 0) { - /* LIBDECOR was the only reason X11 was used, let the user know they need it installed. */ - fprintf(stderr, - "WAYLAND found but libdecor was not, install libdecor for Wayland support, " - "falling back to X11\n"); - } -# endif - -# ifdef WITH_GHOST_WAYLAND_LIBDECOR - wayland_dynload_libdecor_exit(); -# endif wayland_dynload_client_exit(); wayland_dynload_cursor_exit(); wayland_dynload_egl_exit(); return false; } + +void ghost_wl_dynload_libraries_exit() +{ + wayland_dynload_client_exit(); + wayland_dynload_cursor_exit(); + wayland_dynload_egl_exit(); +# ifdef WITH_GHOST_WAYLAND_LIBDECOR + wayland_dynload_libdecor_exit(); +# endif +} + #endif /* WITH_GHOST_WAYLAND_DYNLOAD */ /** \} */ diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h index caea7b0d748..864dee72b0c 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.h +++ b/intern/ghost/intern/GHOST_SystemWayland.h @@ -21,10 +21,6 @@ # include <wayland_dynload_libdecor.h> # endif # include <libdecor.h> -#else -/* Generated by `wayland-scanner`. */ -# include <xdg-decoration-unstable-v1-client-protocol.h> -# include <xdg-shell-client-protocol.h> #endif #include <string> @@ -52,7 +48,8 @@ void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *surface); * Return true when all required WAYLAND libraries are present, * Performs dynamic loading when `WITH_GHOST_WAYLAND_DYNLOAD` is in use. */ -bool ghost_wl_dynload_libraries(); +bool ghost_wl_dynload_libraries_init(); +void ghost_wl_dynload_libraries_exit(); #endif struct GWL_Output { @@ -167,11 +164,11 @@ class GHOST_SystemWayland : public GHOST_System { wl_compositor *compositor(); #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor *decor_context(); -#else - xdg_wm_base *xdg_shell(); - zxdg_decoration_manager_v1 *xdg_decoration_manager(); + libdecor *libdecor_context(); #endif + struct xdg_wm_base *xdg_decor_shell(); + struct zxdg_decoration_manager_v1 *xdg_decor_manager(); + /* End `xdg_decor`. */ const std::vector<GWL_Output *> &outputs() const; @@ -192,6 +189,10 @@ class GHOST_SystemWayland : public GHOST_System { wl_surface *wl_surface, int scale); +#ifdef WITH_GHOST_WAYLAND_LIBDECOR + static bool use_libdecor_runtime(); +#endif + private: struct GWL_Display *d; std::string selection; diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp index 5f3cb3e3f3a..62897b220b8 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cpp +++ b/intern/ghost/intern/GHOST_WindowWayland.cpp @@ -31,13 +31,52 @@ # include <libdecor.h> #endif +/* Generated by `wayland-scanner`. */ +#include <xdg-decoration-unstable-v1-client-protocol.h> +#include <xdg-shell-client-protocol.h> + /* Logging, use `ghost.wl.*` prefix. */ #include "CLG_log.h" static constexpr size_t base_dpi = 96; +#ifdef WITH_GHOST_WAYLAND_LIBDECOR +/* Access `use_libdecor` in #GHOST_SystemWayland. */ +# define use_libdecor GHOST_SystemWayland::use_libdecor_runtime() +#endif + static GHOST_WindowManager *window_manager = nullptr; +#ifdef WITH_GHOST_WAYLAND_LIBDECOR +struct WGL_LibDecor_Window { + struct libdecor_frame *frame = nullptr; + bool configured = false; +}; + +static void wgl_libdecor_window_destroy(WGL_LibDecor_Window *decor) +{ + libdecor_frame_unref(decor->frame); + delete decor; +} +#endif /* WITH_GHOST_WAYLAND_LIBDECOR */ + +struct WGL_XDG_Decor_Window { + struct xdg_surface *surface = nullptr; + struct zxdg_toplevel_decoration_v1 *toplevel_decor = nullptr; + struct xdg_toplevel *toplevel = nullptr; + enum zxdg_toplevel_decoration_v1_mode mode = (enum zxdg_toplevel_decoration_v1_mode)0; +}; + +static void wgl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor) +{ + if (decor->toplevel_decor) { + zxdg_toplevel_decoration_v1_destroy(decor->toplevel_decor); + } + xdg_toplevel_destroy(decor->toplevel); + xdg_surface_destroy(decor->surface); + delete decor; +} + struct GWL_Window { GHOST_WindowWayland *w = nullptr; struct wl_surface *wl_surface = nullptr; @@ -60,15 +99,9 @@ struct GWL_Window { uint32_t dpi = 0; #ifdef WITH_GHOST_WAYLAND_LIBDECOR - struct libdecor_frame *decor_frame = nullptr; - bool decor_configured = false; -#else - struct xdg_surface *xdg_surface = nullptr; - struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration = nullptr; - struct xdg_toplevel *xdg_toplevel = nullptr; - - enum zxdg_toplevel_decoration_v1_mode decoration_mode = (enum zxdg_toplevel_decoration_v1_mode)0; + WGL_LibDecor_Window *libdecor = nullptr; #endif + WGL_XDG_Decor_Window *xdg_decor = nullptr; wl_egl_window *egl_window = nullptr; bool is_maximised = false; @@ -146,10 +179,8 @@ static int outputs_max_scale_or_default(const std::vector<GWL_Output *> &outputs /** \name Listener (XDG Top Level), #xdg_toplevel_listener * \{ */ -#ifndef WITH_GHOST_WAYLAND_LIBDECOR - static CLG_LogRef LOG_WL_XDG_TOPLEVEL = {"ghost.wl.handle.xdg_toplevel"}; -# define LOG (&LOG_WL_XDG_TOPLEVEL) +#define LOG (&LOG_WL_XDG_TOPLEVEL) static void xdg_toplevel_handle_configure(void *data, xdg_toplevel * /*xdg_toplevel*/, @@ -197,9 +228,7 @@ static const xdg_toplevel_listener toplevel_listener = { xdg_toplevel_handle_close, }; -# undef LOG - -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */ +#undef LOG /** \} */ @@ -250,7 +279,7 @@ static void frame_handle_configure(struct libdecor_frame *frame, libdecor_frame_commit(frame, state, configuration); libdecor_state_free(state); - win->decor_configured = true; + win->libdecor->configured = true; } static void frame_handle_close(struct libdecor_frame * /*frame*/, void *data) @@ -285,10 +314,8 @@ static struct libdecor_frame_interface libdecor_frame_iface = { /** \name Listener (XDG Decoration Listener), #zxdg_toplevel_decoration_v1_listener * \{ */ -#ifndef WITH_GHOST_WAYLAND_LIBDECOR - static CLG_LogRef LOG_WL_XDG_TOPLEVEL_DECORATION = {"ghost.wl.handle.xdg_toplevel_decoration"}; -# define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION) +#define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION) static void xdg_toplevel_decoration_handle_configure( void *data, @@ -296,16 +323,14 @@ static void xdg_toplevel_decoration_handle_configure( const uint32_t mode) { CLOG_INFO(LOG, 2, "configure (mode=%u)", mode); - static_cast<GWL_Window *>(data)->decoration_mode = (zxdg_toplevel_decoration_v1_mode)mode; + static_cast<GWL_Window *>(data)->xdg_decor->mode = (zxdg_toplevel_decoration_v1_mode)mode; } static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listener = { xdg_toplevel_decoration_handle_configure, }; -# undef LOG - -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */ +#undef LOG /** \} */ @@ -313,10 +338,8 @@ static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listene /** \name Listener (XDG Surface Handle Configure), #xdg_surface_listener * \{ */ -#ifndef WITH_GHOST_WAYLAND_LIBDECOR - static CLG_LogRef LOG_WL_XDG_SURFACE = {"ghost.wl.handle.xdg_surface"}; -# define LOG (&LOG_WL_XDG_SURFACE) +#define LOG (&LOG_WL_XDG_SURFACE) static void xdg_surface_handle_configure(void *data, xdg_surface *xdg_surface, @@ -324,7 +347,7 @@ static void xdg_surface_handle_configure(void *data, { GWL_Window *win = static_cast<GWL_Window *>(data); - if (win->xdg_surface != xdg_surface) { + if (win->xdg_decor->surface != xdg_surface) { CLOG_INFO(LOG, 2, "configure (skipped)"); return; } @@ -354,9 +377,7 @@ static const xdg_surface_listener xdg_surface_listener = { xdg_surface_handle_configure, }; -# undef LOG - -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */ +#undef LOG /** \} */ @@ -477,42 +498,52 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, const int32_t size_min[2] = {320, 240}; #ifdef WITH_GHOST_WAYLAND_LIBDECOR - /* create window decorations */ - w->decor_frame = libdecor_decorate( - m_system->decor_context(), w->wl_surface, &libdecor_frame_iface, w); - libdecor_frame_map(w->decor_frame); + if (use_libdecor) { + w->libdecor = new WGL_LibDecor_Window; + WGL_LibDecor_Window &decor = *w->libdecor; - libdecor_frame_set_min_content_size(w->decor_frame, UNPACK2(size_min)); + /* create window decorations */ + decor.frame = libdecor_decorate( + m_system->libdecor_context(), w->wl_surface, &libdecor_frame_iface, w); + libdecor_frame_map(w->libdecor->frame); - if (parentWindow) { - libdecor_frame_set_parent( - w->decor_frame, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->decor_frame); - } -#else - w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->xdg_shell(), w->wl_surface); - w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface); - - xdg_toplevel_set_min_size(w->xdg_toplevel, UNPACK2(size_min)); + libdecor_frame_set_min_content_size(decor.frame, UNPACK2(size_min)); - if (m_system->xdg_decoration_manager()) { - w->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( - m_system->xdg_decoration_manager(), w->xdg_toplevel); - zxdg_toplevel_decoration_v1_add_listener( - w->xdg_toplevel_decoration, &toplevel_decoration_v1_listener, w); - zxdg_toplevel_decoration_v1_set_mode(w->xdg_toplevel_decoration, - ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + if (parentWindow) { + WGL_LibDecor_Window &decor_parent = + *dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->libdecor; + libdecor_frame_set_parent(decor.frame, decor_parent.frame); + } } + else +#endif + { + w->xdg_decor = new WGL_XDG_Decor_Window; + WGL_XDG_Decor_Window &decor = *w->xdg_decor; + decor.surface = xdg_wm_base_get_xdg_surface(m_system->xdg_decor_shell(), w->wl_surface); + decor.toplevel = xdg_surface_get_toplevel(decor.surface); + + xdg_toplevel_set_min_size(decor.toplevel, UNPACK2(size_min)); + + if (m_system->xdg_decor_manager()) { + decor.toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration( + m_system->xdg_decor_manager(), decor.toplevel); + zxdg_toplevel_decoration_v1_add_listener( + decor.toplevel_decor, &toplevel_decoration_v1_listener, w); + zxdg_toplevel_decoration_v1_set_mode(decor.toplevel_decor, + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } - xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w); - xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w); + xdg_surface_add_listener(decor.surface, &xdg_surface_listener, w); + xdg_toplevel_add_listener(decor.toplevel, &toplevel_listener, w); - if (parentWindow && is_dialog) { - xdg_toplevel_set_parent( - w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel); + if (parentWindow && is_dialog) { + WGL_XDG_Decor_Window &decor_parent = + *dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_decor; + xdg_toplevel_set_parent(decor.toplevel, decor_parent.toplevel); + } } -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */ - setTitle(title); wl_surface_set_user_data(w->wl_surface, this); @@ -522,11 +553,14 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, wl_display_roundtrip(m_system->display()); #ifdef WITH_GHOST_WAYLAND_LIBDECOR - /* It's important not to return until the window is configured or - * calls to `setState` from Blender will crash `libdecor`. */ - while (!w->decor_configured) { - if (libdecor_dispatch(m_system->decor_context(), 0) < 0) { - break; + if (use_libdecor) { + WGL_LibDecor_Window &decor = *w->libdecor; + /* It's important not to return until the window is configured or + * calls to `setState` from Blender will crash `libdecor`. */ + while (!decor.configured) { + if (libdecor_dispatch(m_system->libdecor_context(), 0) < 0) { + break; + } } } #endif @@ -535,9 +569,13 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, setOpaque(); #endif -#ifndef WITH_GHOST_WAYLAND_LIBDECOR /* Causes a glitch with `libdecor` for some reason. */ - setState(state); + /* Causes a glitch with `libdecor` for some reason. */ +#ifdef WITH_GHOST_WAYLAND_LIBDECOR + if (use_libdecor == false) #endif + { + setState(state); + } /* EGL context. */ if (setDrawingContextType(type) == GHOST_kFailure) { @@ -596,12 +634,18 @@ GHOST_TSuccess GHOST_WindowWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitma void GHOST_WindowWayland::setTitle(const char *title) { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_set_app_id(w->decor_frame, title); - libdecor_frame_set_title(w->decor_frame, title); -#else - xdg_toplevel_set_title(w->xdg_toplevel, title); - xdg_toplevel_set_app_id(w->xdg_toplevel, title); + if (use_libdecor) { + WGL_LibDecor_Window &decor = *w->libdecor; + libdecor_frame_set_app_id(decor.frame, title); + libdecor_frame_set_title(decor.frame, title); + } + else #endif + { + WGL_XDG_Decor_Window &decor = *w->xdg_decor; + xdg_toplevel_set_title(decor.toplevel, title); + xdg_toplevel_set_app_id(decor.toplevel, title); + } this->title = title; } @@ -672,14 +716,14 @@ GHOST_WindowWayland::~GHOST_WindowWayland() wl_egl_window_destroy(w->egl_window); #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_unref(w->decor_frame); -#else - if (w->xdg_toplevel_decoration) { - zxdg_toplevel_decoration_v1_destroy(w->xdg_toplevel_decoration); + if (use_libdecor) { + wgl_libdecor_window_destroy(w->libdecor); } - xdg_toplevel_destroy(w->xdg_toplevel); - xdg_surface_destroy(w->xdg_surface); + else #endif + { + wgl_xdg_decor_window_destroy(w->xdg_decor); + } /* Clear any pointers to this window. This is needed because there are no guarantees * that flushing the display will the "leave" handlers before handling events. */ @@ -711,47 +755,74 @@ GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state) case GHOST_kWindowStateNormal: /* Unset states. */ switch (getState()) { - case GHOST_kWindowStateMaximized: + case GHOST_kWindowStateMaximized: { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_unset_maximized(w->decor_frame); -#else - xdg_toplevel_unset_maximized(w->xdg_toplevel); + if (use_libdecor) { + libdecor_frame_unset_maximized(w->libdecor->frame); + } + else #endif + { + xdg_toplevel_unset_maximized(w->xdg_decor->toplevel); + } break; - case GHOST_kWindowStateFullScreen: + } + case GHOST_kWindowStateFullScreen: { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_unset_fullscreen(w->decor_frame); -#else - xdg_toplevel_unset_fullscreen(w->xdg_toplevel); + if (use_libdecor) { + libdecor_frame_unset_fullscreen(w->libdecor->frame); + } + else #endif + { + xdg_toplevel_unset_fullscreen(w->xdg_decor->toplevel); + } break; - default: + } + default: { break; + } } break; - case GHOST_kWindowStateMaximized: + case GHOST_kWindowStateMaximized: { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_set_maximized(w->decor_frame); -#else - xdg_toplevel_set_maximized(w->xdg_toplevel); + if (use_libdecor) { + libdecor_frame_set_maximized(w->libdecor->frame); + } + else #endif + { + xdg_toplevel_set_maximized(w->xdg_decor->toplevel); + } break; - case GHOST_kWindowStateMinimized: + } + case GHOST_kWindowStateMinimized: { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_set_minimized(w->decor_frame); -#else - xdg_toplevel_set_minimized(w->xdg_toplevel); + if (use_libdecor) { + libdecor_frame_set_minimized(w->libdecor->frame); + } + else #endif + { + xdg_toplevel_set_minimized(w->xdg_decor->toplevel); + } break; - case GHOST_kWindowStateFullScreen: + } + case GHOST_kWindowStateFullScreen: { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_set_fullscreen(w->decor_frame, nullptr); -#else - xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr); + if (use_libdecor) { + libdecor_frame_set_fullscreen(w->libdecor->frame, nullptr); + } + else #endif + { + xdg_toplevel_set_fullscreen(w->xdg_decor->toplevel, nullptr); + } break; - case GHOST_kWindowStateEmbedded: + } + case GHOST_kWindowStateEmbedded: { return GHOST_kFailure; + } } return GHOST_kSuccess; } @@ -780,20 +851,29 @@ GHOST_TSuccess GHOST_WindowWayland::setOrder(GHOST_TWindowOrder /*order*/) GHOST_TSuccess GHOST_WindowWayland::beginFullScreen() const { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_set_fullscreen(w->decor_frame, nullptr); -#else - xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr); + if (use_libdecor) { + libdecor_frame_set_fullscreen(w->libdecor->frame, nullptr); + } + else #endif + { + xdg_toplevel_set_fullscreen(w->xdg_decor->toplevel, nullptr); + } + return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowWayland::endFullScreen() const { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_unset_fullscreen(w->decor_frame); -#else - xdg_toplevel_unset_fullscreen(w->xdg_toplevel); + if (use_libdecor) { + libdecor_frame_unset_fullscreen(w->libdecor->frame); + } + else #endif + { + xdg_toplevel_unset_fullscreen(w->xdg_decor->toplevel); + } return GHOST_kSuccess; } |