From 31943face83b8136716035db0cbc334881094baa Mon Sep 17 00:00:00 2001 From: falkTX Date: Fri, 5 Sep 2025 15:24:48 +0200 Subject: [PATCH] More wayland setup, dynamic x11 or wayland backend Signed-off-by: falkTX --- Makefile.base.mk | 7 +- dgl/src/ApplicationPrivateData.cpp | 1 - dgl/src/pugl-upstream | 2 +- dgl/src/pugl.cpp | 452 +++++++++++++++++++++++++---- dgl/src/pugl.hpp | 13 +- 5 files changed, 419 insertions(+), 56 deletions(-) diff --git a/Makefile.base.mk b/Makefile.base.mk index bb83799a..9ef802b1 100644 --- a/Makefile.base.mk +++ b/Makefile.base.mk @@ -409,7 +409,7 @@ HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true) HAVE_XCURSOR = $(shell $(PKG_CONFIG) --exists xcursor && echo true) HAVE_XEXT = $(shell $(PKG_CONFIG) --exists xext && echo true) HAVE_XRANDR = $(shell $(PKG_CONFIG) --exists xrandr && echo true) -HAVE_WAYLAND = $(shell $(PKG_CONFIG) --exists egl xkbcommon wayland-client wayland-egl wayland-protocols && echo true) +HAVE_WAYLAND = $(shell $(PKG_CONFIG) --exists egl xkbcommon wayland-client wayland-cursor wayland-egl && echo true) endif # Vulkan is not supported yet @@ -512,8 +512,8 @@ endif endif # HAVE_X11 ifeq ($(HAVE_WAYLAND),true) -DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xkbcommon wayland-client wayland-protocols) -DHAVE_WAYLAND -DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xkbcommon wayland-client wayland-protocols) +DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xkbcommon wayland-client wayland-cursor) -DHAVE_WAYLAND +DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xkbcommon wayland-client wayland-cursor) endif endif @@ -845,6 +845,7 @@ features: $(call print_available,HAVE_XCURSOR) $(call print_available,HAVE_XEXT) $(call print_available,HAVE_XRANDR) + $(call print_available,HAVE_WAYLAND) # --------------------------------------------------------------------------------------------------------------------- # Extra rules for MOD Audio stuff diff --git a/dgl/src/ApplicationPrivateData.cpp b/dgl/src/ApplicationPrivateData.cpp index 0e353a7e..dd66a7b6 100644 --- a/dgl/src/ApplicationPrivateData.cpp +++ b/dgl/src/ApplicationPrivateData.cpp @@ -71,7 +71,6 @@ Application::PrivateData::PrivateData(const bool standalone) #ifdef DGL_USING_SDL SDL_Init(SDL_INIT_EVENTS|SDL_INIT_TIMER|SDL_INIT_VIDEO); #else - puglSetWorldHandle(world, this); #ifdef __EMSCRIPTEN__ puglSetWorldString(world, PUGL_CLASS_NAME, "canvas"); #else diff --git a/dgl/src/pugl-upstream b/dgl/src/pugl-upstream index b30578a9..a9073cf3 160000 --- a/dgl/src/pugl-upstream +++ b/dgl/src/pugl-upstream @@ -1 +1 @@ -Subproject commit b30578a98abdf1b8c83cfd3eebf253533a09236b +Subproject commit a9073cf37169f0984b9604f88207ed48e0344fd2 diff --git a/dgl/src/pugl.cpp b/dgl/src/pugl.cpp index 21cade90..e66481d0 100644 --- a/dgl/src/pugl.cpp +++ b/dgl/src/pugl.cpp @@ -15,6 +15,7 @@ */ #include "pugl.hpp" +#include "pugl/pugl.h" // -------------------------------------------------------------------------------------------------------------------- // include base headers @@ -119,6 +120,8 @@ # include # include # include +# include "pugl-upstream/src/xdg-decoration.h" +# include "pugl-upstream/src/xdg-shell.h" # ifdef DGL_OPENGL # include # include @@ -213,7 +216,7 @@ START_NAMESPACE_DGL # ifdef DGL_VULKAN # include "pugl-upstream/src/win_vulkan.c" # endif -#elif defined(HAVE_X11) || defined(HAVE_WAYLAND) +#elif defined(DGL_USING_X11_OR_WAYLAND) # include "pugl-upstream/src/types.h" # ifdef HAVE_X11 # undef PUGL_PUGL_H @@ -253,11 +256,14 @@ struct PuglWorldInternalsImpl; # undef PUGL_PLATFORM_H # undef PUGL_SRC_STUB_H # undef PUGL_SRC_TYPES_H -// # include "pugl-upstream/src/xdg-shell.h" +END_NAMESPACE_DGL extern "C" { +# include "pugl-upstream/src/xdg-decoration.c" # include "pugl-upstream/src/xdg-shell.c" } -namespace wayland { +START_NAMESPACE_DGL +static const char kUsingWaylandCheck[] = "wl"; +namespace wl { struct PuglBackendImpl; struct PuglInternalsImpl; struct PuglViewImpl; @@ -283,7 +289,7 @@ struct PuglWorldInternalsImpl; # endif #endif -#if defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS) +#ifndef DGL_USING_X11_OR_WAYLAND # include "pugl-upstream/src/common.c" # include "pugl-upstream/src/internal.c" #endif @@ -309,7 +315,40 @@ bool puglBackendLeave(PuglView* const view) void puglSetMatchingBackendForCurrentBuild(PuglView* const view) { - #if (defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS)) + #ifdef DGL_USING_X11_OR_WAYLAND + if (view->world->handle == kUsingWaylandCheck) + { + #ifdef HAVE_WAYLAND + using namespace wl; + wl::PuglView* const wlview = reinterpret_cast(view); + #ifdef DGL_CAIRO + puglSetBackend(wlview, puglCairoBackend()); + #endif + #ifdef DGL_OPENGL + puglSetBackend(wlview, puglGlBackend()); + #endif + #ifdef DGL_VULKAN + puglSetBackend(wlview, puglVulkanBackend()); + #endif + #endif + } + else + { + #ifdef HAVE_X11 + using namespace x11; + x11::PuglView* const x11view = reinterpret_cast(view); + #ifdef DGL_CAIRO + puglSetBackend(x11view, puglCairoBackend()); + #endif + #ifdef DGL_OPENGL + puglSetBackend(x11view, puglGlBackend()); + #endif + #ifdef DGL_VULKAN + puglSetBackend(x11view, puglVulkanBackend()); + #endif + #endif + } + #else #ifdef DGL_CAIRO puglSetBackend(view, puglCairoBackend()); #endif @@ -319,19 +358,6 @@ void puglSetMatchingBackendForCurrentBuild(PuglView* const view) #ifdef DGL_VULKAN puglSetBackend(view, puglVulkanBackend()); #endif - #else - // const bool usingWayland = true; - const PuglBackend* (*puglStubBackend)(void) = nullptr; - // usingWayland ? wayland::puglStubBackend : x11::puglStubBackend; - #ifdef DGL_CAIRO - const PuglBackend* (*puglCairoBackend)(void) = nullptr; - #endif - #ifdef DGL_OPENGL - const PuglBackend* (*puglGlBackend)(void) = nullptr; - #endif - #ifdef DGL_VULKAN - const PuglBackend* (*puglVulkanBackend)(void) = nullptr; - #endif #endif if (view->backend != nullptr) @@ -356,7 +382,22 @@ void puglSetMatchingBackendForCurrentBuild(PuglView* const view) } else { + #ifdef DGL_USING_X11_OR_WAYLAND + if (view->world->handle == kUsingWaylandCheck) + { + #ifdef HAVE_WAYLAND + wl::puglSetBackend(reinterpret_cast(view), wl::puglStubBackend()); + #endif + } + else + { + #ifdef HAVE_X11 + x11::puglSetBackend(reinterpret_cast(view), x11::puglStubBackend()); + #endif + } + #else puglSetBackend(view, puglStubBackend()); + #endif } } @@ -377,9 +418,16 @@ void puglRaiseWindow(PuglView* const view) SetForegroundWindow(view->impl->hwnd); SetActiveWindow(view->impl->hwnd); #else - #ifdef HAVE_X11_NOT - XRaiseWindow(view->world->impl->display, view->impl->win); - #endif + if (view->world->handle == kUsingWaylandCheck) + { + } + else + { + #ifdef HAVE_X11 + x11::PuglView* const x11view = reinterpret_cast(view); + XRaiseWindow(x11view->world->impl->display, x11view->impl->win); + #endif + } #endif } @@ -417,15 +465,22 @@ PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, co #elif defined(DISTRHO_OS_WINDOWS) // nothing #else - #ifdef HAVE_X11_NOT - if (view->impl->win) + if (view->world->handle == kUsingWaylandCheck) { - if (const PuglStatus status = updateSizeHints(view)) - return status; + } + else + { + #ifdef HAVE_X11 + x11::PuglView* const x11view = reinterpret_cast(view); + if (x11view->impl->win) + { + if (const x11::PuglStatus status = x11::updateSizeHints(x11view)) + return static_cast(status); - XFlush(view->world->impl->display); + XFlush(x11view->world->impl->display); + } + #endif } - #endif #endif return PUGL_SUCCESS; @@ -457,9 +512,15 @@ void puglSetResizable(PuglView* const view, const bool resizable) SetWindowLong(hwnd, GWL_STYLE, winFlags); } #else - #ifdef HAVE_X11_NOT - updateSizeHints(view); - #endif + if (view->world->handle == kUsingWaylandCheck) + { + } + else + { + #ifdef HAVE_X11 + x11::updateSizeHints(reinterpret_cast(view)); + #endif + } #endif } @@ -497,20 +558,27 @@ PuglStatus puglSetSizeAndDefault(PuglView* const view, const uint width, const u puglBackendEnter(view); } #else - #ifdef HAVE_X11_NOT - // matches upstream pugl, adds flush at the end - if (view->impl->win) + if (view->world->handle == kUsingWaylandCheck) { - if (const PuglStatus status = updateSizeHints(view)) - return status; + } + else + { + #ifdef HAVE_X11 + // matches upstream pugl, adds flush at the end + x11::PuglView* const x11view = reinterpret_cast(view); + if (x11view->impl->win) + { + if (const x11::PuglStatus status = updateSizeHints(x11view)) + return static_cast(status); - if (const PuglStatus status = puglSetWindowSize(view, width, height)) - return status; + if (const x11::PuglStatus status = puglSetWindowSize(x11view, width, height)) + return static_cast(status); - // flush size changes - XFlush(view->world->impl->display); + // flush size changes + XFlush(x11view->world->impl->display); + } + #endif } - #endif #endif return PUGL_SUCCESS; @@ -692,32 +760,263 @@ void puglWin32ShowCentered(PuglView* const view) // -------------------------------------------------------------------------------------------------------------------- -#elif defined(HAVE_X11) || defined(HAVE_WAYLAND) +#elif defined(DGL_USING_X11_OR_WAYLAND) // -------------------------------------------------------------------------------------------------------------------- // X11 vs Wayland redirect +PuglStatus puglAcceptOffer(PuglView* const view, const PuglDataOfferEvent* const offer, const uint32_t typeIndex) +{ + #ifdef HAVE_WAYLAND + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglAcceptOffer(reinterpret_cast(view), + reinterpret_cast(offer), + typeIndex)); + #endif + return static_cast(x11::puglAcceptOffer(reinterpret_cast(view), + reinterpret_cast(offer), + typeIndex)); +} + +void puglFreeView(PuglView* const view) +{ + if (view->world->handle == kUsingWaylandCheck) + return wl::puglFreeView(reinterpret_cast(view)); + x11::puglFreeView(reinterpret_cast(view)); +} + void puglFreeViewInternals(PuglView* const view) { - return x11::puglFreeViewInternals(reinterpret_cast(view)); + if (view->world->handle == kUsingWaylandCheck) + return x11::puglFreeViewInternals(reinterpret_cast(view)); + x11::puglFreeViewInternals(reinterpret_cast(view)); +} + +void puglFreeWorld(PuglWorld* const world) +{ + if (world->handle == kUsingWaylandCheck) + return wl::puglFreeWorld(reinterpret_cast(world)); + x11::puglFreeWorld(reinterpret_cast(world)); +} + +const char* puglGetClipboardType(const PuglView* const view, const uint32_t typeIndex) +{ + if (view->world->handle == kUsingWaylandCheck) + return wl::puglGetClipboardType(reinterpret_cast(view), typeIndex); + return x11::puglGetClipboardType(reinterpret_cast(view), typeIndex); +} + +PuglHandle puglGetHandle(PuglView* const view) +{ + if (view->world->handle == kUsingWaylandCheck) + return wl::puglGetHandle(reinterpret_cast(view)); + return x11::puglGetHandle(reinterpret_cast(view)); +} + +uint32_t puglGetNumClipboardTypes(const PuglView* const view) +{ + if (view->world->handle == kUsingWaylandCheck) + return wl::puglGetNumClipboardTypes(reinterpret_cast(view)); + return x11::puglGetNumClipboardTypes(reinterpret_cast(view)); +} + +double puglGetScaleFactor(const PuglView* const view) +{ + if (view->world->handle == kUsingWaylandCheck) + return wl::puglGetScaleFactor(reinterpret_cast(view)); + return x11::puglGetScaleFactor(reinterpret_cast(view)); +} + +PuglArea puglGetSizeHint(const PuglView* const view, const PuglSizeHint hint) +{ + // FIXME + if (view->world->handle == kUsingWaylandCheck) + { + wl::PuglArea area = wl::puglGetSizeHint(reinterpret_cast(view), + static_cast(hint)); + return CPP_AGGREGATE_INIT(PuglArea){ area.width, area.height }; + } + x11::PuglArea area = x11::puglGetSizeHint(reinterpret_cast(view), + static_cast(hint)); + return CPP_AGGREGATE_INIT(PuglArea){ area.width, area.height }; +} + +PuglNativeView puglGetTransientParent(const PuglView* const view) +{ + if (view->world->handle == kUsingWaylandCheck) + return wl::puglGetTransientParent(reinterpret_cast(view)); + return x11::puglGetTransientParent(reinterpret_cast(view)); } -const char* puglGetWorldString(const PuglWorld* world, PuglStringHint key) +const char* puglGetWorldString(const PuglWorld* const world, const PuglStringHint key) { + if (world->handle == kUsingWaylandCheck) + return wl::puglGetWorldString(reinterpret_cast(world), + static_cast(key)); return x11::puglGetWorldString(reinterpret_cast(world), static_cast(key)); } -PuglStatus puglSetViewHint(PuglView* view, PuglViewHint hint, int value) +PuglStatus puglGrabFocus(PuglView* const view) +{ + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglGrabFocus(reinterpret_cast(view))); + return static_cast(x11::puglGrabFocus(reinterpret_cast(view))); +} + +PuglStatus puglHide(PuglView* const view) +{ + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglHide(reinterpret_cast(view))); + return static_cast(x11::puglHide(reinterpret_cast(view))); +} + +PuglStatus puglObscureView(PuglView* const view) +{ + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglObscureView(reinterpret_cast(view))); + return static_cast(x11::puglObscureView(reinterpret_cast(view))); +} + +PuglView* puglNewView(PuglWorld* const world) +{ + if (world->handle == kUsingWaylandCheck) + return reinterpret_cast(wl::puglNewView(reinterpret_cast(world))); + return reinterpret_cast(x11::puglNewView(reinterpret_cast(world))); +} + +PuglWorld* puglNewWorld(const PuglWorldType type, PuglWorldFlags flags) +{ + bool supportsDecorations = true; + #ifdef HAVE_WAYLAND + const bool usingWayland = puglWaylandStatus(&supportsDecorations); + #else + constexpr bool usingWayland = false; + #endif + d_stdout("Using wayland: %d, compositor supports decorations: %d", usingWayland, supportsDecorations); + + if (usingWayland) + { + if (wl::PuglWorld* const world = wl::puglNewWorld(static_cast(type), + static_cast(flags))) + { + wl::puglSetWorldHandle(world, const_cast(kUsingWaylandCheck)); + return reinterpret_cast(world); + } + return nullptr; + } + + return reinterpret_cast(x11::puglNewWorld(static_cast(type), + static_cast(flags))); +} + +PuglStatus puglRealize(PuglView* const view) +{ + #ifdef HAVE_WAYLAND + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglRealize(reinterpret_cast(view))); + #endif + return static_cast(x11::puglRealize(reinterpret_cast(view))); +} + +PuglStatus puglSetEventFunc(PuglView* const view, const PuglEventFunc eventFunc) +{ + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglSetEventFunc(reinterpret_cast(view), + reinterpret_cast(eventFunc))); + return static_cast(x11::puglSetEventFunc(reinterpret_cast(view), + reinterpret_cast(eventFunc))); +} + +void puglSetHandle(PuglView* const view, const PuglHandle handle) +{ + if (view->world->handle == kUsingWaylandCheck) + x11::puglSetHandle(reinterpret_cast(view), handle); + x11::puglSetHandle(reinterpret_cast(view), handle); +} + +PuglStatus puglSetParent(PuglView* const view, const PuglNativeView parent) +{ + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglSetParent(reinterpret_cast(view), parent)); + return static_cast(x11::puglSetParent(reinterpret_cast(view), parent)); +} + +PuglStatus puglSetPositionHint(PuglView* const view, const PuglPositionHint hint, const int x, const int y) { - return static_cast( - x11::puglSetViewHint(reinterpret_cast(view), static_cast(hint), value) - ); + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglSetPositionHint(reinterpret_cast(view), + static_cast(hint), + x, + y)); + return static_cast(x11::puglSetPositionHint(reinterpret_cast(view), + static_cast(hint), + x, + y)); } -// PodcastPluginsDGL::puglAcceptOffer -// PodcastPluginsDGL::puglGetHandle -// PodcastPluginsDGL::puglStopTimer +PuglStatus puglSetViewHint(PuglView* const view, const PuglViewHint hint, const int value) +{ + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglSetViewHint(reinterpret_cast(view), + static_cast(hint), + value)); + return static_cast(x11::puglSetViewHint(reinterpret_cast(view), + static_cast(hint), + value)); +} + +PuglStatus puglSetViewString(PuglView* const view, const PuglStringHint key, const char* const value) +{ + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglSetViewString(reinterpret_cast(view), + static_cast(key), + value)); + return static_cast(x11::puglSetViewString(reinterpret_cast(view), + static_cast(key), + value)); +} + +void puglSetWorldHandle(PuglWorld* const world, const PuglWorldHandle handle) +{ + if (world->handle == kUsingWaylandCheck) + return wl::puglSetWorldHandle(reinterpret_cast(world), handle); + x11::puglSetWorldHandle(reinterpret_cast(world), handle); +} + +PuglStatus puglSetWorldString(PuglWorld* const world, const PuglStringHint key, const char* const value) +{ + if (world->handle == kUsingWaylandCheck) + return static_cast(wl::puglSetWorldString(reinterpret_cast(world), + static_cast(key), + value)); + return static_cast(x11::puglSetWorldString(reinterpret_cast(world), + static_cast(key), + value)); +} + +PuglStatus puglShow(PuglView* const view, const PuglShowCommand command) +{ + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglShow(reinterpret_cast(view), + static_cast(command))); + return static_cast(x11::puglShow(reinterpret_cast(view), + static_cast(command))); +} + +PuglStatus puglStopTimer(PuglView* const view, const uintptr_t id) +{ + if (view->world->handle == kUsingWaylandCheck) + return static_cast(wl::puglStopTimer(reinterpret_cast(view), id)); + return static_cast(x11::puglStopTimer(reinterpret_cast(view), id)); +} + +PuglStatus puglUpdate(PuglWorld* const world, const double timeout) +{ + if (world->handle == kUsingWaylandCheck) + return static_cast(wl::puglUpdate(reinterpret_cast(world), timeout)); + return static_cast(x11::puglUpdate(reinterpret_cast(world), timeout)); +} #ifdef HAVE_X11 @@ -726,6 +1025,9 @@ PuglStatus puglSetViewHint(PuglView* view, PuglViewHint hint, int value) PuglStatus puglX11UpdateWithoutExposures(PuglWorld* const world) { + if (world->handle == kUsingWaylandCheck) + return PUGL_BACKEND_FAILED; + x11::PuglWorld* const x11world = reinterpret_cast(world); x11::PuglWorldInternals* const impl = x11world->impl; @@ -751,6 +1053,9 @@ PuglStatus puglX11UpdateWithoutExposures(PuglWorld* const world) void puglX11SetWindowType(const PuglView* const view, const bool isStandalone) { + if (view->world->handle == kUsingWaylandCheck) + return; + const x11::PuglView* const x11view = reinterpret_cast(view); const x11::PuglInternals* const impl = x11view->impl; Display* const display = x11view->world->impl->display; @@ -794,6 +1099,53 @@ void puglX11SetWindowType(const PuglView* const view, const bool isStandalone) #endif // HAVE_X11 +#ifdef HAVE_WAYLAND + +// -------------------------------------------------------------------------------------------------------------------- +// Wayland specific, check if running wayland and if compositor supports decorations + +static void wayland_compositor_test(void* const data, + struct wl_registry* const wl_registry, + const uint32_t name, + const char* const interface, + const uint32_t version) +{ + if (std::strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) + *static_cast(data) = wl_registry != NULL && name != 0 && version != 0; +} + +bool puglWaylandStatus(bool* supportsDecorations) +{ + static constexpr const struct wl_registry_listener wl_registry_listener = { + wayland_compositor_test, + nullptr, + }; + + bool supportsWayland = false; + *supportsDecorations = false; + + if (struct wl_display* const wl_display = wl_display_connect(nullptr)) + { + if (struct wl_registry* const wl_registry = wl_display_get_registry(wl_display)) + { + if (wl_registry_add_listener(wl_registry, &wl_registry_listener, supportsDecorations) == 0) + { + if (wl_display_roundtrip(wl_display) > 0) + // TODO also query required features + supportsWayland = true; + } + + wl_registry_destroy(wl_registry); + } + + wl_display_disconnect(wl_display); + } + + return supportsWayland; +} + +#endif // HAVE_WAYLAND + // -------------------------------------------------------------------------------------------------------------------- #endif diff --git a/dgl/src/pugl.hpp b/dgl/src/pugl.hpp index 125707af..a1e4b231 100644 --- a/dgl/src/pugl.hpp +++ b/dgl/src/pugl.hpp @@ -114,8 +114,11 @@ void puglWin32RestoreWindow(PuglView* view); // win32 specific, center view based on parent coordinates (if there is one) void puglWin32ShowCentered(PuglView* view); -#elif defined(HAVE_X11) +#else + +#define DGL_USING_X11_OR_WAYLAND +#ifdef HAVE_X11 #define DGL_USING_X11 // X11 specific, update world without triggering exposure events @@ -123,6 +126,14 @@ PuglStatus puglX11UpdateWithoutExposures(PuglWorld* world); // X11 specific, set dialog window type void puglX11SetWindowType(const PuglView* view, bool isStandalone); +#endif + +#ifdef HAVE_WAYLAND +#define DGL_USING_WAYLAND + +// Wayland specific, return if running wayland and check if compositor supports decorations +bool puglWaylandStatus(bool* supportsDecorations); +#endif #endif