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