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.
This commit is contained in:
Campbell Barton 2022-10-12 16:54:31 +11:00
parent 0f60872461
commit f0e1089a33
Notes: blender-bot 2023-02-13 14:16:34 +01:00
Referenced by issue #101779, Incorrect call to set_app_id on Wayland
Referenced by issue #101781, Geometry Node: Undo crash: Copy, paste, undo and repeat a lot of time
5 changed files with 371 additions and 193 deletions

View File

@ -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(

View File

@ -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 {

View File

@ -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, &registry_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,25 +4139,27 @@ wl_compositor *GHOST_SystemWayland::compositor()
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
libdecor *GHOST_SystemWayland::decor_context()
libdecor *GHOST_SystemWayland::libdecor_context()
{
return d->decor_context;
}
#else /* WITH_GHOST_WAYLAND_LIBDECOR */
xdg_wm_base *GHOST_SystemWayland::xdg_shell()
{
return d->xdg_shell;
}
zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decoration_manager()
{
return d->xdg_decoration_manager;
GHOST_ASSERT(use_libdecor, "X");
GHOST_ASSERT(d->libdecor != nullptr, "X");
return d->libdecor->context;
}
#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
xdg_wm_base *GHOST_SystemWayland::xdg_decor_shell()
{
return d->xdg_decor->shell;
}
zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decor_manager()
{
return d->xdg_decor->manager;
}
/* End `xdg_decor`. */
const std::vector<GWL_Output *> &GHOST_SystemWayland::outputs() const
{
return d->outputs;
@ -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 */
/** \} */

View File

@ -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;

View File

@ -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);
libdecor_frame_set_min_content_size(decor.frame, UNPACK2(size_min));
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
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);
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(w->xdg_toplevel, UNPACK2(size_min));
xdg_toplevel_set_min_size(decor.toplevel, 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 (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(decor.surface, &xdg_surface_listener, w);
xdg_toplevel_add_listener(decor.toplevel, &toplevel_listener, w);
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);
}
}
xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
if (parentWindow && is_dialog) {
xdg_toplevel_set_parent(
w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_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;
}