diff --git a/data/copy-dpf-stuff b/data/copy-dpf-stuff deleted file mode 100755 index 4521ebd6c..000000000 --- a/data/copy-dpf-stuff +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -set -e - -cp -v /Shared/Personal/FOSS/GIT/DISTRHO/DPF/dgl/*.hpp /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/ -cp -r -v /Shared/Personal/FOSS/GIT/DISTRHO/DPF/dgl/src/*.cpp /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/src/ -cp -r -v /Shared/Personal/FOSS/GIT/DISTRHO/DPF/dgl/src/*.hpp /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/src/ -cp -r -v /Shared/Personal/FOSS/GIT/DISTRHO/DPF/distrho/*.cpp /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/ -cp -r -v /Shared/Personal/FOSS/GIT/DISTRHO/DPF/distrho/*.hpp /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/ -cp -r -v /Shared/Personal/FOSS/GIT/DISTRHO/DPF/distrho/*.h /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/ - -cp -r -v /Shared/Personal/FOSS/GIT/DISTRHO/DPF/dgl/src/pugl-upstream/include /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/src/pugl-upstream/ -cp -r -v /Shared/Personal/FOSS/GIT/DISTRHO/DPF/dgl/src/pugl-upstream/src /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/src/pugl-upstream/ -cp -r -v /Shared/Personal/FOSS/GIT/DISTRHO/DPF/dgl/src/pugl-upstream/AUTHORS /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/src/pugl-upstream/ -cp -r -v /Shared/Personal/FOSS/GIT/DISTRHO/DPF/dgl/src/pugl-upstream/COPYING /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/src/pugl-upstream/ - -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/Cairo.hpp -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/Vulkan.hpp -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/src/Cairo.cpp -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/src/Vulkan.cpp -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/dgl/src/Resources.{cpp,hpp} - -# rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/*.cpp -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/*.mm -rm -r /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/src/jackbridge -rm -r /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/src/travesty -rm -r /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/src/vst -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/DistrhoInfo.hpp -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/src/DistrhoPlugin{JACK,LADSPA+DSSI,LV2,LV2export,VST2,VST3}.cpp -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/src/DistrhoPluginVST3.hpp -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/src/DistrhoUI{DSSI,LV2,VST3}.cpp -rm -r /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/extra/sofd -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/extra/FileBrowserDialog.{cpp,hpp} -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/extra/LibraryUtils.hpp -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/extra/RingBuffer.hpp -rm /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/distrho/extra/ScopedSafeLocale.hpp - -# cp -v /Shared/Personal/FOSS/GIT/DISTRHO/DISTRHO_mini-series/plugins/3BandEQ/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/3bandeq/ -# cp -v /Shared/Personal/FOSS/GIT/DISTRHO/DISTRHO_mini-series/plugins/3BandSplitter/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/3bandsplitter/ -# cp -v /Shared/Personal/FOSS/GIT/DISTRHO/DISTRHO_mini-series/plugins/PingPongPan/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/pingpongpan/ -# -# cp -v /Shared/Personal/FOSS/GIT/DISTRHO/DISTRHO_nekobi/plugins/Nekobi/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/nekobi/ -# cp -v /Shared/Personal/FOSS/GIT/DISTRHO/DISTRHO_nekobi/plugins/Nekobi/nekobee-src/{*.c,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/nekobi/nekobee-src/ -# -# cp -v /Shared/Personal/FOSS/GIT/DISTRHO/DISTRHO_prom/plugins/ProM/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/prom/ -# -# cp -v /Shared/Personal/FOSS/GIT/DISTRHO/JuicePlugins/plugins/GrooveJuice/{*.cpp,*.hpp,*.hxx,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/groovejuice/ -# cp -v /Shared/Personal/FOSS/GIT/DISTRHO/JuicePlugins/plugins/PowerJuice/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/powerjuice/ -# # cp -v /Shared/Personal/FOSS/GIT/DISTRHO/JuicePlugins/plugins/PowerJuiceX2/{*.cpp,*.hpp,*.hxx,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/powerjuicex2/ -# cp -v /Shared/Personal/FOSS/GIT/DISTRHO/JuicePlugins/plugins/SegmentJuice/{*.cpp,*.hpp,*.hxx,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/segmentjuice/ -# # cp -v /Shared/Personal/FOSS/GIT/DISTRHO/JuicePlugins/plugins/StutterJuice/{*.cpp,*.hpp,*.hxx,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/stutterjuice/ -# # cp -v /Shared/Personal/FOSS/GIT/DISTRHO/JuicePlugins/plugins/TriggerJuice/{*.cpp,*.hpp,*.hxx,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/triggerjuice/ -# cp -v /Shared/Personal/FOSS/GIT/DISTRHO/JuicePlugins/plugins/VectorJuice/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/vectorjuice/ -# cp -v /Shared/Personal/FOSS/GIT/DISTRHO/JuicePlugins/plugins/WobbleJuice/{*.cpp,*.hpp,*.hxx,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/wobblejuice/ -# -# cp -v /Shared/Personal/FOSS/GIT/zam-plugins-DPF/plugins/ZamComp/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/zamcomp/ -# cp -v /Shared/Personal/FOSS/GIT/zam-plugins-DPF/plugins/ZamCompX2/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/zamcompx2/ -# cp -v /Shared/Personal/FOSS/GIT/zam-plugins-DPF/plugins/ZamEQ2/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/zameq2/ -# cp -v /Shared/Personal/FOSS/GIT/zam-plugins-DPF/plugins/ZamSynth/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/zamsynth/ -# cp -v /Shared/Personal/FOSS/GIT/zam-plugins-DPF/plugins/ZamTube/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/zamtube/ -# cp -v /Shared/Personal/FOSS/GIT/zam-plugins-DPF/plugins/ZaMultiComp/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/zamulticomp/ -# cp -v /Shared/Personal/FOSS/GIT/zam-plugins-DPF/plugins/ZaMultiCompX2/{*.cpp,*.hpp,*.h} /Shared/Personal/FOSS/GIT/falkTX/Carla/source/modules/native-plugins/zamulticompx2/ diff --git a/data/update-dpf b/data/update-dpf new file mode 100755 index 000000000..097de16aa --- /dev/null +++ b/data/update-dpf @@ -0,0 +1,51 @@ +#!/bin/bash + +set -e + +cd $(dirname ${0}) +cd .. + +CARLA_DIR=$(pwd) +DPF_DIR=/tmp/dpf-carla + +rm -rf ${DPF_DIR} +git clone git@github.com:DISTRHO/DPF.git ${DPF_DIR} --depth=1 --recursive -b develop + +cp -v ${DPF_DIR}/dgl/*.hpp ${CARLA_DIR}/source/modules/dgl/ +cp -v ${DPF_DIR}/dgl/src/*.cpp ${CARLA_DIR}/source/modules/dgl/src/ +cp -v ${DPF_DIR}/dgl/src/*.hpp ${CARLA_DIR}/source/modules/dgl/src/ +cp -v ${DPF_DIR}/distrho/*.cpp ${CARLA_DIR}/source/modules/distrho/ +cp -v ${DPF_DIR}/distrho/*.hpp ${CARLA_DIR}/source/modules/distrho/ +cp -v ${DPF_DIR}/distrho/src/*.cpp ${CARLA_DIR}/source/modules/distrho/src/ +cp -v ${DPF_DIR}/distrho/src/*.hpp ${CARLA_DIR}/source/modules/distrho/src/ + +cp -v ${DPF_DIR}/distrho/extra/LeakDetector.hpp ${CARLA_DIR}/source/modules/distrho/extra/ +cp -v ${DPF_DIR}/distrho/extra/ScopedPointer.hpp ${CARLA_DIR}/source/modules/distrho/extra/ +cp -v ${DPF_DIR}/distrho/extra/ScopedSafeLocale.hpp ${CARLA_DIR}/source/modules/distrho/extra/ +cp -v ${DPF_DIR}/distrho/extra/String.hpp ${CARLA_DIR}/source/modules/distrho/extra/ + +cp -r -v ${DPF_DIR}/dgl/src/pugl-upstream/include ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/ +cp -r -v ${DPF_DIR}/dgl/src/pugl-upstream/src ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/ +cp -r -v ${DPF_DIR}/dgl/src/pugl-upstream/AUTHORS ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/ +cp -r -v ${DPF_DIR}/dgl/src/pugl-upstream/COPYING ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/ + +rm ${CARLA_DIR}/source/modules/dgl/Cairo.hpp +rm ${CARLA_DIR}/source/modules/dgl/FileBrowserDialog.hpp +rm ${CARLA_DIR}/source/modules/dgl/Vulkan.hpp +rm ${CARLA_DIR}/source/modules/dgl/src/Cairo.cpp +rm ${CARLA_DIR}/source/modules/dgl/src/Vulkan.cpp +rm ${CARLA_DIR}/source/modules/dgl/src/Resources.{cpp,hpp} + +rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/src/.clang-tidy +rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/include/.clang-tidy +rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/include/meson.build +rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/include/pugl/cairo.h +rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/include/pugl/vulkan.h + +rm ${CARLA_DIR}/source/modules/distrho/DistrhoInfo.hpp +rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoPlugin{JACK,LADSPA+DSSI,LV2,LV2export,VST2,VST3}.cpp +rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoPluginVST3.hpp +rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoUI{DSSI,LV2,VST3}.cpp +rm ${CARLA_DIR}/source/modules/distrho/DistrhoStandaloneUtils.hpp + +rm -rf ${DPF_DIR} diff --git a/source/modules/dgl/Application.hpp b/source/modules/dgl/Application.hpp index 37a91b761..ed25a64b2 100644 --- a/source/modules/dgl/Application.hpp +++ b/source/modules/dgl/Application.hpp @@ -109,7 +109,7 @@ public: void removeIdleCallback(IdleCallback* callback); /** - Set the class name of the application. + Get the class name of the application. This is a stable identifier for the application, used as the window class/instance name on X11 and Windows. It is not displayed to the user, but can be used in scripts and by window managers, @@ -117,6 +117,12 @@ public: Plugins created with DPF have their class name automatically set based on DGL_NAMESPACE and plugin name. */ + const char* getClassName() const noexcept; + + /** + Set the class name of the application. + @see getClassName + */ void setClassName(const char* name); private: diff --git a/source/modules/dgl/src/ApplicationPrivateData.cpp b/source/modules/dgl/src/ApplicationPrivateData.cpp index 7bf488360..ca06a1bbd 100644 --- a/source/modules/dgl/src/ApplicationPrivateData.cpp +++ b/source/modules/dgl/src/ApplicationPrivateData.cpp @@ -45,6 +45,13 @@ static bool isThisTheMainThread(const d_ThreadHandle mainThreadHandle) noexcept // -------------------------------------------------------------------------------------------------------------------- +const char* Application::getClassName() const noexcept +{ + return puglGetClassName(pData->world); +} + +// -------------------------------------------------------------------------------------------------------------------- + Application::PrivateData::PrivateData(const bool standalone) : world(puglNewWorld(standalone ? PUGL_PROGRAM : PUGL_MODULE, standalone ? PUGL_WORLD_THREADS : 0x0)), diff --git a/source/modules/dgl/src/WindowPrivateData.cpp b/source/modules/dgl/src/WindowPrivateData.cpp index 92d90fc7b..60b81957b 100644 --- a/source/modules/dgl/src/WindowPrivateData.cpp +++ b/source/modules/dgl/src/WindowPrivateData.cpp @@ -109,7 +109,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) minHeight(0), keepAspectRatio(false), ignoreIdleCallbacks(false), - waitingForClipboard(false), + waitingForClipboardData(false), + waitingForClipboardEvents(false), clipboardTypeId(0), filenameToRenderInto(nullptr), #ifndef DGL_FILE_BROWSER_DISABLED @@ -137,7 +138,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c minHeight(0), keepAspectRatio(false), ignoreIdleCallbacks(false), - waitingForClipboard(false), + waitingForClipboardData(false), + waitingForClipboardEvents(false), clipboardTypeId(0), filenameToRenderInto(nullptr), #ifndef DGL_FILE_BROWSER_DISABLED @@ -167,7 +169,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, minHeight(0), keepAspectRatio(false), ignoreIdleCallbacks(false), - waitingForClipboard(false), + waitingForClipboardData(false), + waitingForClipboardEvents(false), clipboardTypeId(0), filenameToRenderInto(nullptr), #ifndef DGL_FILE_BROWSER_DISABLED @@ -198,7 +201,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, minHeight(0), keepAspectRatio(false), ignoreIdleCallbacks(false), - waitingForClipboard(false), + waitingForClipboardData(false), + waitingForClipboardEvents(false), clipboardTypeId(0), filenameToRenderInto(nullptr), #ifndef DGL_FILE_BROWSER_DISABLED @@ -261,10 +265,18 @@ void Window::PrivateData::initPre(const uint width, const uint height, const boo puglSetViewHint(view, PUGL_DEPTH_BITS, 16); #endif puglSetViewHint(view, PUGL_STENCIL_BITS, 8); -#ifdef DGL_USE_OPENGL3 + +#if defined(DGL_USE_OPENGL3) || defined(DGL_USE_GLES3) puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3); +#elif defined(DGL_USE_GLES2) + puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); + puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2); +#else + puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_TRUE); + puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2); #endif + // PUGL_SAMPLES ?? puglSetEventFunc(view, puglEventCallback); @@ -602,7 +614,7 @@ void Window::PrivateData::onPuglConfigure(const double width, const double heigh void Window::PrivateData::onPuglExpose() { - DGL_DBGp("PUGL: onPuglExpose\n"); + DGL_DBG("PUGL: onPuglExpose\n"); puglOnDisplayPrepare(view); @@ -761,36 +773,52 @@ void Window::PrivateData::onPuglScroll(const Widget::ScrollEvent& ev) const void* Window::PrivateData::getClipboard(size_t& dataSize) { clipboardTypeId = 0; - waitingForClipboard = true; + waitingForClipboardData = true, + waitingForClipboardEvents = true; + // begin clipboard dance here if (puglPaste(view) != PUGL_SUCCESS) { dataSize = 0; - waitingForClipboard = false; + waitingForClipboardEvents = false; return nullptr; } - // wait for type request - while (waitingForClipboard && clipboardTypeId == 0) - puglUpdate(appData->world, 0.03); + #ifdef DGL_USING_X11 + // wait for type request, clipboardTypeId must be != 0 to be valid + int retry = static_cast(2 / 0.03); + while (clipboardTypeId == 0 && waitingForClipboardData && --retry >= 0) + { + if (puglX11UpdateWithoutExposures(appData->world) != PUGL_SUCCESS) + break; + } + #endif if (clipboardTypeId == 0) { dataSize = 0; - waitingForClipboard = false; + waitingForClipboardEvents = false; return nullptr; } - // wait for actual data - while (waitingForClipboard) - puglUpdate(appData->world, 0.03); + #ifdef DGL_USING_X11 + // wait for actual data (assumes offer was accepted) + retry = static_cast(2 / 0.03); + while (waitingForClipboardData && --retry >= 0) + { + if (puglX11UpdateWithoutExposures(appData->world) != PUGL_SUCCESS) + break; + } + #endif if (clipboardTypeId == 0) { dataSize = 0; + waitingForClipboardEvents = false; return nullptr; } + waitingForClipboardEvents = false; return puglGetClipboard(view, clipboardTypeId - 1, &dataSize); } @@ -801,7 +829,8 @@ uint32_t Window::PrivateData::onClipboardDataOffer() if ((clipboardTypeId = self->onClipboardDataOffer()) != 0) return clipboardTypeId; - waitingForClipboard = false; + // stop waiting for data, it was rejected + waitingForClipboardData = false; return 0; } @@ -810,7 +839,7 @@ void Window::PrivateData::onClipboardData(const uint32_t typeId) if (clipboardTypeId != typeId) clipboardTypeId = 0; - waitingForClipboard = false; + waitingForClipboardData = false; } #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) @@ -826,7 +855,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu } #endif - if (pData->waitingForClipboard) + if (pData->waitingForClipboardEvents) { switch (event->type) { @@ -843,8 +872,15 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu case PUGL_BUTTON_RELEASE: case PUGL_MOTION: case PUGL_SCROLL: + case PUGL_TIMER: + case PUGL_LOOP_ENTER: + case PUGL_LOOP_LEAVE: return PUGL_SUCCESS; + case PUGL_DATA_OFFER: + case PUGL_DATA: + break; default: + d_stdout("Got event %d while waitingForClipboardEvents", event->type); break; } } @@ -857,10 +893,10 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< View created, a #PuglEventCreate case PUGL_CREATE: -#if defined(HAVE_X11) && !defined(DISTRHO_OS_MAC) && !defined(DISTRHO_OS_WINDOWS) + #ifdef DGL_USING_X11 if (! pData->isEmbed) puglX11SetWindowTypeAndPID(view, pData->appData->isStandalone); -#endif + #endif break; ///< View destroyed, a #PuglEventDestroy diff --git a/source/modules/dgl/src/WindowPrivateData.hpp b/source/modules/dgl/src/WindowPrivateData.hpp index c204f7a5d..d5c3cbd8a 100644 --- a/source/modules/dgl/src/WindowPrivateData.hpp +++ b/source/modules/dgl/src/WindowPrivateData.hpp @@ -78,7 +78,8 @@ struct Window::PrivateData : IdleCallback { bool ignoreIdleCallbacks; /** Whether we are waiting to receive clipboard data, ignoring some events in the process. */ - bool waitingForClipboard; + bool waitingForClipboardData; + bool waitingForClipboardEvents; /** The type id returned by the last onClipboardDataOffer call. */ uint32_t clipboardTypeId; diff --git a/source/modules/dgl/src/pugl-upstream/src/wasm.c b/source/modules/dgl/src/pugl-upstream/src/wasm.c index bb929060e..b7d81dadb 100644 --- a/source/modules/dgl/src/pugl-upstream/src/wasm.c +++ b/source/modules/dgl/src/pugl-upstream/src/wasm.c @@ -49,6 +49,20 @@ puglInitViewInternals(PuglWorld* const world) return impl; } +static PuglStatus +puglDispatchEventWithContext(PuglView* const view, const PuglEvent* event) +{ + PuglStatus st0 = PUGL_SUCCESS; + PuglStatus st1 = PUGL_SUCCESS; + + if (!(st0 = view->backend->enter(view, NULL))) { + st0 = view->eventFunc(view, event); + st1 = view->backend->leave(view, NULL); + } + + return st0 ? st0 : st1; +} + static PuglKey keyCodeToSpecial(const unsigned long code, const unsigned long location) { @@ -125,8 +139,12 @@ puglKeyCallback(const int eventType, const EmscriptenKeyboardEvent* const keyEve { PuglView* const view = (PuglView*)userData; - if (keyEvent->repeat && view->hints[PUGL_IGNORE_KEY_REPEAT]) + if (!view->visible) { return EM_FALSE; + } + + if (keyEvent->repeat && view->hints[PUGL_IGNORE_KEY_REPEAT]) + return EM_TRUE; PuglStatus st0 = PUGL_SUCCESS; PuglStatus st1 = PUGL_SUCCESS; @@ -138,6 +156,10 @@ puglKeyCallback(const int eventType, const EmscriptenKeyboardEvent* const keyEve const PuglKey special = keyCodeToSpecial(keyEvent->keyCode, keyEvent->location); + uint key = keyEvent->keyCode; + if (key >= 'A' && key <= 'Z' && !keyEvent->shiftKey) + key += 'a' - 'A'; + PuglEvent event = {{PUGL_NOTHING, 0}}; event.key.type = eventType == EMSCRIPTEN_EVENT_KEYDOWN ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; event.key.time = keyEvent->timestamp / 1000; @@ -145,16 +167,16 @@ puglKeyCallback(const int eventType, const EmscriptenKeyboardEvent* const keyEve // event.key.y = xevent.xkey.y; // event.key.xRoot = xevent.xkey.x_root; // event.key.yRoot = xevent.xkey.y_root; - event.key.key = special ? special : keyEvent->keyCode; + event.key.key = special ? special : key; event.key.keycode = keyEvent->keyCode; event.key.state = state; - st0 = puglDispatchEvent(view, &event); + st0 = puglDispatchEventWithContext(view, &event); d_debug("key event \n" "\tdown: %d\n" "\trepeat: %d\n" "\tlocation: %d\n" - "\tflags: 0x%x\n" + "\tstate: 0x%x\n" "\tkey[]: '%s'\n" "\tcode[]: '%s'\n" "\tlocale[]: '%s'\n" @@ -172,7 +194,7 @@ puglKeyCallback(const int eventType, const EmscriptenKeyboardEvent* const keyEve keyEvent->which, keyEvent->which >= ' ' && keyEvent->which <= '~' ? keyEvent->which : 0, special); - if (event.type == PUGL_KEY_PRESS && !special) { + if (event.type == PUGL_KEY_PRESS && !special && !(keyEvent->ctrlKey|keyEvent->altKey|keyEvent->metaKey)) { char str[8] = PUGL_INIT_STRUCT; if (decodeCharacterString(keyEvent->keyCode, keyEvent->key, str)) { @@ -181,11 +203,11 @@ puglKeyCallback(const int eventType, const EmscriptenKeyboardEvent* const keyEve event.text.type = PUGL_TEXT; event.text.character = event.key.key; memcpy(event.text.string, str, sizeof(event.text.string)); - st1 = puglDispatchEvent(view, &event); + st1 = puglDispatchEventWithContext(view, &event); } } - return (st0 ? st0 : st1) == PUGL_SUCCESS ? EM_FALSE : EM_TRUE; + return (st0 ? st0 : st1) == PUGL_SUCCESS ? EM_TRUE : EM_FALSE; } static EM_BOOL @@ -193,6 +215,10 @@ puglMouseCallback(const int eventType, const EmscriptenMouseEvent* const mouseEv { PuglView* const view = (PuglView*)userData; + if (!view->visible) { + return EM_FALSE; + } + PuglEvent event = {{PUGL_NOTHING, 0}}; const double time = mouseEvent->timestamp / 1000; @@ -201,50 +227,78 @@ puglMouseCallback(const int eventType, const EmscriptenMouseEvent* const mouseEv mouseEvent->altKey, mouseEvent->metaKey); + const double scaleFactor = view->world->impl->scaleFactor; + switch (eventType) { case EMSCRIPTEN_EVENT_MOUSEDOWN: case EMSCRIPTEN_EVENT_MOUSEUP: event.button.type = eventType == EMSCRIPTEN_EVENT_MOUSEDOWN ? PUGL_BUTTON_PRESS : PUGL_BUTTON_RELEASE; event.button.time = time; - event.button.x = mouseEvent->targetX; - event.button.y = mouseEvent->targetY; - event.button.xRoot = mouseEvent->screenX; - event.button.yRoot = mouseEvent->screenY; + event.button.x = mouseEvent->targetX * scaleFactor; + event.button.y = mouseEvent->targetY * scaleFactor; + event.button.xRoot = mouseEvent->screenX * scaleFactor; + event.button.yRoot = mouseEvent->screenY * scaleFactor; event.button.state = state; switch (mouseEvent->button) { - case 1: event.button.button = 2; - case 2: event.button.button = 1; - default: event.button.button = mouseEvent->button; - break; + case 1: + event.button.button = 2; + break; + case 2: + event.button.button = 1; + break; + default: + event.button.button = mouseEvent->button; + break; } break; case EMSCRIPTEN_EVENT_MOUSEMOVE: event.motion.type = PUGL_MOTION; event.motion.time = time; - event.motion.x = mouseEvent->targetX; - event.motion.y = mouseEvent->targetY; - event.motion.xRoot = mouseEvent->screenX; - event.motion.yRoot = mouseEvent->screenY; + if (view->impl->lastX == mouseEvent->targetX && view->impl->lastY == mouseEvent->targetY) { + // adjust local values for delta + const double movementX = mouseEvent->movementX * scaleFactor; + const double movementY = mouseEvent->movementY * scaleFactor; + view->impl->lockedX += movementX; + view->impl->lockedY += movementY; + view->impl->lockedRootX += movementX; + view->impl->lockedRootY += movementY; + // now set x, y, xRoot and yRoot + event.motion.x = view->impl->lockedX; + event.motion.y = view->impl->lockedY; + event.motion.xRoot = view->impl->lockedRootX; + event.motion.yRoot = view->impl->lockedRootY; + } else { + // cache unmodified value first, for pointer lock detection + view->impl->lastX = mouseEvent->targetX; + view->impl->lastY = mouseEvent->targetY; + // now set x, y, xRoot and yRoot + view->impl->lockedX = event.motion.x = mouseEvent->targetX * scaleFactor; + view->impl->lockedY = event.motion.y = mouseEvent->targetY * scaleFactor; + view->impl->lockedRootX = event.motion.xRoot = mouseEvent->screenX * scaleFactor; + view->impl->lockedRootY = event.motion.yRoot = mouseEvent->screenY * scaleFactor; + } event.motion.state = state; break; case EMSCRIPTEN_EVENT_MOUSEENTER: case EMSCRIPTEN_EVENT_MOUSELEAVE: event.crossing.type = eventType == EMSCRIPTEN_EVENT_MOUSEENTER ? PUGL_POINTER_IN : PUGL_POINTER_OUT; event.crossing.time = time; - event.crossing.x = mouseEvent->targetX; - event.crossing.y = mouseEvent->targetY; - event.crossing.xRoot = mouseEvent->screenX; - event.crossing.yRoot = mouseEvent->screenY; + event.crossing.x = mouseEvent->targetX * scaleFactor; + event.crossing.y = mouseEvent->targetY * scaleFactor; + event.crossing.xRoot = mouseEvent->screenX * scaleFactor; + event.crossing.yRoot = mouseEvent->screenY * scaleFactor; event.crossing.state = state; event.crossing.mode = PUGL_CROSSING_NORMAL; break; } if (event.type == PUGL_NOTHING) - return EM_TRUE; + return EM_FALSE; + + puglDispatchEventWithContext(view, &event); - // FIXME must return false so keyboard events work, why? - return puglDispatchEvent(view, &event) == PUGL_SUCCESS ? EM_FALSE : EM_TRUE; + // note: we must always return false, otherwise canvas never gets keyboard input + return EM_FALSE; } static EM_BOOL @@ -252,10 +306,27 @@ puglFocusCallback(const int eventType, const EmscriptenFocusEvent* /*const focus { PuglView* const view = (PuglView*)userData; + if (!view->visible) { + return EM_FALSE; + } + PuglEvent event = {{eventType == EMSCRIPTEN_EVENT_FOCUSIN ? PUGL_FOCUS_IN : PUGL_FOCUS_OUT, 0}}; event.focus.mode = PUGL_CROSSING_NORMAL; - return puglDispatchEvent(view, &event) == PUGL_SUCCESS ? EM_FALSE : EM_TRUE; + puglDispatchEventWithContext(view, &event); + + // note: we must always return false, otherwise canvas never gets proper focus + return EM_FALSE; +} + +static EM_BOOL +puglPointerLockChangeCallback(const int eventType, const EmscriptenPointerlockChangeEvent* event, void* const userData) +{ + PuglView* const view = (PuglView*)userData; + + printf("puglPointerLockChangeCallback %d\n", event->isActive); + view->impl->pointerLocked = event->isActive; + return EM_TRUE; } static EM_BOOL @@ -263,6 +334,12 @@ puglWheelCallback(const int eventType, const EmscriptenWheelEvent* const wheelEv { PuglView* const view = (PuglView*)userData; + if (!view->visible) { + return EM_FALSE; + } + + const double scaleFactor = view->world->impl->scaleFactor; + PuglEvent event = {{PUGL_SCROLL, 0}}; event.scroll.time = wheelEvent->mouse.timestamp / 1000; event.scroll.x = wheelEvent->mouse.targetX; @@ -275,10 +352,35 @@ puglWheelCallback(const int eventType, const EmscriptenWheelEvent* const wheelEv wheelEvent->mouse.metaKey); event.scroll.direction = PUGL_SCROLL_SMOOTH; // FIXME handle wheelEvent->deltaMode - event.scroll.dx = wheelEvent->deltaX * 0.01; - event.scroll.dy = -wheelEvent->deltaY * 0.01; + event.scroll.dx = wheelEvent->deltaX * 0.01 * scaleFactor; + event.scroll.dy = -wheelEvent->deltaY * 0.01 * scaleFactor; - return puglDispatchEvent(view, &event) == PUGL_SUCCESS ? EM_FALSE : EM_TRUE; + return puglDispatchEventWithContext(view, &event) == PUGL_SUCCESS ? EM_TRUE : EM_FALSE; +} + +static EM_BOOL +puglUiCallback(const int eventType, const EmscriptenUiEvent* const uiEvent, void* const userData) +{ + PuglView* const view = (PuglView*)userData; + + // FIXME + const int width = EM_ASM_INT({ return canvas.parentElement.clientWidth; }); + const int height = EM_ASM_INT({ return canvas.parentElement.clientHeight; }); + + if (!width || !height) + return EM_FALSE; + + const double scaleFactor = view->world->impl->scaleFactor = emscripten_get_device_pixel_ratio(); + + emscripten_set_canvas_element_size(view->world->className, width * scaleFactor, height * scaleFactor); + + PuglEvent event = {{PUGL_CONFIGURE, 0}}; + event.configure.x = view->frame.x; + event.configure.y = view->frame.y; + event.configure.width = width * scaleFactor; + event.configure.height = height * scaleFactor; + puglDispatchEvent(view, &event); + return EM_TRUE; } PuglStatus @@ -298,11 +400,13 @@ puglRealize(PuglView* const view) return PUGL_BAD_BACKEND; } + const char* const className = view->world->className; + d_stdout("className is %s", className); + // Set the size to the default if it has not already been set if (view->frame.width <= 0.0 && view->frame.height <= 0.0) { - const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; + PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; if (!defaultSize.width || !defaultSize.height) { - printf("TODO: %s %d\n", __func__, __LINE__); return PUGL_BAD_CONFIGURATION; } @@ -310,26 +414,8 @@ puglRealize(PuglView* const view) view->frame.height = defaultSize.height; } - // Center top-level windows if a position has not been set - if (!view->frame.x && !view->frame.y) { - int screenWidth, screenHeight; - emscripten_get_screen_size(&screenWidth, &screenHeight); - - view->frame.x = (PuglCoord)((screenWidth - view->frame.width) / 2); - view->frame.y = (PuglCoord)((screenHeight - view->frame.height) / 2); - } - - // Configure the backend to get the visual info -// impl->screen = screen; - if ((st = view->backend->configure(view)) /*|| !impl->vi*/) { - printf("TODO: %s %d\n", __func__, __LINE__); - view->backend->destroy(view); - return st ? st : PUGL_BACKEND_FAILED; - } - - // Create the backend drawing context/surface - if ((st = view->backend->create(view))) { - printf("TODO: %s %d\n", __func__, __LINE__); + // Configure and create the backend + if ((st = view->backend->configure(view)) || (st = view->backend->create(view))) { view->backend->destroy(view); return st; } @@ -340,8 +426,13 @@ puglRealize(PuglView* const view) puglDispatchSimpleEvent(view, PUGL_CREATE); - const char* const className = view->world->className; - d_stdout("className is %s", className); + PuglEvent event = {{PUGL_CONFIGURE, 0}}; + event.configure.x = view->frame.x; + event.configure.y = view->frame.y; + event.configure.width = view->frame.width; + event.configure.height = view->frame.height; + puglDispatchEvent(view, &event); + emscripten_set_canvas_element_size(className, view->frame.width, view->frame.height); // emscripten_set_keypress_callback(className, view, false, puglKeyCallback); emscripten_set_keydown_callback(className, view, false, puglKeyCallback); @@ -353,7 +444,10 @@ puglRealize(PuglView* const view) emscripten_set_mouseleave_callback(className, view, false, puglMouseCallback); emscripten_set_focusin_callback(className, view, false, puglFocusCallback); emscripten_set_focusout_callback(className, view, false, puglFocusCallback); + emscripten_set_pointerlockchange_callback(className, view, false, puglPointerLockChangeCallback); emscripten_set_wheel_callback(className, view, false, puglWheelCallback); + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, view, false, puglUiCallback); + view->impl->pointerLocked = true; printf("TODO: %s %d\n", __func__, __LINE__); return PUGL_SUCCESS; @@ -363,20 +457,15 @@ PuglStatus puglShow(PuglView* const view) { printf("TODO: %s %d\n", __func__, __LINE__); - PuglStatus st = PUGL_SUCCESS; - - if (!st) { -// XMapRaised(view->world->impl->display, view->impl->win); - st = puglPostRedisplay(view); - } - - return st; + view->visible = true; + return puglPostRedisplay(view); } PuglStatus puglHide(PuglView* const view) { printf("TODO: %s %d\n", __func__, __LINE__); + view->visible = false; return PUGL_FAILURE; } @@ -401,9 +490,8 @@ puglFreeWorldInternals(PuglWorld* const world) } PuglStatus -puglGrabFocus(PuglView* const view) +puglGrabFocus(PuglView*) { - printf("TODO: %s %d\n", __func__, __LINE__); return PUGL_FAILURE; } @@ -448,31 +536,19 @@ double puglGetTime(const PuglWorld*) { // d_stdout("DONE %s %d", __func__, __LINE__); - return emscripten_get_now(); + return emscripten_get_now() / 1000; } PuglStatus puglUpdate(PuglWorld* const world, const double timeout) { // printf("TODO: %s %d\n", __func__, __LINE__); - PuglEvent event = {{PUGL_EXPOSE, 0}}; for (size_t i = 0; i < world->numViews; ++i) { PuglView* const view = world->views[i]; - static bool first = true; - if (first) { - first = false; - PuglEvent event = {{PUGL_CONFIGURE, 0}}; - - event.configure.x = view->frame.x; - event.configure.y = view->frame.y; - event.configure.width = view->frame.width; - event.configure.height = view->frame.height; - d_stdout("configure at %d %d %u %u", - (int)view->frame.x, (int)view->frame.y, - (uint)view->frame.width, (uint)view->frame.height); - puglDispatchEvent(view, &event); + if (view->visible) { + puglDispatchSimpleEvent(view, PUGL_UPDATE); } if (!view->impl->needsRepaint) { @@ -481,6 +557,7 @@ puglUpdate(PuglWorld* const world, const double timeout) view->impl->needsRepaint = false; + PuglEvent event = {{PUGL_EXPOSE, 0}}; event.expose.x = view->frame.x; event.expose.y = view->frame.y; event.expose.width = view->frame.width; @@ -542,26 +619,28 @@ puglSetSizeHint(PuglView* const view, return PUGL_SUCCESS; } -static void -puglAsyncCallback(void* const arg) +static EM_BOOL +puglTimerLoopCallback(double timeout, void* const arg) { PuglTimer* const timer = (PuglTimer*)arg; PuglInternals* const impl = timer->view->impl; - // only handle async call if timer still present + // only handle active timers for (uint32_t i=0; inumTimers; ++i) { if (impl->timers[i].id == timer->id) { PuglEvent event = {{PUGL_TIMER, 0}}; event.timer.id = timer->id; - puglDispatchEvent(timer->view, &event); - - // re-run again, keeping timer active - emscripten_async_call(puglAsyncCallback, timer, timer->timeout); - break; + puglDispatchEventWithContext(timer->view, &event); + return EM_TRUE; } } + + return EM_FALSE; + + // unused + (void)timeout; } PuglStatus @@ -579,9 +658,8 @@ puglStartTimer(PuglView* const view, const uintptr_t id, const double timeout) PuglTimer* const timer = &impl->timers[timerIndex]; timer->view = view; timer->id = id; - timer->timeout = timeout * 1000; - emscripten_async_call(puglAsyncCallback, timer, timer->timeout); + emscripten_set_timeout_loop(puglTimerLoopCallback, timeout * 1000, timer); return PUGL_SUCCESS; } @@ -632,3 +710,25 @@ puglSetCursor(PuglView* const view, const PuglCursor cursor) printf("TODO: %s %d\n", __func__, __LINE__); return PUGL_FAILURE; } + +PuglStatus +puglSetTransientParent(PuglView* const view, const PuglNativeView parent) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + view->transientParent = parent; + return PUGL_FAILURE; +} + +PuglStatus +puglSetPosition(PuglView* const view, const int x, const int y) +{ + printf("TODO: %s %d\n", __func__, __LINE__); + + if (x > INT16_MAX || y > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + view->frame.x = (PuglCoord)x; + view->frame.y = (PuglCoord)y; + return PUGL_FAILURE; +} diff --git a/source/modules/dgl/src/pugl-upstream/src/wasm.h b/source/modules/dgl/src/pugl-upstream/src/wasm.h index 359ab7cba..850f62b58 100644 --- a/source/modules/dgl/src/pugl-upstream/src/wasm.h +++ b/source/modules/dgl/src/pugl-upstream/src/wasm.h @@ -10,12 +10,9 @@ #include "pugl/pugl.h" -#include - struct PuglTimer { PuglView* view; uintptr_t id; - int timeout; }; struct PuglWorldInternalsImpl { @@ -25,7 +22,11 @@ struct PuglWorldInternalsImpl { struct PuglInternalsImpl { PuglSurface* surface; bool needsRepaint; + bool pointerLocked; uint32_t numTimers; + long lastX, lastY; + double lockedX, lockedY; + double lockedRootX, lockedRootY; struct PuglTimer* timers; }; diff --git a/source/modules/dgl/src/pugl-upstream/src/wasm_gl.c b/source/modules/dgl/src/pugl-upstream/src/wasm_gl.c index 36ba77c4e..3b3b9ecc3 100644 --- a/source/modules/dgl/src/pugl-upstream/src/wasm_gl.c +++ b/source/modules/dgl/src/pugl-upstream/src/wasm_gl.c @@ -116,7 +116,8 @@ puglWasmGlConfigure(PuglView* view) puglWasmGlGetAttrib(display, config, EGL_DEPTH_SIZE); view->hints[PUGL_STENCIL_BITS] = puglWasmGlGetAttrib(display, config, EGL_STENCIL_SIZE); - view->hints[PUGL_SAMPLES] = puglWasmGlGetAttrib(display, config, EGL_SAMPLES); + view->hints[PUGL_SAMPLES] = + puglWasmGlGetAttrib(display, config, EGL_SAMPLES); // always enabled for EGL view->hints[PUGL_DOUBLE_BUFFER] = 1; @@ -136,6 +137,9 @@ puglWasmGlEnter(PuglView* view, const PuglExposeEvent* PUGL_UNUSED(expose)) return PUGL_FAILURE; } + // TESTING: is it faster if we never unset context? + return PUGL_SUCCESS; + return eglMakeCurrent(surface->display, surface->surface, surface->surface, surface->context) ? PUGL_SUCCESS : PUGL_FAILURE; } @@ -150,6 +154,9 @@ puglWasmGlLeave(PuglView* view, const PuglExposeEvent* expose) eglSwapBuffers(surface->display, surface->surface); } + // TESTING: is it faster if we never unset context? + return PUGL_SUCCESS; + return eglMakeCurrent(surface->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) ? PUGL_SUCCESS : PUGL_FAILURE; } @@ -161,26 +168,26 @@ puglWasmGlCreate(PuglView* view) const EGLDisplay display = surface->display; const EGLConfig config = surface->config; - /* - const int ctx_attrs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, + const EGLint attrs[] = { + EGL_CONTEXT_CLIENT_VERSION, + view->hints[PUGL_CONTEXT_VERSION_MAJOR], + + EGL_CONTEXT_MAJOR_VERSION, view->hints[PUGL_CONTEXT_VERSION_MAJOR], - GLX_CONTEXT_MINOR_VERSION_ARB, + /* + EGL_CONTEXT_MINOR_VERSION, view->hints[PUGL_CONTEXT_VERSION_MINOR], - GLX_CONTEXT_FLAGS_ARB, - (view->hints[PUGL_USE_DEBUG_CONTEXT] ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), + EGL_CONTEXT_OPENGL_DEBUG, + (view->hints[PUGL_USE_DEBUG_CONTEXT] ? EGL_TRUE : EGL_FALSE), - GLX_CONTEXT_PROFILE_MASK_ARB, + EGL_CONTEXT_OPENGL_PROFILE_MASK, (view->hints[PUGL_USE_COMPAT_PROFILE] - ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB - : GLX_CONTEXT_CORE_PROFILE_BIT_ARB), - 0}; + ? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT + : EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT), */ - const EGLint attrs[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; @@ -210,6 +217,9 @@ puglWasmGlCreate(PuglView* view) printf("TODO: %s %d | ok\n", __func__, __LINE__); + // TESTING: is it faster if we never unset context? + eglMakeCurrent(surface->display, surface->surface, surface->surface, surface->context); + return PUGL_SUCCESS; } diff --git a/source/modules/dgl/src/pugl.cpp b/source/modules/dgl/src/pugl.cpp index da7f498cd..5ed3b5b24 100644 --- a/source/modules/dgl/src/pugl.cpp +++ b/source/modules/dgl/src/pugl.cpp @@ -108,6 +108,7 @@ #ifndef DGL_FILE_BROWSER_DISABLED # define FILE_BROWSER_DIALOG_DGL_NAMESPACE +# define FILE_BROWSER_DIALOG_NAMESPACE DGL_NAMESPACE # define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED START_NAMESPACE_DGL # include "../../distrho/extra/FileBrowserDialogImpl.hpp" @@ -225,6 +226,8 @@ void puglRaiseWindow(PuglView* const view) if (NSWindow* const window = view->impl->window ? view->impl->window : [view->impl->wrapperView window]) [window orderFrontRegardless]; +#elif defined(DISTRHO_OS_WASM) + // nothing #elif defined(DISTRHO_OS_WINDOWS) SetForegroundWindow(view->impl->hwnd); SetActiveWindow(view->impl->hwnd); @@ -289,6 +292,8 @@ PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, co if (aspect && (status = updateSizeHint(view, PUGL_FIXED_ASPECT)) != PUGL_SUCCESS) return status; } +#elif defined(DISTRHO_OS_WASM) + // nothing #elif defined(DISTRHO_OS_WINDOWS) // nothing #elif defined(HAVE_X11) @@ -316,6 +321,8 @@ void puglSetResizable(PuglView* const view, const bool resizable) [window setStyleMask:style]; } // FIXME use [view setAutoresizingMask:NSViewNotSizable] ? +#elif defined(DISTRHO_OS_WASM) + // nothing #elif defined(DISTRHO_OS_WINDOWS) if (const HWND hwnd = view->impl->hwnd) { @@ -432,6 +439,8 @@ void puglFallbackOnResize(PuglView* const view) #endif } +// -------------------------------------------------------------------------------------------------------------------- + #if defined(DISTRHO_OS_MAC) // -------------------------------------------------------------------------------------------------------------------- @@ -569,8 +578,33 @@ void puglWin32ShowCentered(PuglView* const view) // -------------------------------------------------------------------------------------------------------------------- +#elif defined(DISTRHO_OS_WASM) + +// nothing here yet + +// -------------------------------------------------------------------------------------------------------------------- + #elif defined(HAVE_X11) +PuglStatus puglX11UpdateWithoutExposures(PuglWorld* const world) +{ + const bool wasDispatchingEvents = world->impl->dispatchingEvents; + world->impl->dispatchingEvents = true; + PuglStatus st = PUGL_SUCCESS; + + const double startTime = puglGetTime(world); + const double endTime = startTime + 0.03; + + for (double t = startTime; !st && t < endTime; t = puglGetTime(world)) + { + pollX11Socket(world, endTime - t); + st = dispatchX11Events(world); + } + + world->impl->dispatchingEvents = wasDispatchingEvents; + return st; +} + // -------------------------------------------------------------------------------------------------------------------- // X11 specific, set dialog window type and pid hints diff --git a/source/modules/dgl/src/pugl.hpp b/source/modules/dgl/src/pugl.hpp index 23b62e54f..d5d540b17 100644 --- a/source/modules/dgl/src/pugl.hpp +++ b/source/modules/dgl/src/pugl.hpp @@ -84,6 +84,10 @@ PuglStatus puglMacOSRemoveChildWindow(PuglView* view, PuglView* child); // macOS specific, center view based on parent coordinates (if there is one) void puglMacOSShowCentered(PuglView* view); +#elif defined(DISTRHO_OS_WASM) + +// nothing here yet + #elif defined(DISTRHO_OS_WINDOWS) // win32 specific, call ShowWindow with SW_RESTORE @@ -94,6 +98,11 @@ void puglWin32ShowCentered(PuglView* view); #elif defined(HAVE_X11) +#define DGL_USING_X11 + +// X11 specific, update world without triggering exposure evente +PuglStatus puglX11UpdateWithoutExposures(PuglWorld* world); + // X11 specific, set dialog window type and pid hints void puglX11SetWindowTypeAndPID(const PuglView* view, bool isStandalone); diff --git a/source/modules/distrho/extra/Base64.hpp b/source/modules/distrho/extra/Base64.hpp deleted file mode 100644 index d3eed6bee..000000000 --- a/source/modules/distrho/extra/Base64.hpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 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 - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef DISTRHO_BASE64_HPP_INCLUDED -#define DISTRHO_BASE64_HPP_INCLUDED - -#include "../DistrhoUtils.hpp" - -#include -#include - -// ----------------------------------------------------------------------- -// base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html - -/* - Copyright (C) 2004-2008 René Nyffenegger - - This source code is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this source code must not be misrepresented; you must not - claim that you wrote the original source code. If you use this source code - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original source code. - - 3. This notice may not be removed or altered from any source distribution. - - René Nyffenegger rene.nyffenegger@adp-gmbh.ch -*/ - -// ----------------------------------------------------------------------- -// Helpers - -#ifndef DOXYGEN -namespace DistrhoBase64Helpers { - -static const char* const kBase64Chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - -static inline -uint8_t findBase64CharIndex(const char c) -{ - static const uint8_t kBase64CharsLen(static_cast(std::strlen(kBase64Chars))); - - for (uint8_t i=0; i d_getChunkFromBase64String(const char* const base64string) -{ - DISTRHO_SAFE_ASSERT_RETURN(base64string != nullptr, std::vector()); - - uint i=0, j=0; - uint charArray3[3], charArray4[4]; - - std::vector ret; - ret.reserve(std::strlen(base64string)*3/4 + 4); - - for (std::size_t l=0, len=std::strlen(base64string); l(c); - - if (i == 4) - { - for (i=0; i<4; ++i) - charArray4[i] = DistrhoBase64Helpers::findBase64CharIndex(static_cast(charArray4[i])); - - charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4); - charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2); - charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; - - for (i=0; i<3; ++i) - ret.push_back(static_cast(charArray3[i])); - - i = 0; - } - } - - if (i != 0) - { - for (j=0; j(charArray4[j])); - - for (j=i; j<4; ++j) - charArray4[j] = 0; - - charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4); - charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2); - charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; - - for (j=0; i>0 && j(charArray3[j])); - } - - return ret; -} - -// ----------------------------------------------------------------------- - -#endif // DISTRHO_BASE64_HPP_INCLUDED diff --git a/source/modules/distrho/extra/ExternalWindow.hpp b/source/modules/distrho/extra/ExternalWindow.hpp deleted file mode 100644 index 1f1c360bb..000000000 --- a/source/modules/distrho/extra/ExternalWindow.hpp +++ /dev/null @@ -1,578 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 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 - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef DISTRHO_EXTERNAL_WINDOW_HPP_INCLUDED -#define DISTRHO_EXTERNAL_WINDOW_HPP_INCLUDED - -#include "String.hpp" - -#ifndef DISTRHO_OS_WINDOWS -# include -# include -# include -# include -#endif - -START_NAMESPACE_DISTRHO - -// ----------------------------------------------------------------------- -// ExternalWindow class - -/** - External Window class. - - This is a standalone TopLevelWidget/Window-compatible class, but without any real event handling. - Being compatible with TopLevelWidget/Window, it allows to be used as DPF UI target. - - It can be used to embed non-DPF things or to run a tool in a new process as the "UI". - The uiIdle() function will be called at regular intervals to keep UI running. - There are helper methods in place to launch external tools and keep track of its running state. - - External windows can be setup to run in 3 different modes: - * Embed: - Embed into the host UI, even-loop driven by the host. - This is basically working as a regular plugin UI, as you typically expect them to. - The plugin side does not get control over showing, hiding or closing the window (as usual for plugins). - No restrictions on supported plugin format, everything should work. - Requires DISTRHO_PLUGIN_HAS_EMBED_UI to be set to 1. - - * Semi-external: - The UI is not embed into the host, but the even-loop is still driven by it. - In this mode the host does not have control over the UI except for showing, hiding and setting transient parent. - It is possible to close the window from the plugin, the host will be notified of such case. - Host regularly calls isQuitting() to check if the UI got closed by the user or plugin side. - This mode is only possible in LV2 plugin formats, using lv2ui:showInterface extension. - - * Standalone: - The UI is not embed into the host or uses its event-loop, basically running as standalone. - The host only has control over showing and hiding the window, nothing else. - The UI is still free to close itself at any point. - DPF will keep calling isRunning() to check if it should keep the event-loop running. - Only possible in JACK and DSSI targets, as the UIs are literally standalone applications there. - - Please note that for non-embed windows, you cannot show the window yourself. - The plugin window is only allowed to hide or close itself, a "show" action needs to come from the host. - - A few callbacks are provided so that implementations do not need to care about checking for state changes. - They are not called on construction, but will be everytime something changes either by the host or the window itself. - */ -class ExternalWindow -{ - struct PrivateData; - -public: - /** - Constructor. - */ - explicit ExternalWindow() - : pData() {} - - /** - Constructor for DPF internal use. - */ - explicit ExternalWindow(const PrivateData& data) - : pData(data) {} - - /** - Destructor. - */ - virtual ~ExternalWindow() - { - DISTRHO_SAFE_ASSERT(!pData.visible); - } - - /* -------------------------------------------------------------------------------------------------------- - * ExternalWindow specific calls - Host side calls that you can reimplement for fine-grained funtionality */ - - /** - Check if main-loop is running. - This is used under standalone mode to check whether to keep things running. - Returning false from this function will stop the event-loop and close the window. - */ - virtual bool isRunning() const - { -#ifndef DISTRHO_OS_WINDOWS - if (ext.inUse) - return ext.isRunning(); -#endif - return isVisible(); - } - - /** - Check if we are about to close. - This is used when the event-loop is provided by the host to check if it should close the window. - It is also used in standalone mode right after isRunning() returns false to verify if window needs to be closed. - */ - virtual bool isQuitting() const - { -#ifndef DISTRHO_OS_WINDOWS - return ext.inUse ? ext.isQuitting : pData.isQuitting; -#else - return pData.isQuitting; -#endif - } - - /** - Get the "native" window handle. - This can be reimplemented in order to pass the native window to hosts that can use such informaton. - - Returned value type depends on the platform: - - HaikuOS: This is a pointer to a `BView`. - - MacOS: This is a pointer to an `NSView*`. - - Windows: This is a `HWND`. - - Everything else: This is an [X11] `Window`. - - @note Only available to override if DISTRHO_PLUGIN_HAS_EMBED_UI is set to 1. - */ - virtual uintptr_t getNativeWindowHandle() const noexcept - { - return 0; - } - - /** - Grab the keyboard input focus. - Typically you would setup OS-native methods to bring the window to front and give it focus. - Default implementation does nothing. - */ - virtual void focus() {} - - /* -------------------------------------------------------------------------------------------------------- - * TopLevelWidget-like calls - Information, can be called by either host or plugin */ - -#if DISTRHO_PLUGIN_HAS_EMBED_UI - /** - Whether this Window is embed into another (usually not DGL-controlled) Window. - */ - bool isEmbed() const noexcept - { - return pData.parentWindowHandle != 0; - } -#endif - - /** - Check if this window is visible. - @see setVisible(bool) - */ - bool isVisible() const noexcept - { - return pData.visible; - } - - /** - Whether this Window is running as standalone, that is, without being coupled to a host event-loop. - When in standalone mode, isRunning() is called to check if the event-loop should keep running. - */ - bool isStandalone() const noexcept - { - return pData.isStandalone; - } - - /** - Get width of this window. - Only relevant to hosts when the UI is embedded. - */ - uint getWidth() const noexcept - { - return pData.width; - } - - /** - Get height of this window. - Only relevant to hosts when the UI is embedded. - */ - uint getHeight() const noexcept - { - return pData.height; - } - - /** - Get the scale factor requested for this window. - This is purely informational, and up to developers to choose what to do with it. - */ - double getScaleFactor() const noexcept - { - return pData.scaleFactor; - } - - /** - Get the title of the window previously set with setTitle(). - This is typically displayed in the title bar or in window switchers. - */ - const char* getTitle() const noexcept - { - return pData.title; - } - -#if DISTRHO_PLUGIN_HAS_EMBED_UI - /** - Get the "native" window handle that this window should embed itself into. - Returned value type depends on the platform: - - HaikuOS: This is a pointer to a `BView`. - - MacOS: This is a pointer to an `NSView*`. - - Windows: This is a `HWND`. - - Everything else: This is an [X11] `Window`. - */ - uintptr_t getParentWindowHandle() const noexcept - { - return pData.parentWindowHandle; - } -#endif - - /** - Get the transient window that we should attach ourselves to. - TODO what id? also NSView* on macOS, or NSWindow? - */ - uintptr_t getTransientWindowId() const noexcept - { - return pData.transientWinId; - } - - /* -------------------------------------------------------------------------------------------------------- - * TopLevelWidget-like calls - actions called by either host or plugin */ - - /** - Hide window. - This is the same as calling setVisible(false). - Embed windows should never call this! - @see isVisible(), setVisible(bool) - */ - void hide() - { - setVisible(false); - } - - /** - Hide the UI and gracefully terminate. - Embed windows should never call this! - */ - virtual void close() - { - pData.isQuitting = true; - hide(); -#ifndef DISTRHO_OS_WINDOWS - if (ext.inUse) - terminateAndWaitForExternalProcess(); -#endif - } - - /** - Set width of this window. - Can trigger a sizeChanged callback. - Only relevant to hosts when the UI is embedded. - */ - void setWidth(uint width) - { - setSize(width, getHeight()); - } - - /** - Set height of this window. - Can trigger a sizeChanged callback. - Only relevant to hosts when the UI is embedded. - */ - void setHeight(uint height) - { - setSize(getWidth(), height); - } - - /** - Set size of this window using @a width and @a height values. - Can trigger a sizeChanged callback. - Only relevant to hosts when the UI is embedded. - */ - void setSize(uint width, uint height) - { - DISTRHO_SAFE_ASSERT_UINT_RETURN(width > 1, width,); - DISTRHO_SAFE_ASSERT_UINT_RETURN(height > 1, height,); - - if (pData.width == width && pData.height == height) - return; - - pData.width = width; - pData.height = height; - sizeChanged(width, height); - } - - /** - Set the title of the window, typically displayed in the title bar or in window switchers. - Can trigger a titleChanged callback. - Only relevant to hosts when the UI is not embedded. - */ - void setTitle(const char* title) - { - if (pData.title == title) - return; - - pData.title = title; - titleChanged(title); - } - - /** - Set geometry constraints for the Window when resized by the user. - */ - void setGeometryConstraints(uint minimumWidth, uint minimumHeight, bool keepAspectRatio = false) - { - DISTRHO_SAFE_ASSERT_UINT_RETURN(minimumWidth > 0, minimumWidth,); - DISTRHO_SAFE_ASSERT_UINT_RETURN(minimumHeight > 0, minimumHeight,); - - pData.minWidth = minimumWidth; - pData.minHeight = minimumHeight; - pData.keepAspectRatio = keepAspectRatio; - } - - /* -------------------------------------------------------------------------------------------------------- - * TopLevelWidget-like calls - actions called by the host */ - - /** - Show window. - This is the same as calling setVisible(true). - @see isVisible(), setVisible(bool) - */ - void show() - { - setVisible(true); - } - - /** - Set window visible (or not) according to @a visible. - @see isVisible(), hide(), show() - */ - void setVisible(bool visible) - { - if (pData.visible == visible) - return; - - pData.visible = visible; - visibilityChanged(visible); - } - - /** - Called by the host to set the transient parent window that we should attach ourselves to. - TODO what id? also NSView* on macOS, or NSWindow? - */ - void setTransientWindowId(uintptr_t winId) - { - if (pData.transientWinId == winId) - return; - - pData.transientWinId = winId; - transientParentWindowChanged(winId); - } - -protected: - /* -------------------------------------------------------------------------------------------------------- - * ExternalWindow special calls for running externals tools */ - - bool startExternalProcess(const char* args[]) - { -#ifndef DISTRHO_OS_WINDOWS - ext.inUse = true; - - return ext.start(args); -#else - (void)args; - return false; // TODO -#endif - } - - void terminateAndWaitForExternalProcess() - { -#ifndef DISTRHO_OS_WINDOWS - ext.isQuitting = true; - ext.terminateAndWait(); -#else - // TODO -#endif - } - - /* -------------------------------------------------------------------------------------------------------- - * ExternalWindow specific callbacks */ - - /** - A callback for when the window size changes. - @note WIP this might need to get fed back into the host somehow. - */ - virtual void sizeChanged(uint /* width */, uint /* height */) - { - // unused, meant for custom implementations - } - - /** - A callback for when the window title changes. - @note WIP this might need to get fed back into the host somehow. - */ - virtual void titleChanged(const char* /* title */) - { - // unused, meant for custom implementations - } - - /** - A callback for when the window visibility changes. - @note WIP this might need to get fed back into the host somehow. - */ - virtual void visibilityChanged(bool /* visible */) - { - // unused, meant for custom implementations - } - - /** - A callback for when the transient parent window changes. - */ - virtual void transientParentWindowChanged(uintptr_t /* winId */) - { - // unused, meant for custom implementations - } - -private: - friend class PluginWindow; - friend class UI; - -#ifndef DISTRHO_OS_WINDOWS - struct ExternalProcess { - bool inUse; - bool isQuitting; - mutable pid_t pid; - - ExternalProcess() - : inUse(false), - isQuitting(false), - pid(0) {} - - bool isRunning() const noexcept - { - if (pid <= 0) - return false; - - const pid_t p = ::waitpid(pid, nullptr, WNOHANG); - - if (p == pid || (p == -1 && errno == ECHILD)) - { - d_stdout("NOTICE: Child process exited while idle"); - pid = 0; - return false; - } - - return true; - } - - bool start(const char* args[]) - { - terminateAndWait(); - - pid = vfork(); - - switch (pid) - { - case 0: - execvp(args[0], (char**)args); - _exit(1); - return false; - - case -1: - d_stderr("Could not start external ui"); - return false; - - default: - return true; - } - } - - void terminateAndWait() - { - if (pid <= 0) - return; - - d_stdout("Waiting for external process to stop,,,"); - - bool sendTerm = true; - - for (pid_t p;;) - { - p = ::waitpid(pid, nullptr, WNOHANG); - - switch (p) - { - case 0: - if (sendTerm) - { - sendTerm = false; - ::kill(pid, SIGTERM); - } - break; - - case -1: - if (errno == ECHILD) - { - d_stdout("Done! (no such process)"); - pid = 0; - return; - } - break; - - default: - if (p == pid) - { - d_stdout("Done! (clean wait)"); - pid = 0; - return; - } - break; - } - - // 5 msec - usleep(5*1000); - } - } - } ext; -#endif - - struct PrivateData { - uintptr_t parentWindowHandle; - uintptr_t transientWinId; - uint width; - uint height; - double scaleFactor; - String title; - uint minWidth; - uint minHeight; - bool keepAspectRatio; - bool isQuitting; - bool isStandalone; - bool visible; - - PrivateData() - : parentWindowHandle(0), - transientWinId(0), - width(1), - height(1), - scaleFactor(1.0), - title(), - minWidth(0), - minHeight(0), - keepAspectRatio(false), - isQuitting(false), - isStandalone(false), - visible(false) {} - } pData; - - DISTRHO_DECLARE_NON_COPYABLE(ExternalWindow) -}; - -// ----------------------------------------------------------------------- - -END_NAMESPACE_DISTRHO - -#endif // DISTRHO_EXTERNAL_WINDOW_HPP_INCLUDED diff --git a/source/modules/distrho/extra/Mutex.hpp b/source/modules/distrho/extra/Mutex.hpp deleted file mode 100644 index e3d5fba74..000000000 --- a/source/modules/distrho/extra/Mutex.hpp +++ /dev/null @@ -1,369 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 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 - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef DISTRHO_MUTEX_HPP_INCLUDED -#define DISTRHO_MUTEX_HPP_INCLUDED - -#include "../DistrhoUtils.hpp" - -#ifdef DISTRHO_OS_WINDOWS -# ifndef NOMINMAX -# define NOMINMAX -# endif -# include -# include -#endif - -#include - -START_NAMESPACE_DISTRHO - -class Signal; - -// ----------------------------------------------------------------------- -// Mutex class - -class Mutex -{ -public: - /* - * Constructor. - */ - Mutex(const bool inheritPriority = true) noexcept - : fMutex() - { - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_setprotocol(&attr, inheritPriority ? PTHREAD_PRIO_INHERIT : PTHREAD_PRIO_NONE); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); - pthread_mutex_init(&fMutex, &attr); - pthread_mutexattr_destroy(&attr); - } - - /* - * Destructor. - */ - ~Mutex() noexcept - { - pthread_mutex_destroy(&fMutex); - } - - /* - * Lock the mutex. - */ - bool lock() const noexcept - { - return (pthread_mutex_lock(&fMutex) == 0); - } - - /* - * Try to lock the mutex. - * Returns true if successful. - */ - bool tryLock() const noexcept - { - return (pthread_mutex_trylock(&fMutex) == 0); - } - - /* - * Unlock the mutex. - */ - void unlock() const noexcept - { - pthread_mutex_unlock(&fMutex); - } - -private: - mutable pthread_mutex_t fMutex; - - DISTRHO_DECLARE_NON_COPYABLE(Mutex) -}; - -// ----------------------------------------------------------------------- -// RecursiveMutex class - -class RecursiveMutex -{ -public: - /* - * Constructor. - */ - RecursiveMutex() noexcept -#ifdef DISTRHO_OS_WINDOWS - : fSection() -#else - : fMutex() -#endif - { -#ifdef DISTRHO_OS_WINDOWS - InitializeCriticalSection(&fSection); -#else - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&fMutex, &attr); - pthread_mutexattr_destroy(&attr); -#endif - } - - /* - * Destructor. - */ - ~RecursiveMutex() noexcept - { -#ifdef DISTRHO_OS_WINDOWS - DeleteCriticalSection(&fSection); -#else - pthread_mutex_destroy(&fMutex); -#endif - } - - /* - * Lock the mutex. - */ - bool lock() const noexcept - { -#ifdef DISTRHO_OS_WINDOWS - EnterCriticalSection(&fSection); - return true; -#else - return (pthread_mutex_lock(&fMutex) == 0); -#endif - } - - /* - * Try to lock the mutex. - * Returns true if successful. - */ - bool tryLock() const noexcept - { -#ifdef DISTRHO_OS_WINDOWS - return (TryEnterCriticalSection(&fSection) != FALSE); -#else - return (pthread_mutex_trylock(&fMutex) == 0); -#endif - } - - /* - * Unlock the mutex. - */ - void unlock() const noexcept - { -#ifdef DISTRHO_OS_WINDOWS - LeaveCriticalSection(&fSection); -#else - pthread_mutex_unlock(&fMutex); -#endif - } - -private: -#ifdef DISTRHO_OS_WINDOWS - mutable CRITICAL_SECTION fSection; -#else - mutable pthread_mutex_t fMutex; -#endif - - DISTRHO_DECLARE_NON_COPYABLE(RecursiveMutex) -}; - -// ----------------------------------------------------------------------- -// Signal class - -class Signal -{ -public: - /* - * Constructor. - */ - Signal() noexcept - : fCondition(), - fMutex(), - fTriggered(false) - { - pthread_condattr_t cattr; - pthread_condattr_init(&cattr); - pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_PRIVATE); - pthread_cond_init(&fCondition, &cattr); - pthread_condattr_destroy(&cattr); - - pthread_mutexattr_t mattr; - pthread_mutexattr_init(&mattr); - pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT); - pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL); - pthread_mutex_init(&fMutex, &mattr); - pthread_mutexattr_destroy(&mattr); - } - - /* - * Destructor. - */ - ~Signal() noexcept - { - pthread_cond_destroy(&fCondition); - pthread_mutex_destroy(&fMutex); - } - - /* - * Wait for a signal. - */ - void wait() noexcept - { - pthread_mutex_lock(&fMutex); - - while (! fTriggered) - { - try { - pthread_cond_wait(&fCondition, &fMutex); - } DISTRHO_SAFE_EXCEPTION("pthread_cond_wait"); - } - - fTriggered = false; - - pthread_mutex_unlock(&fMutex); - } - - /* - * Wake up all waiting threads. - */ - void signal() noexcept - { - pthread_mutex_lock(&fMutex); - - if (! fTriggered) - { - fTriggered = true; - pthread_cond_broadcast(&fCondition); - } - - pthread_mutex_unlock(&fMutex); - } - -private: - pthread_cond_t fCondition; - pthread_mutex_t fMutex; - volatile bool fTriggered; - - DISTRHO_PREVENT_HEAP_ALLOCATION - DISTRHO_DECLARE_NON_COPYABLE(Signal) -}; - -// ----------------------------------------------------------------------- -// Helper class to lock&unlock a mutex during a function scope. - -template -class ScopeLocker -{ -public: - ScopeLocker(const Mutex& mutex) noexcept - : fMutex(mutex) - { - fMutex.lock(); - } - - ~ScopeLocker() noexcept - { - fMutex.unlock(); - } - -private: - const Mutex& fMutex; - - DISTRHO_PREVENT_HEAP_ALLOCATION - DISTRHO_DECLARE_NON_COPYABLE(ScopeLocker) -}; - -// ----------------------------------------------------------------------- -// Helper class to try-lock&unlock a mutex during a function scope. - -template -class ScopeTryLocker -{ -public: - ScopeTryLocker(const Mutex& mutex) noexcept - : fMutex(mutex), - fLocked(mutex.tryLock()) {} - - ScopeTryLocker(const Mutex& mutex, const bool forceLock) noexcept - : fMutex(mutex), - fLocked(forceLock ? mutex.lock() : mutex.tryLock()) {} - - ~ScopeTryLocker() noexcept - { - if (fLocked) - fMutex.unlock(); - } - - bool wasLocked() const noexcept - { - return fLocked; - } - - bool wasNotLocked() const noexcept - { - return !fLocked; - } - -private: - const Mutex& fMutex; - const bool fLocked; - - DISTRHO_PREVENT_HEAP_ALLOCATION - DISTRHO_DECLARE_NON_COPYABLE(ScopeTryLocker) -}; - -// ----------------------------------------------------------------------- -// Helper class to unlock&lock a mutex during a function scope. - -template -class ScopeUnlocker -{ -public: - ScopeUnlocker(const Mutex& mutex) noexcept - : fMutex(mutex) - { - fMutex.unlock(); - } - - ~ScopeUnlocker() noexcept - { - fMutex.lock(); - } - -private: - const Mutex& fMutex; - - DISTRHO_PREVENT_HEAP_ALLOCATION - DISTRHO_DECLARE_NON_COPYABLE(ScopeUnlocker) -}; - -// ----------------------------------------------------------------------- -// Define types - -typedef ScopeLocker MutexLocker; -typedef ScopeLocker RecursiveMutexLocker; - -typedef ScopeTryLocker MutexTryLocker; -typedef ScopeTryLocker RecursiveMutexTryLocker; - -typedef ScopeUnlocker MutexUnlocker; -typedef ScopeUnlocker RecursiveMutexUnlocker; - -// ----------------------------------------------------------------------- - -END_NAMESPACE_DISTRHO - -#endif // DISTRHO_MUTEX_HPP_INCLUDED diff --git a/source/modules/distrho/extra/Sleep.hpp b/source/modules/distrho/extra/Sleep.hpp deleted file mode 100644 index 612a940aa..000000000 --- a/source/modules/distrho/extra/Sleep.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 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 - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef DISTRHO_SLEEP_HPP_INCLUDED -#define DISTRHO_SLEEP_HPP_INCLUDED - -#include "../DistrhoUtils.hpp" - -#ifdef DISTRHO_OS_WINDOWS -# ifndef NOMINMAX -# define NOMINMAX -# endif -# include -# include -#else -# include -#endif - -// ----------------------------------------------------------------------- -// d_*sleep - -/* - * Sleep for 'secs' seconds. - */ -static inline -void d_sleep(const uint secs) noexcept -{ - DISTRHO_SAFE_ASSERT_RETURN(secs > 0,); - - try { -#ifdef DISTRHO_OS_WINDOWS - ::Sleep(secs * 1000); -#else - ::sleep(secs); -#endif - } DISTRHO_SAFE_EXCEPTION("d_sleep"); -} - -/* - * Sleep for 'msecs' milliseconds. - */ -static inline -void d_msleep(const uint msecs) noexcept -{ - DISTRHO_SAFE_ASSERT_RETURN(msecs > 0,); - - try { -#ifdef DISTRHO_OS_WINDOWS - ::Sleep(msecs); -#else - ::usleep(msecs * 1000); -#endif - } DISTRHO_SAFE_EXCEPTION("d_msleep"); -} - -// ----------------------------------------------------------------------- - -#endif // DISTRHO_SLEEP_HPP_INCLUDED diff --git a/source/modules/distrho/extra/Thread.hpp b/source/modules/distrho/extra/Thread.hpp deleted file mode 100644 index ec6f13d9f..000000000 --- a/source/modules/distrho/extra/Thread.hpp +++ /dev/null @@ -1,334 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 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 - * permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef DISTRHO_THREAD_HPP_INCLUDED -#define DISTRHO_THREAD_HPP_INCLUDED - -#include "Mutex.hpp" -#include "Sleep.hpp" -#include "String.hpp" - -#ifdef DISTRHO_OS_LINUX -# include -#endif - -START_NAMESPACE_DISTRHO - -// ----------------------------------------------------------------------- -// Thread class - -class Thread -{ -protected: - /* - * Constructor. - */ - Thread(const char* const threadName = nullptr) noexcept - : fLock(), - fSignal(), - fName(threadName), -#ifdef PTW32_DLLPORT - fHandle({nullptr, 0}), -#else - fHandle(0), -#endif - fShouldExit(false) {} - - /* - * Destructor. - */ - virtual ~Thread() /*noexcept*/ - { - DISTRHO_SAFE_ASSERT(! isThreadRunning()); - - stopThread(-1); - } - - /* - * Virtual function to be implemented by the subclass. - */ - virtual void run() = 0; - - // ------------------------------------------------------------------- - -public: - /* - * Check if the thread is running. - */ - bool isThreadRunning() const noexcept - { -#ifdef PTW32_DLLPORT - return (fHandle.p != nullptr); -#else - return (fHandle != 0); -#endif - } - - /* - * Check if the thread should exit. - */ - bool shouldThreadExit() const noexcept - { - return fShouldExit; - } - - /* - * Start the thread. - */ - bool startThread(const bool withRealtimePriority = false) noexcept - { - // check if already running - DISTRHO_SAFE_ASSERT_RETURN(! isThreadRunning(), true); - - pthread_t handle; - - pthread_attr_t attr; - pthread_attr_init(&attr); - - struct sched_param sched_param; - std::memset(&sched_param, 0, sizeof(sched_param)); - - if (withRealtimePriority) - { - sched_param.sched_priority = 80; - -#ifndef DISTRHO_OS_HAIKU - if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) == 0 && - pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) == 0 && -# ifndef DISTRHO_OS_WINDOWS - (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0 || - pthread_attr_setschedpolicy(&attr, SCHED_RR) == 0) && -# endif - pthread_attr_setschedparam(&attr, &sched_param) == 0) - { - d_stdout("Thread setup with realtime priority successful"); - } - else -#endif - { - d_stdout("Thread setup with realtime priority failed, going with normal priority instead"); - pthread_attr_destroy(&attr); - pthread_attr_init(&attr); - } - } - - const MutexLocker ml(fLock); - - fShouldExit = false; - - bool ok = pthread_create(&handle, &attr, _entryPoint, this) == 0; - pthread_attr_destroy(&attr); - - if (withRealtimePriority && !ok) - { - d_stdout("Thread with realtime priority failed on creation, going with normal priority instead"); - pthread_attr_init(&attr); - ok = pthread_create(&handle, &attr, _entryPoint, this) == 0; - pthread_attr_destroy(&attr); - } - - DISTRHO_SAFE_ASSERT_RETURN(ok, false); -#ifdef PTW32_DLLPORT - DISTRHO_SAFE_ASSERT_RETURN(handle.p != nullptr, false); -#else - DISTRHO_SAFE_ASSERT_RETURN(handle != 0, false); -#endif - pthread_detach(handle); - _copyFrom(handle); - - // wait for thread to start - fSignal.wait(); - return true; - } - - /* - * Stop the thread. - * In the 'timeOutMilliseconds': - * = 0 -> no wait - * > 0 -> wait timeout value - * < 0 -> wait forever - */ - bool stopThread(const int timeOutMilliseconds) noexcept - { - const MutexLocker ml(fLock); - - if (isThreadRunning()) - { - signalThreadShouldExit(); - - if (timeOutMilliseconds != 0) - { - // Wait for the thread to stop - int timeOutCheck = (timeOutMilliseconds == 1 || timeOutMilliseconds == -1) ? timeOutMilliseconds : timeOutMilliseconds/2; - - for (; isThreadRunning();) - { - d_msleep(2); - - if (timeOutCheck < 0) - continue; - - if (timeOutCheck > 0) - timeOutCheck -= 1; - else - break; - } - } - - if (isThreadRunning()) - { - // should never happen! - d_stderr2("assertion failure: \"! isThreadRunning()\" in file %s, line %i", __FILE__, __LINE__); - - // copy thread id so we can clear our one - pthread_t threadId; - _copyTo(threadId); - _init(); - - pthread_detach(threadId); - return false; - } - } - - return true; - } - - /* - * Tell the thread to stop as soon as possible. - */ - void signalThreadShouldExit() noexcept - { - fShouldExit = true; - } - - // ------------------------------------------------------------------- - - /* - * Returns the name of the thread. - * This is the name that gets set in the constructor. - */ - const String& getThreadName() const noexcept - { - return fName; - } - - /* - * Returns the Id/handle of the thread. - */ - pthread_t getThreadId() const noexcept - { - return fHandle; - } - - /* - * Changes the name of the caller thread. - */ - static void setCurrentThreadName(const char* const name) noexcept - { - DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',); - -#ifdef DISTRHO_OS_LINUX - prctl(PR_SET_NAME, name, 0, 0, 0); -#endif -#if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 && !defined(DISTRHO_OS_GNU_HURD) - pthread_setname_np(pthread_self(), name); -#endif - } - - // ------------------------------------------------------------------- - -private: - Mutex fLock; // Thread lock - Signal fSignal; // Thread start wait signal - const String fName; // Thread name - volatile pthread_t fHandle; // Handle for this thread - volatile bool fShouldExit; // true if thread should exit - - /* - * Init pthread type. - */ - void _init() noexcept - { -#ifdef PTW32_DLLPORT - fHandle.p = nullptr; - fHandle.x = 0; -#else - fHandle = 0; -#endif - } - - /* - * Copy our pthread type from another var. - */ - void _copyFrom(const pthread_t& handle) noexcept - { -#ifdef PTW32_DLLPORT - fHandle.p = handle.p; - fHandle.x = handle.x; -#else - fHandle = handle; -#endif - } - - /* - * Copy our pthread type to another var. - */ - void _copyTo(volatile pthread_t& handle) const noexcept - { -#ifdef PTW32_DLLPORT - handle.p = fHandle.p; - handle.x = fHandle.x; -#else - handle = fHandle; -#endif - } - - /* - * Thread entry point. - */ - void _runEntryPoint() noexcept - { - if (fName.isNotEmpty()) - setCurrentThreadName(fName); - - // report ready - fSignal.signal(); - - try { - run(); - } catch(...) {} - - // done - _init(); - } - - /* - * Thread entry point. - */ - static void* _entryPoint(void* userData) noexcept - { - static_cast(userData)->_runEntryPoint(); - return nullptr; - } - - DISTRHO_DECLARE_NON_COPYABLE(Thread) -}; - -// ----------------------------------------------------------------------- - -END_NAMESPACE_DISTRHO - -#endif // DISTRHO_THREAD_HPP_INCLUDED diff --git a/source/modules/distrho/src/DistrhoUI.cpp b/source/modules/distrho/src/DistrhoUI.cpp index cc3f53c4e..3af6926f0 100644 --- a/source/modules/distrho/src/DistrhoUI.cpp +++ b/source/modules/distrho/src/DistrhoUI.cpp @@ -44,6 +44,7 @@ # define x_fib_show DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_show) # define x_fib_status DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_status) # define DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED +# define FILE_BROWSER_DIALOG_NAMESPACE DISTRHO_NAMESPACE # define FILE_BROWSER_DIALOG_DISTRHO_NAMESPACE START_NAMESPACE_DISTRHO # include "../extra/FileBrowserDialogImpl.hpp" diff --git a/source/modules/distrho/src/DistrhoUIPrivateData.hpp b/source/modules/distrho/src/DistrhoUIPrivateData.hpp index 7aea3ca89..1cc23ccff 100644 --- a/source/modules/distrho/src/DistrhoUIPrivateData.hpp +++ b/source/modules/distrho/src/DistrhoUIPrivateData.hpp @@ -25,6 +25,7 @@ #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI # include "../extra/Sleep.hpp" +// TODO import and use file browser here #else # include "../../dgl/src/ApplicationPrivateData.hpp" # include "../../dgl/src/WindowPrivateData.hpp" @@ -319,7 +320,7 @@ struct UI::PrivateData { uint fgColor; double scaleFactor; uintptr_t winId; -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) +#if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI char* uiStateFileKeyRequest; #endif char* bundlePath; @@ -346,7 +347,7 @@ struct UI::PrivateData { fgColor(0xffffffff), scaleFactor(1.0), winId(0), -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) +#if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI uiStateFileKeyRequest(nullptr), #endif bundlePath(nullptr), @@ -382,7 +383,7 @@ struct UI::PrivateData { ~PrivateData() noexcept { -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) +#if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI std::free(uiStateFileKeyRequest); #endif std::free(bundlePath); @@ -437,7 +438,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key) if (fileRequestCallbackFunc != nullptr) return fileRequestCallbackFunc(callbacksPtr, key); -#if DISTRHO_PLUGIN_WANT_STATE && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) +#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI std::free(uiStateFileKeyRequest); uiStateFileKeyRequest = strdup(key); DISTRHO_SAFE_ASSERT_RETURN(uiStateFileKeyRequest != nullptr, false); @@ -457,7 +458,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key) // ----------------------------------------------------------------------- // PluginWindow onFileSelected that require UI::PrivateData definitions -#if DISTRHO_UI_FILE_BROWSER +#if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI inline void PluginWindow::onFileSelected(const char* const filename) { DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); @@ -481,7 +482,9 @@ inline void PluginWindow::onFileSelected(const char* const filename) } #endif + puglBackendEnter(pData->view); ui->uiFileBrowserSelected(filename); + puglBackendLeave(pData->view); } #endif diff --git a/source/modules/distrho/src/DistrhoUtils.cpp b/source/modules/distrho/src/DistrhoUtils.cpp index 364461ffa..fc0ff25a0 100644 --- a/source/modules/distrho/src/DistrhoUtils.cpp +++ b/source/modules/distrho/src/DistrhoUtils.cpp @@ -78,7 +78,11 @@ const char* getPluginFormatName() noexcept #if defined(DISTRHO_PLUGIN_TARGET_CARLA) return "Carla"; #elif defined(DISTRHO_PLUGIN_TARGET_JACK) +# ifdef DISTRHO_OS_WASM + return "Wasm/Standalone"; +# else return "JACK/Standalone"; +# endif #elif defined(DISTRHO_PLUGIN_TARGET_LADSPA) return "LADSPA"; #elif defined(DISTRHO_PLUGIN_TARGET_DSSI)