diff --git a/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index 0b6abb609..2f2f39a09 100644 --- a/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -1042,6 +1042,123 @@ private: JUCE_IMPLEMENT_SINGLETON (DLLHandleCache) +//============================================================================== +#if JUCE_LINUX || JUCE_BSD + +class RunLoop final : public Steinberg::Linux::IRunLoop +{ +public: + RunLoop() = default; + + ~RunLoop() + { + for (const auto& h : eventHandlerMap) + LinuxEventLoop::unregisterFdCallback (h.first); + } + + //============================================================================== + tresult PLUGIN_API registerEventHandler (Linux::IEventHandler* handler, + Linux::FileDescriptor fd) override + { + if (handler == nullptr) + return kInvalidArgument; + + auto& handlers = eventHandlerMap[fd]; + + if (handlers.empty()) + { + LinuxEventLoop::registerFdCallback (fd, [this] (int descriptor) + { + for (auto* h : eventHandlerMap[descriptor]) + h->onFDIsSet (descriptor); + + return true; + }); + } + + handlers.push_back (handler); + + return kResultTrue; + } + + tresult PLUGIN_API unregisterEventHandler (Linux::IEventHandler* handler) override + { + if (handler == nullptr) + return kInvalidArgument; + + for (auto iter = eventHandlerMap.begin(), end = eventHandlerMap.end(); iter != end;) + { + auto& handlers = iter->second; + + auto handlersIter = std::find (std::begin (handlers), std::end (handlers), handler); + + if (handlersIter != std::end (handlers)) + { + handlers.erase (handlersIter); + + if (handlers.empty()) + { + LinuxEventLoop::unregisterFdCallback (iter->first); + iter = eventHandlerMap.erase (iter); + continue; + } + } + + ++iter; + } + + return kResultTrue; + } + + //============================================================================== + tresult PLUGIN_API registerTimer (Linux::ITimerHandler* handler, Linux::TimerInterval milliseconds) override + { + if (handler == nullptr || milliseconds <= 0) + return kInvalidArgument; + + timerCallers.emplace_back (handler, (int) milliseconds); + return kResultTrue; + } + + tresult PLUGIN_API unregisterTimer (Linux::ITimerHandler* handler) override + { + auto iter = std::find (timerCallers.begin(), timerCallers.end(), handler); + + if (iter == timerCallers.end()) + return kInvalidArgument; + + timerCallers.erase (iter); + return kResultTrue; + } + + //============================================================================== + uint32 PLUGIN_API addRef() override { return 1000; } + uint32 PLUGIN_API release() override { return 1000; } + tresult PLUGIN_API queryInterface (const TUID, void**) override { return kNoInterface; } + +private: + //============================================================================== + struct TimerCaller : private Timer + { + TimerCaller (Linux::ITimerHandler* h, int interval) : handler (h) { startTimer (interval); } + ~TimerCaller() override { stopTimer(); } + + void timerCallback() override { handler->onTimer(); } + + bool operator== (Linux::ITimerHandler* other) const noexcept { return handler == other; } + + Linux::ITimerHandler* handler = nullptr; + }; + + std::unordered_map> eventHandlerMap; + std::list timerCallers; + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RunLoop) +}; + +#endif + //============================================================================== struct VST3ModuleHandle : public ReferenceCountedObject { @@ -1189,104 +1306,11 @@ struct VST3PluginWindow : public AudioProcessorEditor, } #if JUCE_LINUX - struct RunLoop final : public Steinberg::Linux::IRunLoop - { - ~RunLoop() - { - for (const auto& h : eventHandlers) - LinuxEventLoop::unregisterFdCallback (h.first); - } - - tresult PLUGIN_API registerEventHandler (Linux::IEventHandler* handler, - Linux::FileDescriptor fd) override - { - if (handler == nullptr || eventHandlers.find (fd) != eventHandlers.end()) - return kInvalidArgument; - - LinuxEventLoop::registerFdCallback (fd, [handler] (int descriptor) - { - handler->onFDIsSet (descriptor); - return true; - }); - - eventHandlers.emplace (fd, handler); - return kResultTrue; - } - - tresult PLUGIN_API unregisterEventHandler (Linux::IEventHandler* handler) override - { - if (handler == nullptr) - return kInvalidArgument; - - for (auto it = eventHandlers.begin(), end = eventHandlers.end(); it != end; ++it) - { - if (it->second == handler) - { - LinuxEventLoop::unregisterFdCallback (it->first); - eventHandlers.erase (it); - return kResultTrue; - } - } - - return kResultFalse; - } - - tresult PLUGIN_API registerTimer (Linux::ITimerHandler* handler, Linux::TimerInterval milliseconds) override - { - if (handler == nullptr || milliseconds == 0) - return kInvalidArgument; - - timerHandlers.push_back (std::make_unique (handler, (int) milliseconds)); - return kResultTrue; - } - - tresult PLUGIN_API unregisterTimer (Linux::ITimerHandler* handler) override - { - if (handler == nullptr) - return kInvalidArgument; - - for (auto it = timerHandlers.begin(), end = timerHandlers.end(); it != end; ++it) - { - if (it->get()->handler == handler) - { - timerHandlers.erase (it); - return kResultTrue; - } - } - - return kNotImplemented; - } - - uint32 PLUGIN_API addRef() override { return 1000; } - uint32 PLUGIN_API release() override { return 1000; } - tresult PLUGIN_API queryInterface (const TUID, void**) override { return kNoInterface; } - - std::unordered_map eventHandlers; - - struct TimerCaller : public Timer - { - TimerCaller (Linux::ITimerHandler* h, int interval) : handler (h) - { - startTimer (interval); - } - - void timerCallback() override - { - handler->onTimer(); - } - - Linux::ITimerHandler* handler; - }; - std::vector> timerHandlers; - }; - - RunLoop runLoop; - Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID iid, void** obj) override { if (doUIDsMatch (iid, Steinberg::Linux::IRunLoop::iid)) { - *obj = &runLoop; + *obj = &runLoop.get(); return kResultTrue; } @@ -1530,6 +1554,7 @@ private: AutoResizingNSViewComponentWithParent embeddedComponent; using HandleFormat = NSView*; #elif JUCE_LINUX + SharedResourcePointer runLoop; XEmbedComponent embeddedComponent { true, false }; using HandleFormat = Window; #else @@ -2665,6 +2690,10 @@ public: private: //============================================================================== + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer runLoop; + #endif + std::unique_ptr holder; friend VST3HostContext;