1 #include "SurgeLv2Vstgui.h" 2 #include <algorithm> 3 #include <memory> 4 #include <mutex> 5 #if LINUX 6 #include <dlfcn.h> 7 #include <poll.h> 8 #endif 9 10 #if LINUX 11 void Lv2IdleRunLoop::execIdle() 12 { 13 std::chrono::steady_clock::time_point tick = std::chrono::steady_clock::now(); 14 15 for (Event &ev : _events) 16 { 17 if (!ev.alive) 18 continue; 19 20 // TODO LV2: fix me, XCB descriptor polling not working at this point 21 #if 0 22 pollfd pfd = {}; 23 pfd.fd = ev.fd; 24 pfd.events = POLLIN|POLLERR|POLLHUP; 25 if (poll(&pfd, 1, 0) > 0) 26 #endif 27 { 28 ev.handler->onEvent(); 29 } 30 } 31 32 for (Timer &tm : _timers) 33 { 34 if (!tm.alive) 35 continue; 36 37 if (tm.lastTickValid) 38 { 39 std::chrono::steady_clock::duration duration = tick - tm.lastTick; 40 tm.counter += std::chrono::duration_cast<std::chrono::microseconds>(duration); 41 if (tm.counter >= tm.interval) 42 { 43 tm.handler->onTimer(); 44 tm.counter = std::min(tm.counter - tm.interval, tm.interval); 45 } 46 } 47 tm.lastTick = tick; 48 tm.lastTickValid = true; 49 } 50 51 garbageCollectDeadHandlers<Event>(_events); 52 garbageCollectDeadHandlers<Timer>(_timers); 53 } 54 55 bool Lv2IdleRunLoop::registerEventHandler(int fd, VSTGUI::X11::IEventHandler *handler) 56 { 57 // fprintf(stderr, "registerEventHandler %d %p\n", fd, handler); 58 59 Event ev; 60 ev.fd = fd; 61 ev.handler = handler; 62 ev.alive = true; 63 _events.push_back(ev); 64 65 return true; 66 } 67 68 bool Lv2IdleRunLoop::unregisterEventHandler(VSTGUI::X11::IEventHandler *handler) 69 { 70 // fprintf(stderr, "unregisterEventHandler %p\n", handler); 71 72 auto it = std::find_if(_events.begin(), _events.end(), [handler](const Event &ev) -> bool { 73 return ev.handler == handler && ev.alive; 74 }); 75 76 if (it != _events.end()) 77 it->alive = false; 78 79 return true; 80 } 81 82 bool Lv2IdleRunLoop::registerTimer(uint64_t interval, VSTGUI::X11::ITimerHandler *handler) 83 { 84 // fprintf(stderr, "registerTimer %lu %p\n", interval, handler); 85 86 Timer tm; 87 tm.interval = std::chrono::milliseconds(interval); 88 tm.counter = std::chrono::microseconds(0); 89 tm.lastTickValid = false; 90 tm.handler = handler; 91 tm.alive = true; 92 _timers.push_back(tm); 93 94 return true; 95 } 96 97 bool Lv2IdleRunLoop::unregisterTimer(VSTGUI::X11::ITimerHandler *handler) 98 { 99 // fprintf(stderr, "unregisterTimer %p\n", handler); 100 101 auto it = std::find_if(_timers.begin(), _timers.end(), [handler](const Timer &tm) -> bool { 102 return tm.handler == handler && tm.alive; 103 }); 104 105 if (it != _timers.end()) 106 it->alive = false; 107 108 return true; 109 } 110 111 template <class T> void Lv2IdleRunLoop::garbageCollectDeadHandlers(std::list<T> &handlers) 112 { 113 auto pos = handlers.begin(); 114 auto end = handlers.end(); 115 116 while (pos != end) 117 { 118 auto curPos = pos++; 119 if (!curPos->alive) 120 handlers.erase(curPos); 121 } 122 } 123 #endif 124 125 /// 126 #if LINUX 127 namespace VSTGUI 128 { 129 void *soHandle = nullptr; 130 131 static volatile bool soHandleInitialized = false; 132 static std::mutex soHandleMutex; 133 134 struct Dl_handle_deleter 135 { 136 void operator()(void *x) const noexcept { dlclose(x); } 137 }; 138 static std::unique_ptr<void, Dl_handle_deleter> soHandlePointer; 139 } // namespace VSTGUI 140 141 void VSTGUI::initializeSoHandle() 142 { 143 if (VSTGUI::soHandleInitialized) 144 return; 145 146 std::lock_guard<std::mutex> lock(VSTGUI::soHandleMutex); 147 if (VSTGUI::soHandleInitialized) 148 return; 149 150 Dl_info info; 151 if (dladdr((void *)&lv2ui_descriptor, &info)) 152 { 153 VSTGUI::soHandle = dlopen(info.dli_fname, RTLD_LAZY); 154 VSTGUI::soHandlePointer.reset(VSTGUI::soHandle); 155 } 156 VSTGUI::soHandleInitialized = true; 157 } 158 #endif 159