Signed-off-by: falkTX <falktx@falktx.com>pull/507/head
| @@ -83,10 +83,21 @@ 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. | |||
| */ | |||
| 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 +152,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,14 @@ const char* Application::getClassName() const noexcept | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| Application::PrivateData::PrivateData(const bool standalone) | |||
| 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))), | |||
| isModern(false), | |||
| isStandalone(standalone), | |||
| isStarting(true), | |||
| isQuitting(false), | |||
| isQuittingInNextCycle(false), | |||
| isStarting(true), | |||
| needsRepaint(false), | |||
| visibleWindows(0), | |||
| mainThreadHandle(getCurrentThreadHandle()), | |||
| @@ -68,16 +69,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 | |||
| puglSetWorldHandle(world, this); | |||
| #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() | |||
| @@ -88,12 +84,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. | |||
| @@ -286,7 +286,7 @@ public: | |||
| #else | |||
| UIExporter tmpUI(nullptr, 0, fPlugin.getSampleRate(), | |||
| nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | |||
| fPlugin.getInstancePointer(), scaleFactor); | |||
| fPlugin.getInstancePointer(), scaleFactor, DGL_NAMESPACE::Application::kTypeClassic); | |||
| *width = tmpUI.getWidth(); | |||
| *height = tmpUI.getHeight(); | |||
| scaleFactor = tmpUI.getScaleFactor(); | |||
| @@ -584,7 +584,8 @@ private: | |||
| nullptr, // TODO fileRequestCallback, | |||
| d_nextBundlePath, | |||
| fPlugin.getInstancePointer(), | |||
| fScaleFactor); | |||
| fScaleFactor, | |||
| DGL_NAMESPACE::Application::kTypeClassic); | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| fUI->programLoaded(fCurrentProgram); | |||
| @@ -175,7 +175,8 @@ public: | |||
| nullptr, // TODO file request | |||
| d_nextBundlePath, | |||
| plugin->getInstancePointer(), | |||
| scaleFactor), | |||
| scaleFactor, | |||
| DGL_NAMESPACE::Application::kTypeClassic), | |||
| fKeyboardModifiers(0) | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| , fNotesRingBuffer() | |||
| @@ -600,7 +601,7 @@ public: | |||
| #else | |||
| UIExporter tmpUI(nullptr, 0, fPlugin.getSampleRate(), | |||
| nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | |||
| fPlugin.getInstancePointer(), scaleFactor); | |||
| fPlugin.getInstancePointer(), scaleFactor, DGL_NAMESPACE::Application::kTypeClassic); | |||
| fVstRect.right = tmpUI.getWidth(); | |||
| fVstRect.bottom = tmpUI.getHeight(); | |||
| scaleFactor = tmpUI.getScaleFactor(); | |||
| @@ -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 | |||
| @@ -21,18 +21,18 @@ | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // UI exporter class | |||
| class UIExporter | |||
| { | |||
| // ------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| // UI Widget and its private data | |||
| UI* ui; | |||
| UI::PrivateData* uiData; | |||
| // ------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| public: | |||
| UIExporter(void* const callbacksPtr, | |||
| @@ -47,11 +47,12 @@ public: | |||
| const char* const bundlePath = nullptr, | |||
| void* const dspPtr = nullptr, | |||
| const double scaleFactor = 0.0, | |||
| const DGL_NAMESPACE::Application::Type appType = DGL_NAMESPACE::Application::kTypeAuto, | |||
| const uint32_t bgColor = 0, | |||
| const uint32_t fgColor = 0xffffffff, | |||
| const char* const appClassName = nullptr) | |||
| : ui(nullptr), | |||
| uiData(new UI::PrivateData(appClassName)) | |||
| uiData(new UI::PrivateData(appClassName, appType)) | |||
| { | |||
| uiData->sampleRate = sampleRate; | |||
| uiData->bundlePath = bundlePath != nullptr ? strdup(bundlePath) : nullptr; | |||
| @@ -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 | |||
| @@ -52,7 +52,7 @@ static constexpr const sendNoteFunc sendNoteCallback = nullptr; | |||
| // unwanted in LV2, resize extension is deprecated and hosts can do it without extensions | |||
| static constexpr const setSizeFunc setSizeCallback = nullptr; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| template <class LV2F> | |||
| static const LV2F* getLv2Feature(const LV2_Feature* const* features, const char* const uri) | |||
| @@ -80,6 +80,7 @@ public: | |||
| void* const dspPtr, | |||
| const float sampleRate, | |||
| const float scaleFactor, | |||
| const DGL_NAMESPACE::Application::Type appType, | |||
| const uint32_t bgColor, | |||
| const uint32_t fgColor, | |||
| const char* const appClassName) | |||
| @@ -101,7 +102,7 @@ public: | |||
| sendNoteCallback, | |||
| setSizeCallback, | |||
| fileRequestCallback, | |||
| bundlePath, dspPtr, scaleFactor, bgColor, fgColor, appClassName) | |||
| bundlePath, dspPtr, scaleFactor, appType, bgColor, fgColor, appClassName) | |||
| { | |||
| if (widget != nullptr) | |||
| *widget = (LV2UI_Widget)fUI.getNativeWindowHandle(); | |||
| @@ -483,7 +484,7 @@ private: | |||
| } | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, | |||
| const char* const uri, | |||
| @@ -499,6 +500,9 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, | |||
| return nullptr; | |||
| } | |||
| // TODO allow classic vs modern ui type | |||
| static constexpr const DGL_NAMESPACE::Application::Type appType = DGL_NAMESPACE::Application::kTypeClassic; | |||
| const LV2_Options_Option* options = nullptr; | |||
| const LV2_URID_Map* uridMap = nullptr; | |||
| void* parentId = nullptr; | |||
| @@ -633,7 +637,7 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, | |||
| return new UiLv2(bundlePath, winId, options, uridMap, features, | |||
| controller, writeFunction, widget, instance, | |||
| sampleRate, scaleFactor, bgColor, fgColor, appClassName); | |||
| sampleRate, scaleFactor, appType, bgColor, fgColor, appClassName); | |||
| } | |||
| #define uiPtr ((UiLv2*)ui) | |||
| @@ -648,7 +652,7 @@ static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t buffe | |||
| uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static int lv2ui_idle(LV2UI_Handle ui) | |||
| { | |||
| @@ -665,7 +669,7 @@ static int lv2ui_hide(LV2UI_Handle ui) | |||
| return uiPtr->lv2ui_hide(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static uint32_t lv2_get_options(LV2UI_Handle ui, LV2_Options_Option* options) | |||
| { | |||
| @@ -677,7 +681,7 @@ static uint32_t lv2_set_options(LV2UI_Handle ui, const LV2_Options_Option* optio | |||
| return uiPtr->lv2_set_options(options); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t program) | |||
| @@ -686,7 +690,7 @@ static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t progra | |||
| } | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static const void* lv2ui_extension_data(const char* uri) | |||
| { | |||
| @@ -713,7 +717,7 @@ static const void* lv2ui_extension_data(const char* uri) | |||
| #undef instancePtr | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static const LV2UI_Descriptor sLv2UiDescriptor = { | |||
| DISTRHO_UI_URI, | |||
| @@ -723,7 +727,7 @@ static const LV2UI_Descriptor sLv2UiDescriptor = { | |||
| lv2ui_extension_data | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -929,4 +933,4 @@ void modgui_cleanup(const LV2UI_Handle handle) | |||
| } | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -67,14 +67,14 @@ START_NAMESPACE_DISTRHO | |||
| int dpf_webview_start(int argc, char* argv[]); | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Plugin Application, will set class name based on plugin details | |||
| class PluginApplication : public DGL_NAMESPACE::Application | |||
| { | |||
| public: | |||
| explicit PluginApplication(const char* className) | |||
| : DGL_NAMESPACE::Application(DISTRHO_UI_IS_STANDALONE) | |||
| explicit PluginApplication(const char* className, const Application::Type type) | |||
| : DGL_NAMESPACE::Application(DISTRHO_UI_IS_STANDALONE, type) | |||
| { | |||
| #if defined(__MOD_DEVICES__) || !defined(__EMSCRIPTEN__) | |||
| if (className == nullptr) | |||
| @@ -108,7 +108,7 @@ public: | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Plugin Window, will pass some Window events to UI | |||
| class PluginWindow : public DGL_NAMESPACE::Window | |||
| @@ -243,7 +243,7 @@ protected: | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // UI callbacks | |||
| typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started); | |||
| @@ -253,7 +253,7 @@ typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8 | |||
| typedef void (*setSizeFunc) (void* ptr, uint width, uint height); | |||
| typedef bool (*fileRequestFunc) (void* ptr, const char* key); | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // UI private data | |||
| struct UI::PrivateData { | |||
| @@ -292,8 +292,8 @@ struct UI::PrivateData { | |||
| setSizeFunc setSizeCallbackFunc; | |||
| fileRequestFunc fileRequestCallbackFunc; | |||
| PrivateData(const char* const appClassName) noexcept | |||
| : app(appClassName), | |||
| PrivateData(const char* const appClassName, const DGL_NAMESPACE::Application::Type appType) noexcept | |||
| : app(appClassName, appType), | |||
| window(nullptr), | |||
| #if DISTRHO_UI_USE_WEB_VIEW | |||
| webview(nullptr), | |||
| @@ -392,7 +392,7 @@ struct UI::PrivateData { | |||
| #endif | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // UI private data fileRequestCallback, which requires PluginWindow definitions | |||
| inline bool UI::PrivateData::fileRequestCallback(const char* const key) | |||
| @@ -419,7 +419,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key) | |||
| return false; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // PluginWindow onFileSelected that require UI::PrivateData definitions | |||
| #if DISTRHO_UI_FILE_BROWSER | |||
| @@ -457,7 +457,7 @@ inline void PluginWindow::onFileSelected(const char* const filename) | |||
| } | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -205,7 +205,8 @@ public: | |||
| nullptr, // TODO file request | |||
| d_nextBundlePath, | |||
| instancePointer, | |||
| scaleFactor) | |||
| scaleFactor, | |||
| DGL_NAMESPACE::Application::kTypeClassic) | |||
| { | |||
| } | |||
| @@ -1374,7 +1375,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||
| #else | |||
| UIExporter tmpUI(nullptr, 0, view->sampleRate, | |||
| nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | |||
| view->instancePointer, scaleFactor); | |||
| view->instancePointer, scaleFactor, DGL_NAMESPACE::Application::kTypeClassic); | |||
| rect->right = tmpUI.getWidth(); | |||
| rect->bottom = tmpUI.getHeight(); | |||
| scaleFactor = tmpUI.getScaleFactor(); | |||