Signed-off-by: falkTX <falktx@falktx.com>wayland
| @@ -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(). | |||
| @@ -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,) | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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 | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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<DGL_NAMESPACE::IdleCallback*> idleCallbacks; | |||
| /** Constructor and destructor */ | |||
| explicit PrivateData(bool standalone); | |||
| explicit PrivateData(bool standalone, Type type); | |||
| ~PrivateData(); | |||
| /** Flag one window as shown, which increments @a visibleWindows. | |||
| @@ -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<x11::PuglWorld>(world); | |||
| x11::puglSetWorldHandle(x11world, const_cast<char*>(kUsingX11Check)); | |||
| return cast<PuglWorldInternals>(x11::puglInitWorldInternals(x11world, | |||
| static_cast<x11::PuglWorldType>(type), | |||
| static_cast<x11::PuglWorldFlags>(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<wl::PuglWorld>(world); | |||
| wl::puglSetWorldHandle(wlworld, const_cast<char*>(kUsingWaylandCheck)); | |||
| return cast<PuglWorldInternals>(wl::puglInitWorldInternals(wlworld, | |||
| static_cast<wl::PuglWorldType>(type), | |||
| static_cast<wl::PuglWorldFlags>(flags))); | |||
| #else | |||
| return nullptr; | |||
| #endif | |||
| } | |||
| #endif | |||
| #ifdef HAVE_X11 | |||
| x11::PuglWorld* const x11world = cast<x11::PuglWorld>(world); | |||
| x11::puglSetWorldHandle(x11world, const_cast<char*>(kUsingX11Check)); | |||
| return cast<PuglWorldInternals>(x11::puglInitWorldInternals(x11world, | |||
| static_cast<x11::PuglWorldType>(type), | |||
| static_cast<x11::PuglWorldFlags>(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)) | |||
| @@ -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 | |||