diff --git a/dgl/Application.hpp b/dgl/Application.hpp index c028b53c..935e5d50 100644 --- a/dgl/Application.hpp +++ b/dgl/Application.hpp @@ -83,10 +83,22 @@ BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_off) class DISTRHO_API Application { public: + /** + Type of application to setup, either "classic" or "modern". + + What this means depends on the OS. + For now it's only relevant on X11 vs Wayland systems, where X11 is kTypeClassic and Wayland is kTypeModern. + */ + enum Type { + kTypeAuto, + kTypeClassic, + kTypeModern, + }; + /** Constructor for standalone or plugin application. */ - Application(bool isStandalone = true); + Application(bool isStandalone = true, Type type = kTypeAuto); /** Constructor for a standalone application. @@ -141,6 +153,12 @@ public: */ double getTime() const; + /** + Return the application type, either kTypeClassic or kTypeModern. + This function never return kTypeAuto. + */ + Type getType() const noexcept; + /** Add a callback function to be triggered on every idle cycle. You can add more than one, and remove them at anytime with removeIdleCallback(). diff --git a/dgl/src/Application.cpp b/dgl/src/Application.cpp index 09f57e1e..705b10fb 100644 --- a/dgl/src/Application.cpp +++ b/dgl/src/Application.cpp @@ -98,8 +98,8 @@ static void app_idle(void* const app) } #endif -Application::Application(const bool isStandalone) - : pData(new PrivateData(isStandalone)) +Application::Application(const bool isStandalone, const Type type) + : pData(new PrivateData(isStandalone, type)) { // build config sentinels #ifdef DPF_DEBUG @@ -126,7 +126,7 @@ Application::Application(const bool isStandalone) } Application::Application(int argc, char* argv[]) - : pData(new PrivateData(true)) + : pData(new PrivateData(true, kTypeAuto)) { #if defined(HAVE_X11) && defined(DISTRHO_OS_LINUX) && defined(DGL_USE_WEB_VIEW) if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0) @@ -213,6 +213,11 @@ double Application::getTime() const return pData->getTime(); } +Application::Type Application::getType() const noexcept +{ + return pData->isModern ? kTypeModern : kTypeClassic; +} + void Application::addIdleCallback(IdleCallback* const callback) { DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) diff --git a/dgl/src/ApplicationPrivateData.cpp b/dgl/src/ApplicationPrivateData.cpp index dd66a7b6..7d5e9209 100644 --- a/dgl/src/ApplicationPrivateData.cpp +++ b/dgl/src/ApplicationPrivateData.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2024 Filipe Coelho + * Copyright (C) 2012-2025 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -53,13 +53,28 @@ const char* Application::getClassName() const noexcept // -------------------------------------------------------------------------------------------------------------------- -Application::PrivateData::PrivateData(const bool standalone) +static constexpr inline uint32_t AppTypePuglWorldFlags(Application::Type type) noexcept +{ + #ifdef DGL_USING_X11_OR_WAYLAND + return type == Application::kTypeClassic ? PUGL_WORLD_BACKEND_X11 : + type == Application::kTypeModern ? PUGL_WORLD_BACKEND_WAYLAND : 0; + #else + return 0; + #endif +} + +Application::PrivateData::PrivateData(const bool standalone, const Type type) : world(puglNewWorld(standalone ? PUGL_PROGRAM : PUGL_MODULE, - standalone ? PUGL_WORLD_THREADS : 0x0)), + (standalone ? PUGL_WORLD_THREADS : 0) | AppTypePuglWorldFlags(type))), + #ifdef DGL_USING_X11_OR_WAYLAND + isModern(world != nullptr && puglUsingWayland(world)), + #else + isModern(false), + #endif isStandalone(standalone), + isStarting(true), isQuitting(false), isQuittingInNextCycle(false), - isStarting(true), needsRepaint(false), visibleWindows(0), mainThreadHandle(getCurrentThreadHandle()), @@ -68,15 +83,11 @@ Application::PrivateData::PrivateData(const bool standalone) { DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,); - #ifdef DGL_USING_SDL - SDL_Init(SDL_INIT_EVENTS|SDL_INIT_TIMER|SDL_INIT_VIDEO); - #else #ifdef __EMSCRIPTEN__ puglSetWorldString(world, PUGL_CLASS_NAME, "canvas"); #else puglSetWorldString(world, PUGL_CLASS_NAME, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE)); #endif - #endif } Application::PrivateData::~PrivateData() @@ -87,12 +98,8 @@ Application::PrivateData::~PrivateData() windows.clear(); idleCallbacks.clear(); - #ifdef DGL_USING_SDL - SDL_Quit(); - #else if (world != nullptr) puglFreeWorld(world); - #endif } // -------------------------------------------------------------------------------------------------------------------- diff --git a/dgl/src/ApplicationPrivateData.hpp b/dgl/src/ApplicationPrivateData.hpp index 59afaae3..b5ef6621 100644 --- a/dgl/src/ApplicationPrivateData.hpp +++ b/dgl/src/ApplicationPrivateData.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2025 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -51,18 +51,21 @@ struct Application::PrivateData { /** Pugl world instance. */ PuglWorld* const world; + /** Whether the applicating uses modern backend, otherwise classic. */ + const bool isModern; + /** Whether the application is running as standalone, otherwise it is part of a plugin. */ const bool isStandalone; + /** Whether the applicating is starting up, that is, no windows have been made visible yet. Defaults to true. */ + bool isStarting; + /** Whether the applicating is about to quit, or already stopped. Defaults to false. */ bool isQuitting; /** Helper for safely close everything from main thread. */ bool isQuittingInNextCycle; - /** Whether the applicating is starting up, that is, no windows have been made visible yet. Defaults to true. */ - bool isStarting; - /** When true force all windows to be repainted on next idle. */ bool needsRepaint; @@ -80,7 +83,7 @@ struct Application::PrivateData { std::list idleCallbacks; /** Constructor and destructor */ - explicit PrivateData(bool standalone); + explicit PrivateData(bool standalone, Type type); ~PrivateData(); /** Flag one window as shown, which increments @a visibleWindows. diff --git a/dgl/src/pugl.cpp b/dgl/src/pugl.cpp index cb582873..87641764 100644 --- a/dgl/src/pugl.cpp +++ b/dgl/src/pugl.cpp @@ -966,32 +966,85 @@ PuglInternals* puglInitViewInternals(PuglWorld* const world) PuglWorldInternals* puglInitWorldInternals(PuglWorld* const world, const PuglWorldType type, const 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); + bool usingWayland = false; + bool usingX11 = false; + + // initial choice by env var + if (const char* const backend = std::getenv("DPF_BACKEND")) + { + if (std::strcmp(backend, "x11") == 0) + usingX11 = true; + else if (std::strcmp(backend, "wayland") != 0) + usingWayland = true; + else + d_stderr("Unknown DPF_BACKEND value, must be 'x11' or 'wayland'"); + } + + // overridden if required for operation + if (flags & PUGL_WORLD_BACKEND_X11) + { + usingX11 = true; + usingWayland = false; + } + if (flags & PUGL_WORLD_BACKEND_WAYLAND) + { + usingX11 = false; + usingWayland = true; + #ifdef HAVE_WAYLAND + puglWaylandStatus(&supportsDecorations); + #endif + } + + // pick backend automatically if none selected + if (! (usingX11 || usingWayland)) + { + #ifdef HAVE_WAYLAND + usingWayland = puglWaylandStatus(&supportsDecorations); + if (! usingWayland) + #endif + { + #ifdef HAVE_X11 + supportsDecorations = true; + usingX11 = true; + #endif + } + + if (! (usingX11 || usingWayland)) + { + d_stderr("Could not find a usable windowing backend"); + return nullptr; + } + } + + if (usingX11) + { + #ifdef HAVE_X11 + d_stdout("Using X11"); + x11::PuglWorld* const x11world = cast(world); + x11::puglSetWorldHandle(x11world, const_cast(kUsingX11Check)); + return cast(x11::puglInitWorldInternals(x11world, + static_cast(type), + static_cast(flags))); + #else + return nullptr; + #endif + } - #ifdef HAVE_WAYLAND if (usingWayland) { + #ifdef HAVE_WAYLAND + d_stdout("Using Wayland, compositor supports decorations: %s", supportsDecorations ? "true" : "false"); wl::PuglWorld* const wlworld = cast(world); wl::puglSetWorldHandle(wlworld, const_cast(kUsingWaylandCheck)); return cast(wl::puglInitWorldInternals(wlworld, static_cast(type), static_cast(flags))); + #else + return nullptr; + #endif } - #endif - #ifdef HAVE_X11 - x11::PuglWorld* const x11world = cast(world); - x11::puglSetWorldHandle(x11world, const_cast(kUsingX11Check)); - return cast(x11::puglInitWorldInternals(x11world, - static_cast(type), - static_cast(flags))); - #else + return nullptr; - #endif } @@ -1182,6 +1235,14 @@ PuglStatus puglViewStringChanged(PuglView* const view, const PuglStringHint key, return PUGL_BAD_BACKEND; } +// -------------------------------------------------------------------------------------------------------------------- +// X11 or Wayland specific, check if using wayland + +bool puglUsingWayland(PuglWorld* const world) +{ + return world->handle == kUsingWaylandCheck; +} + #ifdef HAVE_X11 // -------------------------------------------------------------------------------------------------------------------- @@ -1288,18 +1349,6 @@ bool puglWaylandStatus(bool* supportsDecorations) bool supportsWayland = false; *supportsDecorations = false; - if (const char* const backend = std::getenv("DPF_BACKEND")) - { - if (std::strcmp(backend, "x11") == 0) - return false; - - if (std::strcmp(backend, "wayland") != 0) - { - d_stderr2("Unknown DPF_BACKEND value, will use X11"); - return 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)) diff --git a/dgl/src/pugl.hpp b/dgl/src/pugl.hpp index a1e4b231..2ea81fda 100644 --- a/dgl/src/pugl.hpp +++ b/dgl/src/pugl.hpp @@ -118,6 +118,13 @@ void puglWin32ShowCentered(PuglView* view); #define DGL_USING_X11_OR_WAYLAND +// custom flags for world creation +#define PUGL_WORLD_BACKEND_X11 0x1000 +#define PUGL_WORLD_BACKEND_WAYLAND 0x2000 + +// X11 or Wayland specific, check if using wayland +bool puglUsingWayland(PuglWorld* world); + #ifdef HAVE_X11 #define DGL_USING_X11