1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any purpose with
6  * or without fee is hereby granted, provided that the above copyright notice and this
7  * permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10  * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #ifndef DISTRHO_UI_INTERNAL_HPP_INCLUDED
18 #define DISTRHO_UI_INTERNAL_HPP_INCLUDED
19 
20 #include "DistrhoUIPrivateData.hpp"
21 
22 START_NAMESPACE_DISTRHO
23 
24 // -----------------------------------------------------------------------
25 // Static data, see DistrhoUI.cpp
26 
27 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
28 extern uintptr_t   g_nextWindowId;
29 extern double      g_nextScaleFactor;
30 extern const char* g_nextBundlePath;
31 #endif
32 
33 // -----------------------------------------------------------------------
34 // UI exporter class
35 
36 class UIExporter
37 {
38     // -------------------------------------------------------------------
39     // UI Widget and its private data
40 
41     UI* ui;
42     UI::PrivateData* uiData;
43 
44     // -------------------------------------------------------------------
45 
46 public:
UIExporter(void * const callbacksPtr,const uintptr_t winId,const double sampleRate,const editParamFunc editParamCall,const setParamFunc setParamCall,const setStateFunc setStateCall,const sendNoteFunc sendNoteCall,const setSizeFunc setSizeCall,const fileRequestFunc fileRequestCall,const char * const bundlePath=nullptr,void * const dspPtr=nullptr,const double scaleFactor=0.0,const uint32_t bgColor=0,const uint32_t fgColor=0xffffffff)47     UIExporter(void* const callbacksPtr,
48                const uintptr_t winId,
49                const double sampleRate,
50                const editParamFunc editParamCall,
51                const setParamFunc setParamCall,
52                const setStateFunc setStateCall,
53                const sendNoteFunc sendNoteCall,
54                const setSizeFunc setSizeCall,
55                const fileRequestFunc fileRequestCall,
56                const char* const bundlePath = nullptr,
57                void* const dspPtr = nullptr,
58                const double scaleFactor = 0.0,
59                const uint32_t bgColor = 0,
60                const uint32_t fgColor = 0xffffffff)
61         : ui(nullptr),
62           uiData(new UI::PrivateData())
63     {
64         uiData->sampleRate = sampleRate;
65         uiData->dspPtr = dspPtr;
66 
67         uiData->bgColor = bgColor;
68         uiData->fgColor = fgColor;
69         uiData->scaleFactor = scaleFactor;
70         uiData->winId = winId;
71 
72         uiData->callbacksPtr            = callbacksPtr;
73         uiData->editParamCallbackFunc   = editParamCall;
74         uiData->setParamCallbackFunc    = setParamCall;
75         uiData->setStateCallbackFunc    = setStateCall;
76         uiData->sendNoteCallbackFunc    = sendNoteCall;
77         uiData->setSizeCallbackFunc     = setSizeCall;
78         uiData->fileRequestCallbackFunc = fileRequestCall;
79 
80 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
81         g_nextWindowId    = winId;
82         g_nextScaleFactor = scaleFactor;
83         g_nextBundlePath  = bundlePath;
84 #endif
85         UI::PrivateData::s_nextPrivateData = uiData;
86 
87         UI* const uiPtr = createUI();
88 
89 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
90         g_nextWindowId    = 0;
91         g_nextScaleFactor = 0.0;
92         g_nextBundlePath  = nullptr;
93 #else
94         // Leave context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp
95         uiData->window->leaveContext();
96 #endif
97         UI::PrivateData::s_nextPrivateData = nullptr;
98 
99         DISTRHO_SAFE_ASSERT_RETURN(uiPtr != nullptr,);
100         ui = uiPtr;
101 
102 #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
103         // unused
104         (void)bundlePath;
105 #endif
106     }
107 
~UIExporter()108     ~UIExporter()
109     {
110         quit();
111         delete ui;
112         delete uiData;
113     }
114 
115     // -------------------------------------------------------------------
116 
getWidth() const117     uint getWidth() const noexcept
118     {
119         return uiData->window->getWidth();
120     }
121 
getHeight() const122     uint getHeight() const noexcept
123     {
124         return uiData->window->getHeight();
125     }
126 
getScaleFactor() const127     double getScaleFactor() const noexcept
128     {
129         return uiData->window->getScaleFactor();
130     }
131 
isVisible() const132     bool isVisible() const noexcept
133     {
134         return uiData->window->isVisible();
135     }
136 
getNativeWindowHandle() const137     uintptr_t getNativeWindowHandle() const noexcept
138     {
139         return uiData->window->getNativeWindowHandle();
140     }
141 
getBackgroundColor() const142     uint getBackgroundColor() const noexcept
143     {
144         DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0);
145 
146         return uiData->bgColor;
147     }
148 
getForegroundColor() const149     uint getForegroundColor() const noexcept
150     {
151         DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0xffffffff);
152 
153         return uiData->fgColor;
154     }
155 
156     // -------------------------------------------------------------------
157 
getParameterOffset() const158     uint32_t getParameterOffset() const noexcept
159     {
160         DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0);
161 
162         return uiData->parameterOffset;
163     }
164 
165     // -------------------------------------------------------------------
166 
parameterChanged(const uint32_t index,const float value)167     void parameterChanged(const uint32_t index, const float value)
168     {
169         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
170 
171         ui->parameterChanged(index, value);
172     }
173 
174 #if DISTRHO_PLUGIN_WANT_PROGRAMS
programLoaded(const uint32_t index)175     void programLoaded(const uint32_t index)
176     {
177         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
178 
179         ui->programLoaded(index);
180     }
181 #endif
182 
183 #if DISTRHO_PLUGIN_WANT_STATE
stateChanged(const char * const key,const char * const value)184     void stateChanged(const char* const key, const char* const value)
185     {
186         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
187         DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
188         DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);
189 
190         ui->stateChanged(key, value);
191     }
192 #endif
193 
194     // -------------------------------------------------------------------
195 
196 #if DISTRHO_UI_IS_STANDALONE
exec(DGL_NAMESPACE::IdleCallback * const cb)197     void exec(DGL_NAMESPACE::IdleCallback* const cb)
198     {
199         DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,);
200 
201         uiData->window->show();
202         uiData->window->focus();
203         uiData->app.addIdleCallback(cb);
204         uiData->app.exec();
205     }
206 
exec_idle()207     void exec_idle()
208     {
209         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, );
210 
211         ui->uiIdle();
212     }
213 #else
plugin_idle()214     bool plugin_idle()
215     {
216         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false);
217 
218         uiData->app.idle();
219         ui->uiIdle();
220         return ! uiData->app.isQuitting();
221     }
222 #endif
223 
focus()224     void focus()
225     {
226         uiData->window->focus();
227     }
228 
quit()229     void quit()
230     {
231         uiData->window->close();
232         uiData->app.quit();
233     }
234 
235     // -------------------------------------------------------------------
236 
setWindowTitle(const char * const uiTitle)237     void setWindowTitle(const char* const uiTitle)
238     {
239         uiData->window->setTitle(uiTitle);
240     }
241 
setWindowTransientWinId(const uintptr_t winId)242     void setWindowTransientWinId(const uintptr_t winId)
243     {
244 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
245         ui->setTransientWindowId(winId);
246 #elif 0 /* TODO */
247         glWindow.setTransientWinId(winId);
248 #else
249         (void)winId;
250 #endif
251     }
252 
setWindowVisible(const bool yesNo)253     bool setWindowVisible(const bool yesNo)
254     {
255         uiData->window->setVisible(yesNo);
256 
257         return ! uiData->app.isQuitting();
258     }
259 
260 #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
handlePluginKeyboard(const bool press,const uint key,const uint16_t mods)261     bool handlePluginKeyboard(const bool press, const uint key, const uint16_t mods)
262     {
263         // TODO also trigger Character input event
264         DGL_NAMESPACE::Widget::KeyboardEvent ev;
265         ev.press = press;
266         ev.key = key;
267         ev.mod = mods;
268         return ui->onKeyboard(ev);
269     }
270 
handlePluginSpecial(const bool press,const DGL_NAMESPACE::Key key,const uint16_t mods)271     bool handlePluginSpecial(const bool press, const DGL_NAMESPACE::Key key, const uint16_t mods)
272     {
273         DGL_NAMESPACE::Widget::SpecialEvent ev;
274         ev.press = press;
275         ev.key = key;
276         ev.mod = mods;
277         return ui->onSpecial(ev);
278     }
279 #endif
280 
281     // -------------------------------------------------------------------
282 
notifyScaleFactorChanged(const double scaleFactor)283     void notifyScaleFactorChanged(const double scaleFactor)
284     {
285         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
286 
287         ui->uiScaleFactorChanged(scaleFactor);
288     }
289 
setSampleRate(const double sampleRate,const bool doCallback=false)290     void setSampleRate(const double sampleRate, const bool doCallback = false)
291     {
292         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
293         DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,);
294         DISTRHO_SAFE_ASSERT(sampleRate > 0.0);
295 
296         if (d_isEqual(uiData->sampleRate, sampleRate))
297             return;
298 
299         uiData->sampleRate = sampleRate;
300 
301         if (doCallback)
302             ui->sampleRateChanged(sampleRate);
303     }
304 
305     DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UIExporter)
306 };
307 
308 // -----------------------------------------------------------------------
309 
310 END_NAMESPACE_DISTRHO
311 
312 #endif // DISTRHO_UI_INTERNAL_HPP_INCLUDED
313