Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt5
-rw-r--r--build_files/cmake/platform/platform_unix.cmake11
-rw-r--r--intern/ghost/CMakeLists.txt25
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp63
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h13
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp163
6 files changed, 266 insertions, 14 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 31608b0c1ce..60d980930c1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -222,6 +222,11 @@ if(UNIX AND NOT (APPLE OR HAIKU))
option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing (under development)" OFF)
mark_as_advanced(WITH_GHOST_WAYLAND)
+
+ if (WITH_GHOST_WAYLAND)
+ option(WITH_GHOST_WAYLAND_LIBDECOR "Optionally build with LibDecor window decorations" OFF)
+ mark_as_advanced(WITH_GHOST_WAYLAND_LIBDECOR)
+ endif()
endif()
if(WITH_GHOST_X11)
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index 6750c23d548..781e2798fea 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -615,6 +615,10 @@ if(WITH_GHOST_WAYLAND)
pkg_check_modules(wayland-cursor REQUIRED wayland-cursor)
pkg_check_modules(dbus REQUIRED dbus-1)
+ if(WITH_GHOST_WAYLAND_LIBDECOR)
+ pkg_check_modules(libdecor REQUIRED libdecor-0>=0.1)
+ endif()
+
set(WITH_GL_EGL ON)
list(APPEND PLATFORM_LINKLIBS
@@ -624,6 +628,13 @@ if(WITH_GHOST_WAYLAND)
${wayland-cursor_LINK_LIBRARIES}
${dbus_LINK_LIBRARIES}
)
+
+ if(WITH_GHOST_WAYLAND_LIBDECOR)
+ list(APPEND PLATFORM_LINKLIBS
+ ${libdecor_LIBRARIES}
+ )
+ add_definitions(-DWITH_GHOST_WAYLAND_LIBDECOR)
+ endif()
endif()
if(WITH_GHOST_X11)
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 945b3261562..150bcb9273e 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -271,6 +271,12 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
${dbus_INCLUDE_DIRS}
)
+ if(WITH_GHOST_WAYLAND_LIBDECOR)
+ list(APPEND INC_SYS
+ ${libdecor_INCLUDE_DIRS}
+ )
+ endif()
+
include(CheckSymbolExists)
set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE")
check_symbol_exists(memfd_create "sys/mman.h" HAVE_MEMFD_CREATE)
@@ -332,14 +338,17 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
${INC_DST}
)
- # `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"
- )
+ 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()
+
# `xdg-output`.
generate_protocol_bindings(
"${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-output/xdg-output-unstable-v1.xml"
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 8e3ca59cc74..66d0902c0ca 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -254,8 +254,14 @@ struct display_t {
struct wl_display *display = nullptr;
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;
+#endif
+
struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
struct wl_shm *shm = nullptr;
std::vector<output_t *> outputs;
@@ -402,6 +408,11 @@ static void display_destroy(display_t *d)
wl_compositor_destroy(d->compositor);
}
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ if (d->decor_context) {
+ libdecor_unref(d->decor_context);
+ }
+#else
if (d->xdg_decoration_manager) {
zxdg_decoration_manager_v1_destroy(d->xdg_decoration_manager);
}
@@ -409,6 +420,7 @@ static void display_destroy(display_t *d)
if (d->xdg_shell) {
xdg_wm_base_destroy(d->xdg_shell);
}
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
if (eglGetDisplay) {
::eglTerminate(eglGetDisplay(EGLNativeDisplayType(d->display)));
@@ -2190,6 +2202,8 @@ static const struct wl_output_listener output_listener = {
/** \name Listener (XDG WM Base), #xdg_wm_base_listener
* \{ */
+#ifndef WITH_GHOST_WAYLAND_LIBDECOR
+
static void shell_handle_ping(void * /*data*/,
struct xdg_wm_base *xdg_wm_base,
const uint32_t serial)
@@ -2201,6 +2215,32 @@ static const struct xdg_wm_base_listener shell_listener = {
shell_handle_ping,
};
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (LibDecor), #libdecor_interface
+ * \{ */
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+
+static void decor_handle_error(struct libdecor * /*context*/,
+ enum libdecor_error error,
+ const char *message)
+{
+ (void)(error);
+ (void)(message);
+ GHOST_PRINT("decoration error (" << error << "): " << message << std::endl);
+ exit(EXIT_FAILURE);
+}
+
+static struct libdecor_interface libdecor_interface = {
+ decor_handle_error,
+};
+
+#endif /* WITH_GHOST_WAYLAND_LIBDECOR. */
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2218,6 +2258,9 @@ 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 (!strcmp(interface, xdg_wm_base_interface.name)) {
display->xdg_shell = static_cast<xdg_wm_base *>(
wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1));
@@ -2227,6 +2270,7 @@ static void global_handle_add(void *data,
display->xdg_decoration_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 (!strcmp(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, 3));
@@ -2330,10 +2374,18 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t)
wl_display_roundtrip(d->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!");
+ }
+#else
if (!d->xdg_shell) {
display_destroy(d);
throw std::runtime_error("Wayland: unable to access xdg_shell!");
}
+#endif
/* Register data device per seat for IPC between Wayland clients. */
if (d->data_device_manager) {
@@ -2667,6 +2719,15 @@ wl_compositor *GHOST_SystemWayland::compositor()
return d->compositor;
}
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+
+libdecor *GHOST_SystemWayland::decor_context()
+{
+ return d->decor_context;
+}
+
+#else /* WITH_GHOST_WAYLAND_LIBDECOR */
+
xdg_wm_base *GHOST_SystemWayland::xdg_shell()
{
return d->xdg_shell;
@@ -2677,6 +2738,8 @@ zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decoration_manager()
return d->xdg_decoration_manager;
}
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
+
const std::vector<output_t *> &GHOST_SystemWayland::outputs() const
{
return d->outputs;
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index 4b953dccac6..972d16257eb 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -13,9 +13,13 @@
#include <wayland-client.h>
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+# include <libdecor.h>
+#else
/* Generated by `wayland-scanner`. */
-#include <xdg-decoration-unstable-v1-client-protocol.h>
-#include <xdg-shell-client-protocol.h>
+# include <xdg-decoration-unstable-v1-client-protocol.h>
+# include <xdg-shell-client-protocol.h>
+#endif
#include <string>
@@ -103,9 +107,12 @@ 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();
+#endif
const std::vector<output_t *> &outputs() const;
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index afaa2e11aa7..bd11476b2e2 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -18,6 +18,10 @@
#include <algorithm> /* For `std::find`. */
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+# include <libdecor.h>
+#endif
+
static constexpr size_t base_dpi = 96;
struct window_t {
@@ -41,10 +45,17 @@ struct window_t {
*/
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 xdg_toplevel *xdg_toplevel = 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;
+#endif
+
wl_egl_window *egl_window = nullptr;
bool is_maximised = false;
bool is_fullscreen = false;
@@ -121,6 +132,8 @@ static int outputs_max_scale_or_default(const std::vector<output_t *> &outputs,
/** \name Listener (XDG Top Level), #xdg_toplevel_listener
* \{ */
+#ifndef WITH_GHOST_WAYLAND_LIBDECOR
+
static void xdg_toplevel_handle_configure(void *data,
xdg_toplevel * /*xdg_toplevel*/,
const int32_t width,
@@ -163,12 +176,83 @@ static const xdg_toplevel_listener toplevel_listener = {
xdg_toplevel_handle_close,
};
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (LibDecor Frame), #libdecor_frame_interface
+ * \{ */
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+
+static void frame_handle_configure(struct libdecor_frame *frame,
+ struct libdecor_configuration *configuration,
+ void *data)
+{
+ window_t *win = static_cast<window_t *>(data);
+
+ int size_next[2];
+ enum libdecor_window_state window_state;
+ struct libdecor_state *state;
+
+ if (!libdecor_configuration_get_content_size(
+ configuration, frame, &size_next[0], &size_next[1])) {
+ size_next[0] = win->size[0] / win->scale;
+ size_next[1] = win->size[1] / win->scale;
+ }
+
+ win->size[0] = win->scale * size_next[0];
+ win->size[1] = win->scale * size_next[1];
+
+ wl_egl_window_resize(win->egl_window, win->size[0], win->size[1], 0, 0);
+ win->w->notify_size();
+
+ if (!libdecor_configuration_get_window_state(configuration, &window_state)) {
+ window_state = LIBDECOR_WINDOW_STATE_NONE;
+ }
+
+ win->is_maximised = window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED;
+ win->is_fullscreen = window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN;
+ win->is_active = window_state & LIBDECOR_WINDOW_STATE_ACTIVE;
+
+ win->is_active ? win->w->activate() : win->w->deactivate();
+
+ state = libdecor_state_new(size_next[0], size_next[1]);
+ libdecor_frame_commit(frame, state, configuration);
+ libdecor_state_free(state);
+
+ win->decor_configured = true;
+}
+
+static void frame_handle_close(struct libdecor_frame * /*frame*/, void *data)
+{
+ static_cast<window_t *>(data)->w->close();
+}
+
+static void frame_handle_commit(struct libdecor_frame * /*frame*/, void *data)
+{
+ /* we have to swap twice to keep any pop-up menues alive */
+ static_cast<window_t *>(data)->w->swapBuffers();
+ static_cast<window_t *>(data)->w->swapBuffers();
+}
+
+static struct libdecor_frame_interface libdecor_frame_iface = {
+ frame_handle_configure,
+ frame_handle_close,
+ frame_handle_commit,
+};
+
+#endif /* WITH_GHOST_WAYLAND_LIBDECOR. */
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Listener (XDG Decoration Listener), #zxdg_toplevel_decoration_v1_listener
* \{ */
+#ifndef WITH_GHOST_WAYLAND_LIBDECOR
+
static void xdg_toplevel_decoration_handle_configure(
void *data,
struct zxdg_toplevel_decoration_v1 * /*zxdg_toplevel_decoration_v1*/,
@@ -181,12 +265,16 @@ static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listene
xdg_toplevel_decoration_handle_configure,
};
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Listener (XDG Surface Handle Configure), #xdg_surface_listener
* \{ */
+#ifndef WITH_GHOST_WAYLAND_LIBDECOR
+
static void xdg_surface_handle_configure(void *data,
xdg_surface *xdg_surface,
const uint32_t serial)
@@ -220,6 +308,8 @@ static const xdg_surface_listener xdg_surface_listener = {
xdg_surface_handle_configure,
};
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -316,6 +406,19 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
w->egl_window = wl_egl_window_create(w->wl_surface, int(w->size[0]), int(w->size[1]));
+#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 (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);
@@ -334,8 +437,6 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
- wl_surface_set_user_data(w->wl_surface, this);
-
xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
@@ -344,15 +445,31 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel);
}
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
+
+ wl_surface_set_user_data(w->wl_surface, this);
+
/* Call top-level callbacks. */
wl_surface_commit(w->wl_surface);
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;
+ }
+ }
+#endif
+
#ifdef GHOST_OPENGL_ALPHA
setOpaque();
#endif
+#ifndef WITH_GHOST_WAYLAND_LIBDECOR /* Causes a glicth with libdecor for some reason. */
setState(state);
+#endif
setTitle(title);
@@ -512,8 +629,14 @@ 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);
+#endif
+
this->title = title;
}
@@ -581,11 +704,17 @@ GHOST_WindowWayland::~GHOST_WindowWayland()
releaseNativeHandles();
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);
}
xdg_toplevel_destroy(w->xdg_toplevel);
xdg_surface_destroy(w->xdg_surface);
+#endif
+
wl_surface_destroy(w->wl_surface);
/* NOTE(@campbellbarton): This is needed so the appropriate handlers event
@@ -622,23 +751,43 @@ GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state)
/* Unset states. */
switch (getState()) {
case GHOST_kWindowStateMaximized:
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_unset_maximized(w->decor_frame);
+#else
xdg_toplevel_unset_maximized(w->xdg_toplevel);
+#endif
break;
case GHOST_kWindowStateFullScreen:
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_unset_fullscreen(w->decor_frame);
+#else
xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
+#endif
break;
default:
break;
}
break;
case GHOST_kWindowStateMaximized:
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_set_maximized(w->decor_frame);
+#else
xdg_toplevel_set_maximized(w->xdg_toplevel);
+#endif
break;
case GHOST_kWindowStateMinimized:
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_set_minimized(w->decor_frame);
+#else
xdg_toplevel_set_minimized(w->xdg_toplevel);
+#endif
break;
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);
+#endif
break;
case GHOST_kWindowStateEmbedded:
return GHOST_kFailure;
@@ -669,13 +818,21 @@ 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);
+#endif
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);
+#endif
return GHOST_kSuccess;
}