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:
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
|
@ -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(
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,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 */
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue