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