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