Mercurial > hg > pub > prymula > com
comparison DPF-Prymula-audioplugins/dpf/distrho/src/DistrhoUI.cpp @ 3:84e66ea83026
DPF-Prymula-audioplugins-0.231015-2
author | prymula <prymula76@outlook.com> |
---|---|
date | Mon, 16 Oct 2023 21:53:34 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2:cf2cb71d31dd | 3:84e66ea83026 |
---|---|
1 /* | |
2 * DISTRHO Plugin Framework (DPF) | |
3 * Copyright (C) 2012-2023 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 #include "DistrhoDetails.hpp" | |
18 #include "src/DistrhoPluginChecks.h" | |
19 #include "src/DistrhoDefines.h" | |
20 | |
21 #include <cstddef> | |
22 | |
23 #ifdef DISTRHO_PROPER_CPP11_SUPPORT | |
24 # include <cstdint> | |
25 #else | |
26 # include <stdint.h> | |
27 #endif | |
28 | |
29 #if DISTRHO_UI_FILE_BROWSER && !defined(DISTRHO_OS_MAC) | |
30 # define DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, SEP, FUNCTION) NS ## SEP ## FUNCTION | |
31 # define DISTRHO_PUGL_NAMESPACE_MACRO(NS, FUNCTION) DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, _, FUNCTION) | |
32 # define x_fib_add_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_add_recent) | |
33 # define x_fib_cfg_buttons DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_cfg_buttons) | |
34 # define x_fib_cfg_filter_callback DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_cfg_filter_callback) | |
35 # define x_fib_close DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_close) | |
36 # define x_fib_configure DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_configure) | |
37 # define x_fib_filename DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_filename) | |
38 # define x_fib_free_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_free_recent) | |
39 # define x_fib_handle_events DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_handle_events) | |
40 # define x_fib_load_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_load_recent) | |
41 # define x_fib_recent_at DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_recent_at) | |
42 # define x_fib_recent_count DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_recent_count) | |
43 # define x_fib_recent_file DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_recent_file) | |
44 # define x_fib_save_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_save_recent) | |
45 # define x_fib_show DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_show) | |
46 # define x_fib_status DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_status) | |
47 # define DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED | |
48 # define FILE_BROWSER_DIALOG_NAMESPACE DISTRHO_NAMESPACE | |
49 # define FILE_BROWSER_DIALOG_DISTRHO_NAMESPACE | |
50 START_NAMESPACE_DISTRHO | |
51 # include "../extra/FileBrowserDialogImpl.hpp" | |
52 END_NAMESPACE_DISTRHO | |
53 # include "../extra/FileBrowserDialogImpl.cpp" | |
54 #endif | |
55 | |
56 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
57 # if defined(DISTRHO_OS_WINDOWS) | |
58 # include <winsock2.h> | |
59 # include <windows.h> | |
60 # elif defined(HAVE_X11) | |
61 # include <X11/Xresource.h> | |
62 # endif | |
63 #else | |
64 # include "src/TopLevelWidgetPrivateData.hpp" | |
65 # include "src/WindowPrivateData.hpp" | |
66 #endif | |
67 | |
68 #include "DistrhoUIPrivateData.hpp" | |
69 | |
70 START_NAMESPACE_DISTRHO | |
71 | |
72 /* ------------------------------------------------------------------------------------------------------------ | |
73 * Static data, see DistrhoUIInternal.hpp */ | |
74 | |
75 const char* g_nextBundlePath = nullptr; | |
76 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
77 uintptr_t g_nextWindowId = 0; | |
78 double g_nextScaleFactor = 1.0; | |
79 #endif | |
80 | |
81 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
82 /* ------------------------------------------------------------------------------------------------------------ | |
83 * get global scale factor */ | |
84 | |
85 #ifdef DISTRHO_OS_MAC | |
86 double getDesktopScaleFactor(uintptr_t parentWindowHandle); | |
87 #else | |
88 static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | |
89 { | |
90 // allow custom scale for testing | |
91 if (const char* const scale = getenv("DPF_SCALE_FACTOR")) | |
92 return std::max(1.0, std::atof(scale)); | |
93 | |
94 #if defined(DISTRHO_OS_WINDOWS) | |
95 if (const HMODULE Shcore = LoadLibraryA("Shcore.dll")) | |
96 { | |
97 typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*); | |
98 typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*); | |
99 | |
100 # if defined(__GNUC__) && (__GNUC__ >= 9) | |
101 # pragma GCC diagnostic push | |
102 # pragma GCC diagnostic ignored "-Wcast-function-type" | |
103 # endif | |
104 const PFN_GetProcessDpiAwareness GetProcessDpiAwareness | |
105 = (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness"); | |
106 const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor | |
107 = (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor"); | |
108 # if defined(__GNUC__) && (__GNUC__ >= 9) | |
109 # pragma GCC diagnostic pop | |
110 # endif | |
111 | |
112 DWORD dpiAware = 0; | |
113 DWORD scaleFactor = 100; | |
114 if (GetProcessDpiAwareness && GetScaleFactorForMonitor | |
115 && GetProcessDpiAwareness(nullptr, &dpiAware) == 0 && dpiAware != 0) | |
116 { | |
117 const HMONITOR hMon = parentWindowHandle != 0 | |
118 ? MonitorFromWindow((HWND)parentWindowHandle, MONITOR_DEFAULTTOPRIMARY) | |
119 : MonitorFromPoint(POINT{0,0}, MONITOR_DEFAULTTOPRIMARY); | |
120 GetScaleFactorForMonitor(hMon, &scaleFactor); | |
121 } | |
122 | |
123 FreeLibrary(Shcore); | |
124 return static_cast<double>(scaleFactor) / 100.0; | |
125 } | |
126 #elif defined(HAVE_X11) | |
127 ::Display* const display = XOpenDisplay(nullptr); | |
128 DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1.0); | |
129 | |
130 XrmInitialize(); | |
131 | |
132 double dpi = 96.0; | |
133 if (char* const rms = XResourceManagerString(display)) | |
134 { | |
135 if (const XrmDatabase db = XrmGetStringDatabase(rms)) | |
136 { | |
137 char* type = nullptr; | |
138 XrmValue value = {}; | |
139 | |
140 if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) | |
141 && type != nullptr | |
142 && std::strcmp(type, "String") == 0 | |
143 && value.addr != nullptr) | |
144 { | |
145 char* end = nullptr; | |
146 const double xftDpi = std::strtod(value.addr, &end); | |
147 if (xftDpi > 0.0 && xftDpi < HUGE_VAL) | |
148 dpi = xftDpi; | |
149 } | |
150 | |
151 XrmDestroyDatabase(db); | |
152 } | |
153 } | |
154 | |
155 XCloseDisplay(display); | |
156 return dpi / 96; | |
157 #endif | |
158 | |
159 return 1.0; | |
160 | |
161 // might be unused | |
162 (void)parentWindowHandle; | |
163 } | |
164 #endif // !DISTRHO_OS_MAC | |
165 | |
166 #endif | |
167 | |
168 /* ------------------------------------------------------------------------------------------------------------ | |
169 * UI::PrivateData special handling */ | |
170 | |
171 UI::PrivateData* UI::PrivateData::s_nextPrivateData = nullptr; | |
172 | |
173 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
174 ExternalWindow::PrivateData | |
175 #else | |
176 PluginWindow& | |
177 #endif | |
178 UI::PrivateData::createNextWindow(UI* const ui, uint width, uint height, const bool adjustForScaleFactor) | |
179 { | |
180 UI::PrivateData* const pData = s_nextPrivateData; | |
181 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
182 const double scaleFactor = d_isNotZero(pData->scaleFactor) ? pData->scaleFactor : getDesktopScaleFactor(pData->winId); | |
183 | |
184 if (adjustForScaleFactor && d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0)) | |
185 { | |
186 width *= scaleFactor; | |
187 height *= scaleFactor; | |
188 } | |
189 | |
190 pData->window = new PluginWindow(ui, pData->app); | |
191 ExternalWindow::PrivateData ewData; | |
192 ewData.parentWindowHandle = pData->winId; | |
193 ewData.width = width; | |
194 ewData.height = height; | |
195 ewData.scaleFactor = scaleFactor; | |
196 ewData.title = DISTRHO_PLUGIN_NAME; | |
197 ewData.isStandalone = DISTRHO_UI_IS_STANDALONE; | |
198 return ewData; | |
199 #else | |
200 const double scaleFactor = pData->scaleFactor; | |
201 | |
202 if (adjustForScaleFactor && d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0)) | |
203 { | |
204 width *= scaleFactor; | |
205 height *= scaleFactor; | |
206 } | |
207 | |
208 pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, scaleFactor); | |
209 | |
210 // If there are no callbacks, this is most likely a temporary window, so ignore idle callbacks | |
211 if (pData->callbacksPtr == nullptr) | |
212 pData->window->setIgnoreIdleCallbacks(); | |
213 | |
214 return pData->window.getObject(); | |
215 #endif | |
216 } | |
217 | |
218 /* ------------------------------------------------------------------------------------------------------------ | |
219 * UI */ | |
220 | |
221 UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetAsMinimumSize) | |
222 : UIWidget(UI::PrivateData::createNextWindow(this, | |
223 #ifdef DISTRHO_UI_DEFAULT_WIDTH | |
224 width == 0 ? DISTRHO_UI_DEFAULT_WIDTH : | |
225 #endif | |
226 width, | |
227 #ifdef DISTRHO_UI_DEFAULT_HEIGHT | |
228 height == 0 ? DISTRHO_UI_DEFAULT_HEIGHT : | |
229 #endif | |
230 height, | |
231 #ifdef DISTRHO_UI_DEFAULT_WIDTH | |
232 width == 0 | |
233 #else | |
234 false | |
235 #endif | |
236 )), | |
237 uiData(UI::PrivateData::s_nextPrivateData) | |
238 { | |
239 #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
240 if (width != 0 && height != 0) | |
241 { | |
242 Widget::setSize(width, height); | |
243 | |
244 if (automaticallyScaleAndSetAsMinimumSize) | |
245 setGeometryConstraints(width, height, true, true, true); | |
246 } | |
247 #ifdef DISTRHO_UI_DEFAULT_WIDTH | |
248 else | |
249 { | |
250 Widget::setSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT); | |
251 } | |
252 #endif | |
253 #else | |
254 // unused | |
255 (void)automaticallyScaleAndSetAsMinimumSize; | |
256 #endif | |
257 } | |
258 | |
259 UI::~UI() | |
260 { | |
261 } | |
262 | |
263 /* ------------------------------------------------------------------------------------------------------------ | |
264 * Host state */ | |
265 | |
266 bool UI::isResizable() const noexcept | |
267 { | |
268 #if DISTRHO_UI_USER_RESIZABLE | |
269 # if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
270 return true; | |
271 # else | |
272 return uiData->window->isResizable(); | |
273 # endif | |
274 #else | |
275 return false; | |
276 #endif | |
277 } | |
278 | |
279 uint UI::getBackgroundColor() const noexcept | |
280 { | |
281 return uiData->bgColor; | |
282 } | |
283 | |
284 uint UI::getForegroundColor() const noexcept | |
285 { | |
286 return uiData->fgColor; | |
287 } | |
288 | |
289 double UI::getSampleRate() const noexcept | |
290 { | |
291 return uiData->sampleRate; | |
292 } | |
293 | |
294 const char* UI::getBundlePath() const noexcept | |
295 { | |
296 return uiData->bundlePath; | |
297 } | |
298 | |
299 void UI::editParameter(uint32_t index, bool started) | |
300 { | |
301 uiData->editParamCallback(index + uiData->parameterOffset, started); | |
302 } | |
303 | |
304 void UI::setParameterValue(uint32_t index, float value) | |
305 { | |
306 uiData->setParamCallback(index + uiData->parameterOffset, value); | |
307 } | |
308 | |
309 #if DISTRHO_PLUGIN_WANT_STATE | |
310 void UI::setState(const char* key, const char* value) | |
311 { | |
312 uiData->setStateCallback(key, value); | |
313 } | |
314 #endif | |
315 | |
316 #if DISTRHO_PLUGIN_WANT_STATE | |
317 bool UI::requestStateFile(const char* key) | |
318 { | |
319 return uiData->fileRequestCallback(key); | |
320 } | |
321 #endif | |
322 | |
323 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |
324 void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity) | |
325 { | |
326 uiData->sendNoteCallback(channel, note, velocity); | |
327 } | |
328 #endif | |
329 | |
330 #if DISTRHO_UI_FILE_BROWSER | |
331 bool UI::openFileBrowser(const FileBrowserOptions& options) | |
332 { | |
333 return getWindow().openFileBrowser((DGL_NAMESPACE::FileBrowserOptions&)options); | |
334 } | |
335 #endif | |
336 | |
337 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |
338 /* ------------------------------------------------------------------------------------------------------------ | |
339 * Direct DSP access */ | |
340 | |
341 void* UI::getPluginInstancePointer() const noexcept | |
342 { | |
343 return uiData->dspPtr; | |
344 } | |
345 #endif | |
346 | |
347 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
348 /* ------------------------------------------------------------------------------------------------------------ | |
349 * External UI helpers (static calls) */ | |
350 | |
351 const char* UI::getNextBundlePath() noexcept | |
352 { | |
353 return g_nextBundlePath; | |
354 } | |
355 | |
356 double UI::getNextScaleFactor() noexcept | |
357 { | |
358 return g_nextScaleFactor; | |
359 } | |
360 | |
361 # if DISTRHO_PLUGIN_HAS_EMBED_UI | |
362 uintptr_t UI::getNextWindowId() noexcept | |
363 { | |
364 return g_nextWindowId; | |
365 } | |
366 # endif | |
367 #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
368 | |
369 /* ------------------------------------------------------------------------------------------------------------ | |
370 * DSP/Plugin Callbacks (optional) */ | |
371 | |
372 void UI::sampleRateChanged(double) | |
373 { | |
374 } | |
375 | |
376 /* ------------------------------------------------------------------------------------------------------------ | |
377 * UI Callbacks (optional) */ | |
378 | |
379 void UI::uiScaleFactorChanged(double) | |
380 { | |
381 } | |
382 | |
383 #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
384 std::vector<DGL_NAMESPACE::ClipboardDataOffer> UI::getClipboardDataOfferTypes() | |
385 { | |
386 return uiData->window->getClipboardDataOfferTypes(); | |
387 } | |
388 | |
389 uint32_t UI::uiClipboardDataOffer() | |
390 { | |
391 std::vector<DGL_NAMESPACE::ClipboardDataOffer> offers(uiData->window->getClipboardDataOfferTypes()); | |
392 | |
393 for (std::vector<DGL_NAMESPACE::ClipboardDataOffer>::iterator it=offers.begin(), end=offers.end(); it != end;++it) | |
394 { | |
395 const DGL_NAMESPACE::ClipboardDataOffer offer = *it; | |
396 if (std::strcmp(offer.type, "text/plain") == 0) | |
397 return offer.id; | |
398 } | |
399 | |
400 return 0; | |
401 } | |
402 | |
403 void UI::uiFocus(bool, DGL_NAMESPACE::CrossingMode) | |
404 { | |
405 } | |
406 | |
407 void UI::uiReshape(uint, uint) | |
408 { | |
409 // NOTE this must be the same as Window::onReshape | |
410 pData->fallbackOnResize(); | |
411 } | |
412 #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
413 | |
414 #if DISTRHO_UI_FILE_BROWSER | |
415 void UI::uiFileBrowserSelected(const char*) | |
416 { | |
417 } | |
418 #endif | |
419 | |
420 /* ------------------------------------------------------------------------------------------------------------ | |
421 * UI Resize Handling, internal */ | |
422 | |
423 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
424 void UI::sizeChanged(const uint width, const uint height) | |
425 { | |
426 UIWidget::sizeChanged(width, height); | |
427 | |
428 uiData->setSizeCallback(width, height); | |
429 } | |
430 #else | |
431 void UI::onResize(const ResizeEvent& ev) | |
432 { | |
433 UIWidget::onResize(ev); | |
434 | |
435 #if !(defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP)) | |
436 if (uiData->initializing) | |
437 return; | |
438 | |
439 const uint width = ev.size.getWidth(); | |
440 const uint height = ev.size.getHeight(); | |
441 uiData->setSizeCallback(width, height); | |
442 #endif | |
443 } | |
444 | |
445 // NOTE: only used for VST3 and CLAP | |
446 void UI::requestSizeChange(const uint width, const uint height) | |
447 { | |
448 #if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP) | |
449 if (uiData->initializing) | |
450 uiData->window->setSizeFromHost(width, height); | |
451 else | |
452 uiData->setSizeCallback(width, height); | |
453 #else | |
454 // unused | |
455 (void)width; | |
456 (void)height; | |
457 #endif | |
458 } | |
459 #endif | |
460 | |
461 // ----------------------------------------------------------------------------------------------------------- | |
462 | |
463 END_NAMESPACE_DISTRHO |