@@ -1,5 +1,7 @@ | |||||
# DPF - DISTRHO Plugin Framework | # DPF - DISTRHO Plugin Framework | ||||
[](https://travis-ci.org/DISTRHO/DPF) | |||||
[](https://github.com/DISTRHO/DPF/actions/workflows/makefile.yml) | |||||
[](https://github.com/DISTRHO/DPF/actions/workflows/cmake.yml) | |||||
[](https://github.com/DISTRHO/DPF/actions/workflows/example-plugins.yml) | |||||
DPF is designed to make development of new plugins an easy and enjoyable task.<br/> | DPF is designed to make development of new plugins an easy and enjoyable task.<br/> | ||||
It allows developers to create plugins with custom UIs using a simple C++ API.<br/> | It allows developers to create plugins with custom UIs using a simple C++ API.<br/> | ||||
@@ -23,7 +25,7 @@ Bug reports happen on the [DPF github project](https://github.com/DISTRHO/DPF/is | |||||
Online documentation is available at [https://distrho.github.io/DPF/](https://distrho.github.io/DPF/). | Online documentation is available at [https://distrho.github.io/DPF/](https://distrho.github.io/DPF/). | ||||
Online help and discussion about DPF happens in the [KXStudio chat DPF room](https://chat.kx.studio/channel/dpf). | |||||
Online help and discussion about DPF happens in the [kx.studio chat, DPF room](https://chat.kx.studio/). | |||||
## List of plugins made with DPF: | ## List of plugins made with DPF: | ||||
@@ -59,7 +61,6 @@ Online help and discussion about DPF happens in the [KXStudio chat DPF room](htt | |||||
- [Shiro Plugins](https://github.com/ninodewit/SHIRO-Plugins/) | - [Shiro Plugins](https://github.com/ninodewit/SHIRO-Plugins/) | ||||
- [Shiru Plugins](https://github.com/linuxmao-org/shiru-plugins) | - [Shiru Plugins](https://github.com/linuxmao-org/shiru-plugins) | ||||
Checking the [github "DPF" tag](https://github.com/topics/dpf) can potentially brings up other DPF-made plugins. | |||||
Checking the [github "DPF" tag](https://github.com/topics/dpf) can potentially bring up other DPF-made plugins. | |||||
Plugin examples are available in the `example/` folder inside this repo.<br/> | |||||
Extra OpenGL UI examples are available [here](https://github.com/DISTRHO/gl-examples). | |||||
Plugin examples are available in the `example/` folder inside this repo. |
@@ -317,6 +317,17 @@ function(dpf__build_vst2 NAME DGL_LIBRARY) | |||||
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/vst2/$<0:>" | ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/vst2/$<0:>" | ||||
OUTPUT_NAME "${NAME}-vst2" | OUTPUT_NAME "${NAME}-vst2" | ||||
PREFIX "") | PREFIX "") | ||||
if(APPLE) | |||||
set_target_properties("${NAME}-vst2" PROPERTIES | |||||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.vst/Contents/MacOS/$<0:>" | |||||
OUTPUT_NAME "${NAME}" | |||||
SUFFIX "") | |||||
set(INFO_PLIST_PROJECT_NAME "${NAME}") | |||||
configure_file("${DPF_ROOT_DIR}/utils/plugin.vst/Contents/Info.plist" | |||||
"${PROJECT_BINARY_DIR}/bin/${NAME}.vst/Contents/Info.plist" @ONLY) | |||||
file(COPY "${DPF_ROOT_DIR}/utils/plugin.vst/Contents/PkgInfo" | |||||
DESTINATION "${PROJECT_BINARY_DIR}/bin/${NAME}.vst/Contents") | |||||
endif() | |||||
endfunction() | endfunction() | ||||
# dpf__add_dgl_cairo | # dpf__add_dgl_cairo | ||||
@@ -64,7 +64,6 @@ public: | |||||
Quit the application. | Quit the application. | ||||
This stops the event-loop and closes all Windows. | This stops the event-loop and closes all Windows. | ||||
This function is thread-safe. | This function is thread-safe. | ||||
@note This function is meant for standalones only, *never* call this from plugins. | |||||
*/ | */ | ||||
void quit(); | void quit(); | ||||
@@ -923,6 +923,7 @@ private: | |||||
*/ | */ | ||||
inline void onDisplay() override | inline void onDisplay() override | ||||
{ | { | ||||
// NOTE maybe should use BaseWidget::getWindow().getScaleFactor() as 3rd arg ? | |||||
NanoVG::beginFrame(BaseWidget::getWidth(), BaseWidget::getHeight()); | NanoVG::beginFrame(BaseWidget::getWidth(), BaseWidget::getHeight()); | ||||
onNanoDisplay(); | onNanoDisplay(); | ||||
NanoVG::endFrame(); | NanoVG::endFrame(); | ||||
@@ -33,14 +33,25 @@ public: | |||||
*/ | */ | ||||
StandaloneWindow(Application& app) | StandaloneWindow(Application& app) | ||||
: Window(app), | : Window(app), | ||||
TopLevelWidget((Window&)*this) {} | |||||
TopLevelWidget((Window&)*this), | |||||
sgc((Window&)*this) {} | |||||
/** | /** | ||||
Constructor with parent window, typically used to run as modal. | |||||
Constructor with a transient parent window, typically used to run as modal. | |||||
*/ | */ | ||||
StandaloneWindow(Application& app, Window& parentWindow) | |||||
: Window(app, parentWindow), | |||||
TopLevelWidget((Window&)*this) {} | |||||
StandaloneWindow(Application& app, Window& transientParentWindow) | |||||
: Window(app, transientParentWindow), | |||||
TopLevelWidget((Window&)*this), | |||||
sgc((Window&)*this, transientParentWindow) {} | |||||
/** | |||||
Clear current graphics context. | |||||
Must be called at the end of your StandaloneWindow constructor. | |||||
*/ | |||||
void done() | |||||
{ | |||||
sgc.done(); | |||||
} | |||||
/** | /** | ||||
Overloaded functions to ensure they apply to the Window class. | Overloaded functions to ensure they apply to the Window class. | ||||
@@ -66,6 +77,9 @@ public: | |||||
bool keepAspectRatio = false, bool automaticallyScale = false) | bool keepAspectRatio = false, bool automaticallyScale = false) | ||||
{ Window::setGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, automaticallyScale); } | { Window::setGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, automaticallyScale); } | ||||
private: | |||||
ScopedGraphicsContext sgc; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(StandaloneWindow) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(StandaloneWindow) | ||||
}; | }; | ||||
@@ -49,6 +49,8 @@ class TopLevelWidget; | |||||
*/ | */ | ||||
class Window | class Window | ||||
{ | { | ||||
struct PrivateData; | |||||
public: | public: | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
/** | /** | ||||
@@ -59,6 +61,7 @@ public: | |||||
/** | /** | ||||
File browser button state. | File browser button state. | ||||
This allows to customize the behaviour of the file browse dialog buttons. | This allows to customize the behaviour of the file browse dialog buttons. | ||||
Note these are merely hints, not all systems support them. | |||||
*/ | */ | ||||
enum ButtonState { | enum ButtonState { | ||||
kButtonInvisible, | kButtonInvisible, | ||||
@@ -87,7 +90,7 @@ public: | |||||
Buttons() | Buttons() | ||||
: listAllFiles(kButtonVisibleChecked), | : listAllFiles(kButtonVisibleChecked), | ||||
showHidden(kButtonVisibleUnchecked), | showHidden(kButtonVisibleUnchecked), | ||||
showPlaces(kButtonVisibleUnchecked) {} | |||||
showPlaces(kButtonVisibleChecked) {} | |||||
} buttons; | } buttons; | ||||
/** Constructor for default values */ | /** Constructor for default values */ | ||||
@@ -113,7 +116,7 @@ public: | |||||
Window win(app); | Window win(app); | ||||
ScopedPointer<MyCustomTopLevelWidget> widget; | ScopedPointer<MyCustomTopLevelWidget> widget; | ||||
{ | { | ||||
const ScopedGraphicsContext sgc(win); | |||||
const Window::ScopedGraphicsContext sgc(win); | |||||
widget = new MyCustomTopLevelWidget(win); | widget = new MyCustomTopLevelWidget(win); | ||||
} | } | ||||
app.exec(); | app.exec(); | ||||
@@ -127,12 +130,25 @@ public: | |||||
*/ | */ | ||||
struct ScopedGraphicsContext | struct ScopedGraphicsContext | ||||
{ | { | ||||
/** Constructor that will make the @a window graphics context the current one */ | |||||
explicit ScopedGraphicsContext(Window& window); | explicit ScopedGraphicsContext(Window& window); | ||||
/** Overloaded constructor, gives back context to its transient parent when done */ | |||||
explicit ScopedGraphicsContext(Window& window, Window& transientParentWindow); | |||||
/** Desstructor for clearing current context, if not done yet */ | |||||
~ScopedGraphicsContext(); | ~ScopedGraphicsContext(); | ||||
/** Early context clearing, useful for standalone windows not created by you. */ | |||||
void done(); | |||||
DISTRHO_DECLARE_NON_COPYABLE(ScopedGraphicsContext) | DISTRHO_DECLARE_NON_COPYABLE(ScopedGraphicsContext) | ||||
DISTRHO_PREVENT_HEAP_ALLOCATION | DISTRHO_PREVENT_HEAP_ALLOCATION | ||||
private: | private: | ||||
Window& window; | Window& window; | ||||
Window::PrivateData* ppData; | |||||
bool active; | |||||
}; | }; | ||||
/** | /** | ||||
@@ -441,7 +457,6 @@ protected: | |||||
#endif | #endif | ||||
private: | private: | ||||
struct PrivateData; | |||||
PrivateData* const pData; | PrivateData* const pData; | ||||
friend class Application; | friend class Application; | ||||
friend class PluginWindow; | friend class PluginWindow; | ||||
@@ -43,8 +43,6 @@ void Application::exec(const uint idleTimeInMs) | |||||
void Application::quit() | void Application::quit() | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(pData->isStandalone,); | |||||
pData->quit(); | pData->quit(); | ||||
} | } | ||||
@@ -127,8 +127,6 @@ void Application::PrivateData::idle(const uint timeoutInMs) | |||||
void Application::PrivateData::quit() | void Application::PrivateData::quit() | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(isStandalone,); | |||||
if (! isThisTheMainThread(mainThreadHandle)) | if (! isThisTheMainThread(mainThreadHandle)) | ||||
{ | { | ||||
if (! isQuittingInNextCycle) | if (! isQuittingInNextCycle) | ||||
@@ -29,11 +29,13 @@ ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(Window& parentWindow, cons | |||||
setResizable(false); | setResizable(false); | ||||
setTitle("About"); | setTitle("About"); | ||||
if (image.isInvalid()) | |||||
return; | |||||
if (image.isValid()) | |||||
{ | |||||
setSize(image.getSize()); | |||||
setGeometryConstraints(image.getWidth(), image.getHeight(), true, true); | |||||
} | |||||
setSize(image.getSize()); | |||||
setGeometryConstraints(image.getWidth(), image.getHeight(), true, true); | |||||
done(); | |||||
} | } | ||||
template <class ImageType> | template <class ImageType> | ||||
@@ -44,11 +46,13 @@ ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(TopLevelWidget* const pare | |||||
setResizable(false); | setResizable(false); | ||||
setTitle("About"); | setTitle("About"); | ||||
if (image.isInvalid()) | |||||
return; | |||||
if (image.isValid()) | |||||
{ | |||||
setSize(image.getSize()); | |||||
setGeometryConstraints(image.getWidth(), image.getHeight(), true, true); | |||||
} | |||||
setSize(image.getSize()); | |||||
setGeometryConstraints(image.getWidth(), image.getHeight(), true, true); | |||||
done(); | |||||
} | } | ||||
template <class ImageType> | template <class ImageType> | ||||
@@ -24,14 +24,37 @@ START_NAMESPACE_DGL | |||||
// ScopedGraphicsContext | // ScopedGraphicsContext | ||||
Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win) | Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win) | ||||
: window(win) | |||||
: window(win), | |||||
ppData(nullptr), | |||||
active(puglBackendEnter(window.pData->view)) {} | |||||
Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win, Window& transientWin) | |||||
: window(win), | |||||
ppData(transientWin.pData), | |||||
active(false) | |||||
{ | { | ||||
puglBackendEnter(window.pData->view); | |||||
puglBackendLeave(ppData->view); | |||||
active = puglBackendEnter(window.pData->view); | |||||
} | } | ||||
Window::ScopedGraphicsContext::~ScopedGraphicsContext() | Window::ScopedGraphicsContext::~ScopedGraphicsContext() | ||||
{ | { | ||||
puglBackendLeave(window.pData->view); | |||||
done(); | |||||
} | |||||
void Window::ScopedGraphicsContext::done() | |||||
{ | |||||
if (active) | |||||
{ | |||||
puglBackendLeave(window.pData->view); | |||||
active = false; | |||||
} | |||||
if (ppData != nullptr) | |||||
{ | |||||
puglBackendEnter(ppData->view); | |||||
ppData = nullptr; | |||||
} | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -94,6 +94,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||||
minWidth(0), | minWidth(0), | ||||
minHeight(0), | minHeight(0), | ||||
keepAspectRatio(false), | keepAspectRatio(false), | ||||
ignoreIdleCallbacks(false), | |||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
#endif | #endif | ||||
@@ -118,12 +119,12 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||||
minWidth(0), | minWidth(0), | ||||
minHeight(0), | minHeight(0), | ||||
keepAspectRatio(false), | keepAspectRatio(false), | ||||
ignoreIdleCallbacks(false), | |||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
#endif | #endif | ||||
modal(ppData) | modal(ppData) | ||||
{ | { | ||||
puglBackendLeave(transientParentView); | |||||
puglSetTransientFor(view, puglGetNativeWindow(transientParentView)); | puglSetTransientFor(view, puglGetNativeWindow(transientParentView)); | ||||
initPre(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | initPre(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | ||||
@@ -147,6 +148,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
minWidth(0), | minWidth(0), | ||||
minHeight(0), | minHeight(0), | ||||
keepAspectRatio(false), | keepAspectRatio(false), | ||||
ignoreIdleCallbacks(false), | |||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
#endif | #endif | ||||
@@ -177,6 +179,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
minWidth(0), | minWidth(0), | ||||
minHeight(0), | minHeight(0), | ||||
keepAspectRatio(false), | keepAspectRatio(false), | ||||
ignoreIdleCallbacks(false), | |||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
#endif | #endif | ||||
@@ -266,10 +269,6 @@ bool Window::PrivateData::initPost() | |||||
puglShow(view); | puglShow(view); | ||||
} | } | ||||
// give context back to transient parent window | |||||
if (transientParentView != nullptr) | |||||
puglBackendEnter(transientParentView); | |||||
return true; | return true; | ||||
} | } | ||||
@@ -317,8 +316,10 @@ void Window::PrivateData::show() | |||||
PuglRect rect = puglGetFrame(view); | PuglRect rect = puglGetFrame(view); | ||||
puglSetWindowSize(view, static_cast<uint>(rect.width), static_cast<uint>(rect.height)); | puglSetWindowSize(view, static_cast<uint>(rect.width), static_cast<uint>(rect.height)); | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
puglWin32ShowWindowCentered(view); | |||||
#if defined(DISTRHO_OS_WINDOWS) | |||||
puglWin32ShowCentered(view); | |||||
#elif defined(DISTRHO_OS_MAC) | |||||
puglMacOSShowCentered(view); | |||||
#else | #else | ||||
puglShow(view); | puglShow(view); | ||||
#endif | #endif | ||||
@@ -419,6 +420,9 @@ void Window::PrivateData::idleCallback() | |||||
bool Window::PrivateData::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | bool Window::PrivateData::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | ||||
{ | { | ||||
if (ignoreIdleCallbacks) | |||||
return false; | |||||
if (timerFrequencyInMs == 0) | if (timerFrequencyInMs == 0) | ||||
{ | { | ||||
appData->idleCallbacks.push_back(callback); | appData->idleCallbacks.push_back(callback); | ||||
@@ -430,6 +434,9 @@ bool Window::PrivateData::addIdleCallback(IdleCallback* const callback, const ui | |||||
bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback) | bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback) | ||||
{ | { | ||||
if (ignoreIdleCallbacks) | |||||
return false; | |||||
if (std::find(appData->idleCallbacks.begin(), | if (std::find(appData->idleCallbacks.begin(), | ||||
appData->idleCallbacks.end(), callback) != appData->idleCallbacks.end()) | appData->idleCallbacks.end(), callback) != appData->idleCallbacks.end()) | ||||
{ | { | ||||
@@ -459,19 +466,19 @@ bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& opti | |||||
if (startDir.isEmpty()) | if (startDir.isEmpty()) | ||||
{ | { | ||||
// TESTING verify this whole thing... | // TESTING verify this whole thing... | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
# ifdef DISTRHO_OS_WINDOWS | |||||
if (char* const cwd = _getcwd(nullptr, 0)) | if (char* const cwd = _getcwd(nullptr, 0)) | ||||
{ | { | ||||
startDir = cwd; | startDir = cwd; | ||||
std::free(cwd); | std::free(cwd); | ||||
} | } | ||||
#else | |||||
# else | |||||
if (char* const cwd = getcwd(nullptr, 0)) | if (char* const cwd = getcwd(nullptr, 0)) | ||||
{ | { | ||||
startDir = cwd; | startDir = cwd; | ||||
std::free(cwd); | std::free(cwd); | ||||
} | } | ||||
#endif | |||||
# endif | |||||
} | } | ||||
DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false); | DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false); | ||||
@@ -497,7 +504,22 @@ bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& opti | |||||
# ifdef DISTRHO_OS_MAC | # ifdef DISTRHO_OS_MAC | ||||
uint flags = 0x0; | uint flags = 0x0; | ||||
// TODO flags | |||||
if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked) | |||||
flags |= 0x001; | |||||
else if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
flags |= 0x002; | |||||
if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked) | |||||
flags |= 0x010; | |||||
else if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
flags |= 0x020; | |||||
if (options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleChecked) | |||||
flags |= 0x100; | |||||
else if (options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
flags |= 0x200; | |||||
return puglMacOSFilePanelOpen(view, startDir, title, flags, openPanelCallback); | return puglMacOSFilePanelOpen(view, startDir, title, flags, openPanelCallback); | ||||
# endif | # endif | ||||
@@ -529,6 +551,13 @@ bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& opti | |||||
ofn.lpstrFile = fileNameW.data(); | ofn.lpstrFile = fileNameW.data(); | ||||
ofn.nMaxFile = (DWORD)fileNameW.size(); | ofn.nMaxFile = (DWORD)fileNameW.size(); | ||||
// flags | |||||
ofn.Flags = OFN_PATHMUSTEXIST; | |||||
if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked) | |||||
ofn.Flags |= OFN_FORCESHOWHIDDEN; | |||||
if (options.buttons.showPlaces == FileBrowserOptions::kButtonInvisible) | |||||
ofn.FlagsEx |= OFN_EX_NOPLACESBAR; | |||||
// TODO synchronous only, can't do better with WinAPI native dialogs. | // TODO synchronous only, can't do better with WinAPI native dialogs. | ||||
// threading might work, if someone is motivated to risk it. | // threading might work, if someone is motivated to risk it. | ||||
if (GetOpenFileNameW(&ofn)) | if (GetOpenFileNameW(&ofn)) | ||||
@@ -552,7 +581,22 @@ bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& opti | |||||
# ifdef HAVE_X11 | # ifdef HAVE_X11 | ||||
uint flags = 0x0; | uint flags = 0x0; | ||||
// TODO flags | |||||
if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked) | |||||
flags |= 0x001; | |||||
else if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
flags |= 0x002; | |||||
if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked) | |||||
flags |= 0x010; | |||||
else if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
flags |= 0x020; | |||||
if (options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleChecked) | |||||
flags |= 0x100; | |||||
else if (options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
flags |= 0x200; | |||||
return sofdFileDialogShow(view, startDir, title, flags, autoScaling ? autoScaleFactor : scaleFactor); | return sofdFileDialogShow(view, startDir, title, flags, autoScaling ? autoScaleFactor : scaleFactor); | ||||
# endif | # endif | ||||
@@ -872,9 +916,9 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
///< View created, a #PuglEventCreate | ///< View created, a #PuglEventCreate | ||||
case PUGL_CREATE: | case PUGL_CREATE: | ||||
#ifdef DGL_PUGL_USING_X11 | |||||
#ifdef HAVE_X11 | |||||
if (! pData->isEmbed) | if (! pData->isEmbed) | ||||
puglExtraSetWindowTypeAndPID(view); | |||||
puglX11SetWindowTypeAndPID(view); | |||||
#endif | #endif | ||||
break; | break; | ||||
@@ -74,6 +74,9 @@ struct Window::PrivateData : IdleCallback { | |||||
uint minWidth, minHeight; | uint minWidth, minHeight; | ||||
bool keepAspectRatio; | bool keepAspectRatio; | ||||
/** Whether to ignore idle callback requests, useful for temporary windows. */ | |||||
bool ignoreIdleCallbacks; | |||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
/** Selected file for openFileBrowser on windows, stored for fake async operation. */ | /** Selected file for openFileBrowser on windows, stored for fake async operation. */ | ||||
const char* win32SelectedFile; | const char* win32SelectedFile; | ||||
@@ -159,9 +159,9 @@ START_NAMESPACE_DGL | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// expose backend enter | // expose backend enter | ||||
void puglBackendEnter(PuglView* const view) | |||||
bool puglBackendEnter(PuglView* const view) | |||||
{ | { | ||||
view->backend->enter(view, NULL); | |||||
return view->backend->enter(view, NULL) == PUGL_SUCCESS; | |||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -213,10 +213,17 @@ double puglGetDesktopScaleFactor(const PuglView* const view) | |||||
typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*); | typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*); | ||||
typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*); | typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*); | ||||
# if defined(__GNUC__) && (__GNUC__ >= 9) | |||||
# pragma GCC diagnostic push | |||||
# pragma GCC diagnostic ignored "-Wcast-function-type" | |||||
# endif | |||||
const PFN_GetProcessDpiAwareness GetProcessDpiAwareness | const PFN_GetProcessDpiAwareness GetProcessDpiAwareness | ||||
= (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness"); | = (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness"); | ||||
const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor | const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor | ||||
= (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor"); | = (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor"); | ||||
# if defined(__GNUC__) && (__GNUC__ >= 9) | |||||
# pragma GCC diagnostic pop | |||||
# endif | |||||
DWORD dpiAware = 0; | DWORD dpiAware = 0; | ||||
if (GetProcessDpiAwareness && GetScaleFactorForMonitor | if (GetProcessDpiAwareness && GetScaleFactorForMonitor | ||||
@@ -494,6 +501,33 @@ puglMacOSRemoveChildWindow(PuglView* const view, PuglView* const child) | |||||
return PUGL_FAILURE; | return PUGL_FAILURE; | ||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// macOS specific, center view based on parent coordinates (if there is one) | |||||
void puglMacOSShowCentered(PuglView* const view) | |||||
{ | |||||
if (puglShow(view) != PUGL_SUCCESS) | |||||
return; | |||||
if (view->transientParent != 0) | |||||
{ | |||||
NSWindow* const transientWindow = [(NSView*)view->transientParent window]; | |||||
DISTRHO_SAFE_ASSERT_RETURN(transientWindow != nullptr,); | |||||
const NSRect ourFrame = [view->impl->window frame]; | |||||
const NSRect transientFrame = [transientWindow frame]; | |||||
const int x = transientFrame.origin.x + transientFrame.size.width / 2 - ourFrame.size.width / 2; | |||||
const int y = transientFrame.origin.y + transientFrame.size.height / 2 + ourFrame.size.height / 2; | |||||
[view->impl->window setFrameTopLeftPoint:NSMakePoint(x, y)]; | |||||
} | |||||
else | |||||
{ | |||||
[view->impl->window center]; | |||||
} | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// macOS specific, setup file browser dialog | // macOS specific, setup file browser dialog | ||||
@@ -505,13 +539,18 @@ bool puglMacOSFilePanelOpen(PuglView* const view, | |||||
NSOpenPanel* const panel = [NSOpenPanel openPanel]; | NSOpenPanel* const panel = [NSOpenPanel openPanel]; | ||||
// TODO flags | |||||
[panel setAllowsMultipleSelection:NO]; | |||||
[panel setCanChooseFiles:YES]; | [panel setCanChooseFiles:YES]; | ||||
[panel setCanChooseDirectories:NO]; | [panel setCanChooseDirectories:NO]; | ||||
[panel setAllowsMultipleSelection:NO]; | |||||
[panel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:startDir]]]; | [panel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:startDir]]]; | ||||
// TODO file filter using allowedContentTypes: [UTType] | |||||
if (flags & 0x001) | |||||
[panel setAllowsOtherFileTypes:YES]; | |||||
if (flags & 0x010) | |||||
[panel setShowsHiddenFiles:YES]; | |||||
NSString* titleString = [[NSString alloc] | NSString* titleString = [[NSString alloc] | ||||
initWithBytes:title | initWithBytes:title | ||||
length:strlen(title) | length:strlen(title) | ||||
@@ -552,7 +591,7 @@ void puglWin32RestoreWindow(PuglView* const view) | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// win32 specific, center view based on parent coordinates (if there is one) | // win32 specific, center view based on parent coordinates (if there is one) | ||||
void puglWin32ShowWindowCentered(PuglView* const view) | |||||
void puglWin32ShowCentered(PuglView* const view) | |||||
{ | { | ||||
PuglInternals* impl = view->impl; | PuglInternals* impl = view->impl; | ||||
DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,); | ||||
@@ -596,9 +635,9 @@ void puglWin32SetWindowResizable(PuglView* const view, const bool resizable) | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// X11 specific, safer way to grab focus | // X11 specific, safer way to grab focus | ||||
PuglStatus puglX11GrabFocus(PuglView* const view) | |||||
PuglStatus puglX11GrabFocus(const PuglView* const view) | |||||
{ | { | ||||
PuglInternals* const impl = view->impl; | |||||
const PuglInternals* const impl = view->impl; | |||||
XWindowAttributes wa; | XWindowAttributes wa; | ||||
std::memset(&wa, 0, sizeof(wa)); | std::memset(&wa, 0, sizeof(wa)); | ||||
@@ -615,6 +654,29 @@ PuglStatus puglX11GrabFocus(PuglView* const view) | |||||
return PUGL_SUCCESS; | return PUGL_SUCCESS; | ||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// X11 specific, set dialog window type and pid hints | |||||
void puglX11SetWindowTypeAndPID(const PuglView* const view) | |||||
{ | |||||
const PuglInternals* const impl = view->impl; | |||||
const pid_t pid = getpid(); | |||||
const Atom _nwp = XInternAtom(impl->display, "_NET_WM_PID", False); | |||||
XChangeProperty(impl->display, impl->win, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); | |||||
const Atom _wt = XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE", False); | |||||
// Setting the window to both dialog and normal will produce a decorated floating dialog | |||||
// Order is important: DIALOG needs to come before NORMAL | |||||
const Atom _wts[2] = { | |||||
XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_DIALOG", False), | |||||
XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_NORMAL", False) | |||||
}; | |||||
XChangeProperty(impl->display, impl->win, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, 2); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// X11 specific stuff for sofd | // X11 specific stuff for sofd | ||||
@@ -637,11 +699,9 @@ bool sofdFileDialogShow(PuglView* const view, | |||||
DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false); | DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false); | ||||
DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false); | DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false); | ||||
/* | |||||
x_fib_cfg_buttons(3, options.buttons.listAllFiles-1); | |||||
x_fib_cfg_buttons(1, options.buttons.showHidden-1); | |||||
x_fib_cfg_buttons(2, options.buttons.showPlaces-1); | |||||
*/ | |||||
x_fib_cfg_buttons(3, flags & 0x001 ? 1 : flags & 0x002 ? 0 : -1); | |||||
x_fib_cfg_buttons(1, flags & 0x010 ? 1 : flags & 0x020 ? 0 : -1); | |||||
x_fib_cfg_buttons(2, flags & 0x100 ? 1 : flags & 0x200 ? 0 : -1); | |||||
return (x_fib_show(sofd_display, view->impl->win, 0, 0, scaleFactor + 0.5) == 0); | return (x_fib_show(sofd_display, view->impl->win, 0, 0, scaleFactor + 0.5) == 0); | ||||
} | } | ||||
@@ -48,7 +48,7 @@ USE_NAMESPACE_DGL | |||||
PUGL_BEGIN_DECLS | PUGL_BEGIN_DECLS | ||||
// expose backend enter | // expose backend enter | ||||
PUGL_API void | |||||
PUGL_API bool | |||||
puglBackendEnter(PuglView* view); | puglBackendEnter(PuglView* view); | ||||
// expose backend leave | // expose backend leave | ||||
@@ -108,6 +108,10 @@ puglMacOSAddChildWindow(PuglView* view, PuglView* child); | |||||
PUGL_API PuglStatus | PUGL_API PuglStatus | ||||
puglMacOSRemoveChildWindow(PuglView* view, PuglView* child); | puglMacOSRemoveChildWindow(PuglView* view, PuglView* child); | ||||
// macOS specific, center view based on parent coordinates (if there is one) | |||||
PUGL_API void | |||||
puglMacOSShowCentered(PuglView* view); | |||||
// macOS specific, setup file browser dialog | // macOS specific, setup file browser dialog | ||||
typedef void (*openPanelCallback)(PuglView* view, const char* path); | typedef void (*openPanelCallback)(PuglView* view, const char* path); | ||||
bool puglMacOSFilePanelOpen(PuglView* view, const char* startDir, const char* title, uint flags, openPanelCallback callback); | bool puglMacOSFilePanelOpen(PuglView* view, const char* startDir, const char* title, uint flags, openPanelCallback callback); | ||||
@@ -120,7 +124,7 @@ puglWin32RestoreWindow(PuglView* view); | |||||
// win32 specific, center view based on parent coordinates (if there is one) | // win32 specific, center view based on parent coordinates (if there is one) | ||||
PUGL_API void | PUGL_API void | ||||
puglWin32ShowWindowCentered(PuglView* view); | |||||
puglWin32ShowCentered(PuglView* view); | |||||
// win32 specific, set or unset WS_SIZEBOX style flag | // win32 specific, set or unset WS_SIZEBOX style flag | ||||
PUGL_API void | PUGL_API void | ||||
@@ -130,7 +134,11 @@ puglWin32SetWindowResizable(PuglView* view, bool resizable); | |||||
#ifdef HAVE_X11 | #ifdef HAVE_X11 | ||||
// X11 specific, safer way to grab focus | // X11 specific, safer way to grab focus | ||||
PUGL_API PuglStatus | PUGL_API PuglStatus | ||||
puglX11GrabFocus(PuglView* view); | |||||
puglX11GrabFocus(const PuglView* view); | |||||
// X11 specific, set dialog window type and pid hints | |||||
PUGL_API void | |||||
puglX11SetWindowTypeAndPID(const PuglView* view); | |||||
// X11 specific, show file dialog via sofd | // X11 specific, show file dialog via sofd | ||||
PUGL_API bool | PUGL_API bool | ||||
@@ -2072,7 +2072,7 @@ int x_fib_show (Display *dpy, Window parent, int x, int y, double scalefactor) { | |||||
sync_button_states () ; | sync_button_states () ; | ||||
_fib_height = _fib_font_vsep * 15.8 * (1.0 + (scalefactor - 1.0) / 2.0); | _fib_height = _fib_font_vsep * 15.8 * (1.0 + (scalefactor - 1.0) / 2.0); | ||||
_fib_width = MAX (_btn_span, 440 * scalefactor); | |||||
_fib_width = MAX (_btn_span, 480 * scalefactor); | |||||
XResizeWindow (dpy, _fib_win, _fib_width, _fib_height); | XResizeWindow (dpy, _fib_win, _fib_width, _fib_height); | ||||
@@ -303,17 +303,26 @@ protected: | |||||
*/ | */ | ||||
virtual void uiFileBrowserSelected(const char* filename); | virtual void uiFileBrowserSelected(const char* filename); | ||||
# endif | # endif | ||||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
* UI Resize Handling, internal */ | * UI Resize Handling, internal */ | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/** | |||||
External Window resize function, called when the window is resized. | |||||
This is overriden here so the host knows when the UI is resized by you. | |||||
@see ExternalWindow::sizeChanged(uint,uint) | |||||
*/ | |||||
void sizeChanged(uint width, uint height) override; | |||||
#else | |||||
/** | /** | ||||
OpenGL widget resize function, called when the widget is resized. | |||||
Widget resize function, called when the widget is resized. | |||||
This is overriden here so the host knows when the UI is resized by you. | This is overriden here so the host knows when the UI is resized by you. | ||||
@see Widget::onResize(const ResizeEvent&) | @see Widget::onResize(const ResizeEvent&) | ||||
*/ | */ | ||||
void onResize(const ResizeEvent& ev) override; | void onResize(const ResizeEvent& ev) override; | ||||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#endif | |||||
// ------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------- | ||||
@@ -19,6 +19,28 @@ | |||||
#endif | #endif | ||||
#include "src/DistrhoPluginChecks.h" | #include "src/DistrhoPluginChecks.h" | ||||
#include "src/DistrhoDefines.h" | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#import <Cocoa/Cocoa.h> | |||||
#include <algorithm> | |||||
#include <cmath> | |||||
START_NAMESPACE_DISTRHO | |||||
double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | |||||
{ | |||||
// allow custom scale for testing | |||||
if (const char* const scale = getenv("DPF_SCALE_FACTOR")) | |||||
return std::max(1.0, std::atof(scale)); | |||||
if (NSView* const parentView = (NSView*)parentWindowHandle) | |||||
if (NSWindow* const parentWindow = [parentView window]) | |||||
return [parentWindow screen].backingScaleFactor; | |||||
return [NSScreen mainScreen].backingScaleFactor; | |||||
} | |||||
END_NAMESPACE_DISTRHO | |||||
#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#include "../dgl/Base.hpp" | #include "../dgl/Base.hpp" | ||||
#define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(DGL_NS, SEP, PUGL_NS, INTERFACE) DGL_NS ## SEP ## PUGL_NS ## SEP ## INTERFACE | #define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(DGL_NS, SEP, PUGL_NS, INTERFACE) DGL_NS ## SEP ## PUGL_NS ## SEP ## INTERFACE | ||||
@@ -33,3 +55,4 @@ | |||||
#define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, WrapperView) | #define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, WrapperView) | ||||
#import "src/pugl.mm" | #import "src/pugl.mm" | ||||
#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI |
@@ -19,9 +19,7 @@ | |||||
#include "String.hpp" | #include "String.hpp" | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
# error Unsupported platform! | |||||
#else | |||||
#ifndef DISTRHO_OS_WINDOWS | |||||
# include <cerrno> | # include <cerrno> | ||||
# include <signal.h> | # include <signal.h> | ||||
# include <sys/wait.h> | # include <sys/wait.h> | ||||
@@ -106,9 +104,10 @@ public: | |||||
*/ | */ | ||||
virtual bool isRunning() const | virtual bool isRunning() const | ||||
{ | { | ||||
#ifndef DISTRHO_OS_WINDOWS | |||||
if (ext.inUse) | if (ext.inUse) | ||||
return ext.isRunning(); | return ext.isRunning(); | ||||
#endif | |||||
return isVisible(); | return isVisible(); | ||||
} | } | ||||
@@ -119,7 +118,11 @@ public: | |||||
*/ | */ | ||||
virtual bool isQuitting() const | virtual bool isQuitting() const | ||||
{ | { | ||||
#ifndef DISTRHO_OS_WINDOWS | |||||
return ext.inUse ? ext.isQuitting : pData.isQuitting; | return ext.inUse ? ext.isQuitting : pData.isQuitting; | ||||
#else | |||||
return pData.isQuitting; | |||||
#endif | |||||
} | } | ||||
/** | /** | ||||
@@ -259,9 +262,10 @@ public: | |||||
{ | { | ||||
pData.isQuitting = true; | pData.isQuitting = true; | ||||
hide(); | hide(); | ||||
#ifndef DISTRHO_OS_WINDOWS | |||||
if (ext.inUse) | if (ext.inUse) | ||||
terminateAndWaitForExternalProcess(); | terminateAndWaitForExternalProcess(); | ||||
#endif | |||||
} | } | ||||
/** | /** | ||||
@@ -293,7 +297,7 @@ public: | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_UINT2_RETURN(width > 1 && height > 1, width, height,); | DISTRHO_SAFE_ASSERT_UINT2_RETURN(width > 1 && height > 1, width, height,); | ||||
if (pData.width == width || pData.height == height) | |||||
if (pData.width == width && pData.height == height) | |||||
return; | return; | ||||
pData.width = width; | pData.width = width; | ||||
@@ -357,15 +361,24 @@ protected: | |||||
bool startExternalProcess(const char* args[]) | bool startExternalProcess(const char* args[]) | ||||
{ | { | ||||
#ifndef DISTRHO_OS_WINDOWS | |||||
ext.inUse = true; | ext.inUse = true; | ||||
return ext.start(args); | return ext.start(args); | ||||
#else | |||||
(void)args; | |||||
return false; // TODO | |||||
#endif | |||||
} | } | ||||
void terminateAndWaitForExternalProcess() | void terminateAndWaitForExternalProcess() | ||||
{ | { | ||||
#ifndef DISTRHO_OS_WINDOWS | |||||
ext.isQuitting = true; | ext.isQuitting = true; | ||||
ext.terminateAndWait(); | ext.terminateAndWait(); | ||||
#else | |||||
// TODO | |||||
#endif | |||||
} | } | ||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
@@ -414,6 +427,7 @@ private: | |||||
friend class PluginWindow; | friend class PluginWindow; | ||||
friend class UI; | friend class UI; | ||||
#ifndef DISTRHO_OS_WINDOWS | |||||
struct ExternalProcess { | struct ExternalProcess { | ||||
bool inUse; | bool inUse; | ||||
bool isQuitting; | bool isQuitting; | ||||
@@ -510,6 +524,7 @@ private: | |||||
} | } | ||||
} | } | ||||
} ext; | } ext; | ||||
#endif | |||||
struct PrivateData { | struct PrivateData { | ||||
uintptr_t parentWindowHandle; | uintptr_t parentWindowHandle; | ||||
@@ -85,9 +85,11 @@ public: | |||||
fLastControlValues(nullptr), | fLastControlValues(nullptr), | ||||
fSampleRate(sampleRate), | fSampleRate(sampleRate), | ||||
fURIDs(uridMap), | fURIDs(uridMap), | ||||
#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST | |||||
fCtrlInPortChangeReq(ctrlInPortChangeReq), | |||||
#endif | |||||
fUridMap(uridMap), | fUridMap(uridMap), | ||||
fWorker(worker), | |||||
fCtrlInPortChangeReq(ctrlInPortChangeReq) | |||||
fWorker(worker) | |||||
{ | { | ||||
#if DISTRHO_PLUGIN_NUM_INPUTS > 0 | #if DISTRHO_PLUGIN_NUM_INPUTS > 0 | ||||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) | for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) | ||||
@@ -157,6 +159,11 @@ public: | |||||
// unused | // unused | ||||
(void)fWorker; | (void)fWorker; | ||||
#endif | #endif | ||||
#if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST | |||||
// unused | |||||
(void)ctrlInPortChangeReq; | |||||
#endif | |||||
} | } | ||||
~PluginLv2() | ~PluginLv2() | ||||
@@ -1178,9 +1185,11 @@ private: | |||||
} fURIDs; | } fURIDs; | ||||
// LV2 features | // LV2 features | ||||
#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST | |||||
const LV2_ControlInputPort_Change_Request* const fCtrlInPortChangeReq; | |||||
#endif | |||||
const LV2_URID_Map* const fUridMap; | const LV2_URID_Map* const fUridMap; | ||||
const LV2_Worker_Schedule* const fWorker; | const LV2_Worker_Schedule* const fWorker; | ||||
const LV2_ControlInputPort_Change_Request* const fCtrlInPortChangeReq; | |||||
#if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
StringToStringMap fStateMap; | StringToStringMap fStateMap; | ||||
@@ -14,21 +14,117 @@ | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
*/ | */ | ||||
#include "DistrhoUIPrivateData.hpp" | |||||
#include "src/WindowPrivateData.hpp" | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#include "src/DistrhoPluginChecks.h" | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# if defined(DISTRHO_OS_WINDOWS) | |||||
# define WIN32_LEAN_AND_MEAN | |||||
# include <windows.h> | |||||
# elif defined(HAVE_X11) | |||||
# include <X11/Xresource.h> | |||||
# endif | |||||
#else | |||||
# include "src/TopLevelWidgetPrivateData.hpp" | # include "src/TopLevelWidgetPrivateData.hpp" | ||||
# include "src/WindowPrivateData.hpp" | |||||
#endif | #endif | ||||
#include "DistrhoUIPrivateData.hpp" | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* Static data, see DistrhoUIInternal.hpp */ | * Static data, see DistrhoUIInternal.hpp */ | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
uintptr_t g_nextWindowId = 0; | uintptr_t g_nextWindowId = 0; | ||||
double g_nextScaleFactor = 1.0; | double g_nextScaleFactor = 1.0; | ||||
const char* g_nextBundlePath = nullptr; | const char* g_nextBundlePath = nullptr; | ||||
/* ------------------------------------------------------------------------------------------------------------ | |||||
* get global scale factor */ | |||||
#ifdef DISTRHO_OS_MAC | |||||
double getDesktopScaleFactor(uintptr_t parentWindowHandle); | |||||
#else | |||||
static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | |||||
{ | |||||
// allow custom scale for testing | |||||
if (const char* const scale = getenv("DPF_SCALE_FACTOR")) | |||||
return std::max(1.0, std::atof(scale)); | |||||
#if defined(DISTRHO_OS_WINDOWS) | |||||
if (const HMODULE Shcore = LoadLibraryA("Shcore.dll")) | |||||
{ | |||||
typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*); | |||||
typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*); | |||||
# if defined(__GNUC__) && (__GNUC__ >= 9) | |||||
# pragma GCC diagnostic push | |||||
# pragma GCC diagnostic ignored "-Wcast-function-type" | |||||
# endif | |||||
const PFN_GetProcessDpiAwareness GetProcessDpiAwareness | |||||
= (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness"); | |||||
const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor | |||||
= (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor"); | |||||
# if defined(__GNUC__) && (__GNUC__ >= 9) | |||||
# pragma GCC diagnostic pop | |||||
# endif | |||||
DWORD dpiAware = 0; | |||||
if (GetProcessDpiAwareness && GetScaleFactorForMonitor | |||||
&& GetProcessDpiAwareness(NULL, &dpiAware) == 0 && dpiAware != 0) | |||||
{ | |||||
const HMONITOR hMon = parentWindowHandle != 0 | |||||
? MonitorFromWindow((HWND)parentWindowHandle, MONITOR_DEFAULTTOPRIMARY) | |||||
: MonitorFromPoint(POINT{0,0}, MONITOR_DEFAULTTOPRIMARY); | |||||
DWORD scaleFactor = 0; | |||||
if (GetScaleFactorForMonitor(hMon, &scaleFactor) == 0 && scaleFactor != 0) | |||||
{ | |||||
FreeLibrary(Shcore); | |||||
return static_cast<double>(scaleFactor) / 100.0; | |||||
} | |||||
} | |||||
FreeLibrary(Shcore); | |||||
} | |||||
#elif defined(HAVE_X11) | |||||
::Display* const display = XOpenDisplay(nullptr); | |||||
DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1.0); | |||||
XrmInitialize(); | |||||
if (char* const rms = XResourceManagerString(display)) | |||||
{ | |||||
if (const XrmDatabase sdb = XrmGetStringDatabase(rms)) | |||||
{ | |||||
char* type = nullptr; | |||||
XrmValue ret; | |||||
if (XrmGetResource(sdb, "Xft.dpi", "String", &type, &ret) | |||||
&& ret.addr != nullptr | |||||
&& type != nullptr | |||||
&& std::strncmp("String", type, 6) == 0) | |||||
{ | |||||
if (const double dpi = std::atof(ret.addr)) | |||||
{ | |||||
XCloseDisplay(display); | |||||
return dpi / 96; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
XCloseDisplay(display); | |||||
#endif | |||||
return 1.0; | |||||
// might be unused | |||||
(void)parentWindowHandle; | |||||
} | |||||
#endif // !DISTRHO_OS_MAC | |||||
#endif | #endif | ||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
@@ -50,12 +146,17 @@ UI::PrivateData::createNextWindow(UI* const ui, const uint width, const uint hei | |||||
ewData.parentWindowHandle = pData->winId; | ewData.parentWindowHandle = pData->winId; | ||||
ewData.width = width; | ewData.width = width; | ||||
ewData.height = height; | ewData.height = height; | ||||
ewData.scaleFactor = pData->scaleFactor; | |||||
ewData.scaleFactor = pData->scaleFactor != 0.0 ? pData->scaleFactor : getDesktopScaleFactor(pData->winId); | |||||
ewData.title = DISTRHO_PLUGIN_NAME; | ewData.title = DISTRHO_PLUGIN_NAME; | ||||
ewData.isStandalone = DISTRHO_UI_IS_STANDALONE; | ewData.isStandalone = DISTRHO_UI_IS_STANDALONE; | ||||
return ewData; | return ewData; | ||||
#else | #else | ||||
pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, pData->scaleFactor); | pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, pData->scaleFactor); | ||||
// If there are no callbacks, this is most likely a temporary window, so ignore idle callbacks | |||||
if (pData->callbacksPtr == nullptr) | |||||
pData->window->setIgnoreIdleCallbacks(); | |||||
return pData->window.getObject(); | return pData->window.getObject(); | ||||
#endif | #endif | ||||
} | } | ||||
@@ -209,10 +310,19 @@ void UI::uiFileBrowserSelected(const char*) | |||||
{ | { | ||||
} | } | ||||
# endif | # endif | ||||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* UI Resize Handling, internal */ | * UI Resize Handling, internal */ | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
void UI::sizeChanged(const uint width, const uint height) | |||||
{ | |||||
UIWidget::sizeChanged(width, height); | |||||
uiData->setSizeCallback(width, height); | |||||
} | |||||
#else | |||||
void UI::onResize(const ResizeEvent& ev) | void UI::onResize(const ResizeEvent& ev) | ||||
{ | { | ||||
UIWidget::onResize(ev); | UIWidget::onResize(ev); | ||||
@@ -221,7 +331,7 @@ void UI::onResize(const ResizeEvent& ev) | |||||
const uint height = ev.size.getHeight(); | const uint height = ev.size.getHeight(); | ||||
uiData->setSizeCallback(width, height); | uiData->setSizeCallback(width, height); | ||||
} | } | ||||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#endif | |||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
@@ -91,6 +91,7 @@ public: | |||||
g_nextScaleFactor = 0.0; | g_nextScaleFactor = 0.0; | ||||
g_nextBundlePath = nullptr; | g_nextBundlePath = nullptr; | ||||
#else | #else | ||||
// Leave context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp | |||||
uiData->window->leaveContext(); | uiData->window->leaveContext(); | ||||
#endif | #endif | ||||
UI::PrivateData::s_nextPrivateData = nullptr; | UI::PrivateData::s_nextPrivateData = nullptr; | ||||
@@ -106,6 +107,7 @@ public: | |||||
~UIExporter() | ~UIExporter() | ||||
{ | { | ||||
quit(); | |||||
delete ui; | delete ui; | ||||
delete uiData; | delete uiData; | ||||
} | } | ||||
@@ -227,9 +229,7 @@ public: | |||||
void quit() | void quit() | ||||
{ | { | ||||
uiData->window->close(); | uiData->window->close(); | ||||
if (uiData->app.isStandalone()) | |||||
uiData->app.quit(); | |||||
uiData->app.quit(); | |||||
} | } | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -52,14 +52,14 @@ START_NAMESPACE_DGL | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
struct PluginApplication | struct PluginApplication | ||||
{ | { | ||||
IdleCallback* idleCallback; | |||||
DGL_NAMESPACE::IdleCallback* idleCallback; | |||||
UI* ui; | UI* ui; | ||||
explicit PluginApplication() | explicit PluginApplication() | ||||
: idleCallback(nullptr), | : idleCallback(nullptr), | ||||
ui(nullptr) {} | ui(nullptr) {} | ||||
void addIdleCallback(IdleCallback* const cb) | |||||
void addIdleCallback(DGL_NAMESPACE::IdleCallback* const cb) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(idleCallback == nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(idleCallback == nullptr,); | ||||
@@ -187,6 +187,11 @@ public: | |||||
puglBackendLeave(pData->view); | puglBackendLeave(pData->view); | ||||
} | } | ||||
void setIgnoreIdleCallbacks(const bool ignore = true) | |||||
{ | |||||
pData->ignoreIdleCallbacks = ignore; | |||||
} | |||||
protected: | protected: | ||||
void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override | void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override | ||||
{ | { | ||||
@@ -42,6 +42,19 @@ typedef DGL_NAMESPACE::VulkanImage DemoImage; | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// Partial specialization is not allowed in C++, so we need to define these here | |||||
template<> inline | |||||
ExampleImagesWidget<SubWidget, DemoImage>::ExampleImagesWidget(Widget* const parentWidget) | |||||
: SubWidget(parentWidget) { init(parentWidget->getApp()); } | |||||
template<> inline | |||||
ExampleImagesWidget<TopLevelWidget, DemoImage>::ExampleImagesWidget(Window& windowToMapTo) | |||||
: TopLevelWidget(windowToMapTo) { init(windowToMapTo.getApp()); } | |||||
template<> | |||||
ExampleImagesWidget<StandaloneWindow, DemoImage>::ExampleImagesWidget(Application& app) | |||||
: StandaloneWindow(app) { init(app); done(); } | |||||
typedef ExampleImagesWidget<SubWidget, DemoImage> ExampleImagesSubWidget; | typedef ExampleImagesWidget<SubWidget, DemoImage> ExampleImagesSubWidget; | ||||
typedef ExampleImagesWidget<TopLevelWidget, DemoImage> ExampleImagesTopLevelWidget; | typedef ExampleImagesWidget<TopLevelWidget, DemoImage> ExampleImagesTopLevelWidget; | ||||
typedef ExampleImagesWidget<StandaloneWindow, DemoImage> ExampleImagesStandaloneWindow; | typedef ExampleImagesWidget<StandaloneWindow, DemoImage> ExampleImagesStandaloneWindow; | ||||
@@ -435,6 +448,7 @@ public: | |||||
resizer = new ResizeHandle(this); | resizer = new ResizeHandle(this); | ||||
curPageChanged(0); | curPageChanged(0); | ||||
done(); | |||||
} | } | ||||
protected: | protected: | ||||
@@ -37,6 +37,11 @@ public: | |||||
#ifndef DGL_NO_SHARED_RESOURCES | #ifndef DGL_NO_SHARED_RESOURCES | ||||
loadSharedResources(); | loadSharedResources(); | ||||
#endif | #endif | ||||
setResizable(true); | |||||
setSize(500, 200); | |||||
setGeometryConstraints(500, 200, true); | |||||
setTitle("FileBrowserDialog"); | |||||
done(); | |||||
} | } | ||||
protected: | protected: | ||||
@@ -170,8 +175,6 @@ int main() | |||||
Application app(true); | Application app(true); | ||||
NanoFilePicker win(app); | NanoFilePicker win(app); | ||||
win.setSize(500, 200); | |||||
win.setTitle("FileBrowserDialog"); | |||||
win.show(); | win.show(); | ||||
app.exec(); | app.exec(); | ||||
@@ -127,9 +127,13 @@ class NanoExampleWindow : public Window | |||||
{ | { | ||||
public: | public: | ||||
explicit NanoExampleWindow(Application& app) | explicit NanoExampleWindow(Application& app) | ||||
: Window(app), | |||||
container(*this) | |||||
: Window(app) | |||||
{ | { | ||||
{ | |||||
const ScopedGraphicsContext sgc(*this); | |||||
container = new NanoRectanglesContainer(*this); | |||||
} | |||||
const uint targetWidth = 400; | const uint targetWidth = 400; | ||||
const uint targetHeight = 400; | const uint targetHeight = 400; | ||||
const double scaleFactor = getScaleFactor(); | const double scaleFactor = getScaleFactor(); | ||||
@@ -141,7 +145,7 @@ public: | |||||
} | } | ||||
private: | private: | ||||
NanoRectanglesContainer container; | |||||
ScopedPointer<NanoRectanglesContainer> container; | |||||
}; | }; | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -154,7 +158,6 @@ int main() | |||||
Application app; | Application app; | ||||
NanoExampleWindow win(app); | NanoExampleWindow win(app); | ||||
win.show(); | win.show(); | ||||
app.exec(); | app.exec(); | ||||
@@ -165,6 +165,7 @@ ExampleColorWidget<StandaloneWindow>::ExampleColorWidget(Application& app) | |||||
{ | { | ||||
setSize(300, 300); | setSize(300, 300); | ||||
addIdleCallback(this); | addIdleCallback(this); | ||||
done(); | |||||
} | } | ||||
typedef ExampleColorWidget<SubWidget> ExampleColorSubWidget; | typedef ExampleColorWidget<SubWidget> ExampleColorSubWidget; | ||||
@@ -21,8 +21,8 @@ | |||||
// DGL Stuff | // DGL Stuff | ||||
#include "../../dgl/ImageBase.hpp" | #include "../../dgl/ImageBase.hpp" | ||||
#include "../../dgl/StandaloneWindow.hpp" | |||||
#include "../../dgl/SubWidget.hpp" | #include "../../dgl/SubWidget.hpp" | ||||
#include "../../dgl/TopLevelWidget.hpp" | |||||
// ------------------------------------------------------ | // ------------------------------------------------------ | ||||
// Images | // Images | ||||
@@ -55,69 +55,34 @@ public: | |||||
static constexpr const char* kExampleWidgetName = "Images"; | static constexpr const char* kExampleWidgetName = "Images"; | ||||
// SubWidget | // SubWidget | ||||
ExampleImagesWidget(Widget* const parent) | |||||
: BaseWidget(parent), | |||||
imgTop1st(1), | |||||
imgTop2nd(2), | |||||
imgTop3rd(3), | |||||
img1x(0), | |||||
img2x(kImg2max), | |||||
img3y(kImg3max), | |||||
img1rev(false), | |||||
img2rev(true), | |||||
img3rev(true), | |||||
img1(CatPics::cat1Data, CatPics::cat1Width, CatPics::cat1Height, kImageFormatBGR), | |||||
img2(CatPics::cat2Data, CatPics::cat2Width, CatPics::cat2Height, kImageFormatBGR), | |||||
img3(CatPics::cat3Data, CatPics::cat3Width, CatPics::cat3Height, kImageFormatBGR) | |||||
{ | |||||
BaseWidget::setSize(500, 400); | |||||
parent->getApp().addIdleCallback(this); | |||||
} | |||||
explicit ExampleImagesWidget(Widget* const parent); | |||||
// TopLevelWidget | // TopLevelWidget | ||||
ExampleImagesWidget(Window& windowToMapTo) | |||||
: BaseWidget(windowToMapTo), | |||||
imgTop1st(1), | |||||
imgTop2nd(2), | |||||
imgTop3rd(3), | |||||
img1x(0), | |||||
img2x(kImg2max), | |||||
img3y(kImg3max), | |||||
img1rev(false), | |||||
img2rev(true), | |||||
img3rev(true), | |||||
img1(CatPics::cat1Data, CatPics::cat1Width, CatPics::cat1Height, kImageFormatBGR), | |||||
img2(CatPics::cat2Data, CatPics::cat2Width, CatPics::cat2Height, kImageFormatBGR), | |||||
img3(CatPics::cat3Data, CatPics::cat3Width, CatPics::cat3Height, kImageFormatBGR) | |||||
{ | |||||
BaseWidget::setSize(500, 400); | |||||
windowToMapTo.getApp().addIdleCallback(this); | |||||
} | |||||
explicit ExampleImagesWidget(Window& windowToMapTo); | |||||
// StandaloneWindow | // StandaloneWindow | ||||
ExampleImagesWidget(Application& app) | |||||
: BaseWidget(app), | |||||
imgTop1st(1), | |||||
imgTop2nd(2), | |||||
imgTop3rd(3), | |||||
img1x(0), | |||||
img2x(kImg2max), | |||||
img3y(kImg3max), | |||||
img1rev(false), | |||||
img2rev(true), | |||||
img3rev(true), | |||||
img1(CatPics::cat1Data, CatPics::cat1Width, CatPics::cat1Height, kImageFormatBGR), | |||||
img2(CatPics::cat2Data, CatPics::cat2Width, CatPics::cat2Height, kImageFormatBGR), | |||||
img3(CatPics::cat3Data, CatPics::cat3Width, CatPics::cat3Height, kImageFormatBGR) | |||||
explicit ExampleImagesWidget(Application& app); | |||||
protected: | |||||
void init(Application& app) | |||||
{ | { | ||||
BaseWidget::setSize(500, 400); | |||||
imgTop1st = 1; | |||||
imgTop2nd = 2; | |||||
imgTop3rd = 3; | |||||
img1x = 0; | |||||
img2x = kImg2max; | |||||
img3y = kImg3max; | |||||
img1rev = false; | |||||
img2rev = true; | |||||
img3rev = true; | |||||
img1 = BaseImage(CatPics::cat1Data, CatPics::cat1Width, CatPics::cat1Height, kImageFormatBGR); | |||||
img2 = BaseImage(CatPics::cat2Data, CatPics::cat2Width, CatPics::cat2Height, kImageFormatBGR); | |||||
img3 = BaseImage(CatPics::cat3Data, CatPics::cat3Width, CatPics::cat3Height, kImageFormatBGR); | |||||
BaseWidget::setSize(500, 400); | |||||
app.addIdleCallback(this); | app.addIdleCallback(this); | ||||
} | } | ||||
protected: | |||||
void idleCallback() noexcept override | void idleCallback() noexcept override | ||||
{ | { | ||||
if (img1rev) | if (img1rev) | ||||
@@ -21,8 +21,8 @@ | |||||
// DGL Stuff | // DGL Stuff | ||||
#include "../../dgl/Color.hpp" | #include "../../dgl/Color.hpp" | ||||
#include "../../dgl/StandaloneWindow.hpp" | |||||
#include "../../dgl/SubWidget.hpp" | #include "../../dgl/SubWidget.hpp" | ||||
#include "../../dgl/TopLevelWidget.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
@@ -37,23 +37,14 @@ class ExampleRectanglesWidget : public BaseWidget | |||||
public: | public: | ||||
static constexpr const char* const kExampleWidgetName = "Rectangles"; | static constexpr const char* const kExampleWidgetName = "Rectangles"; | ||||
explicit ExampleRectanglesWidget(Widget* const parentWidget) | |||||
: BaseWidget(parentWidget) | |||||
{ | |||||
init(); | |||||
} | |||||
// SubWidget | |||||
explicit ExampleRectanglesWidget(Widget* const parent); | |||||
explicit ExampleRectanglesWidget(Window& windowToMapTo) | |||||
: BaseWidget(windowToMapTo) | |||||
{ | |||||
init(); | |||||
} | |||||
// TopLevelWidget | |||||
explicit ExampleRectanglesWidget(Window& windowToMapTo); | |||||
explicit ExampleRectanglesWidget(Application& app) | |||||
: BaseWidget(app) | |||||
{ | |||||
init(); | |||||
} | |||||
// StandaloneWindow | |||||
explicit ExampleRectanglesWidget(Application& app); | |||||
void init() | void init() | ||||
{ | { | ||||
@@ -166,6 +157,31 @@ protected: | |||||
} | } | ||||
}; | }; | ||||
// SubWidget | |||||
template<> inline | |||||
ExampleRectanglesWidget<SubWidget>::ExampleRectanglesWidget(Widget* const parentWidget) | |||||
: SubWidget(parentWidget) | |||||
{ | |||||
init(); | |||||
} | |||||
// TopLevelWidget | |||||
template<> inline | |||||
ExampleRectanglesWidget<TopLevelWidget>::ExampleRectanglesWidget(Window& windowToMapTo) | |||||
: TopLevelWidget(windowToMapTo) | |||||
{ | |||||
init(); | |||||
} | |||||
// StandaloneWindow | |||||
template<> inline | |||||
ExampleRectanglesWidget<StandaloneWindow>::ExampleRectanglesWidget(Application& app) | |||||
: StandaloneWindow(app) | |||||
{ | |||||
init(); | |||||
done(); | |||||
} | |||||
typedef ExampleRectanglesWidget<SubWidget> ExampleRectanglesSubWidget; | typedef ExampleRectanglesWidget<SubWidget> ExampleRectanglesSubWidget; | ||||
typedef ExampleRectanglesWidget<TopLevelWidget> ExampleRectanglesTopLevelWidget; | typedef ExampleRectanglesWidget<TopLevelWidget> ExampleRectanglesTopLevelWidget; | ||||
typedef ExampleRectanglesWidget<StandaloneWindow> ExampleRectanglesStandaloneWindow; | typedef ExampleRectanglesWidget<StandaloneWindow> ExampleRectanglesStandaloneWindow; | ||||
@@ -21,8 +21,8 @@ | |||||
// DGL Stuff | // DGL Stuff | ||||
#include "../../dgl/Color.hpp" | #include "../../dgl/Color.hpp" | ||||
#include "../../dgl/StandaloneWindow.hpp" | |||||
#include "../../dgl/SubWidget.hpp" | #include "../../dgl/SubWidget.hpp" | ||||
#include "../../dgl/TopLevelWidget.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
@@ -40,23 +40,14 @@ class ExampleShapesWidget : public BaseWidget | |||||
public: | public: | ||||
static constexpr const char* const kExampleWidgetName = "Shapes"; | static constexpr const char* const kExampleWidgetName = "Shapes"; | ||||
explicit ExampleShapesWidget(Widget* const parentWidget) | |||||
: BaseWidget(parentWidget) | |||||
{ | |||||
this->setSize(300, 300); | |||||
} | |||||
// SubWidget | |||||
explicit ExampleShapesWidget(Widget* const parent); | |||||
explicit ExampleShapesWidget(Window& windowToMapTo) | |||||
: BaseWidget(windowToMapTo) | |||||
{ | |||||
this->setSize(300, 300); | |||||
} | |||||
// TopLevelWidget | |||||
explicit ExampleShapesWidget(Window& windowToMapTo); | |||||
explicit ExampleShapesWidget(Application& app) | |||||
: BaseWidget(app) | |||||
{ | |||||
this->setSize(300, 300); | |||||
} | |||||
// StandaloneWindow | |||||
explicit ExampleShapesWidget(Application& app); | |||||
protected: | protected: | ||||
void onDisplay() override | void onDisplay() override | ||||
@@ -104,6 +95,31 @@ protected: | |||||
} | } | ||||
}; | }; | ||||
// SubWidget | |||||
template<> inline | |||||
ExampleShapesWidget<SubWidget>::ExampleShapesWidget(Widget* const parentWidget) | |||||
: SubWidget(parentWidget) | |||||
{ | |||||
setSize(300, 300); | |||||
} | |||||
// TopLevelWidget | |||||
template<> inline | |||||
ExampleShapesWidget<TopLevelWidget>::ExampleShapesWidget(Window& windowToMapTo) | |||||
: TopLevelWidget(windowToMapTo) | |||||
{ | |||||
setSize(300, 300); | |||||
} | |||||
// StandaloneWindow | |||||
template<> inline | |||||
ExampleShapesWidget<StandaloneWindow>::ExampleShapesWidget(Application& app) | |||||
: StandaloneWindow(app) | |||||
{ | |||||
setSize(300, 300); | |||||
done(); | |||||
} | |||||
typedef ExampleShapesWidget<SubWidget> ExampleShapesSubWidget; | typedef ExampleShapesWidget<SubWidget> ExampleShapesSubWidget; | ||||
typedef ExampleShapesWidget<TopLevelWidget> ExampleShapesTopLevelWidget; | typedef ExampleShapesWidget<TopLevelWidget> ExampleShapesTopLevelWidget; | ||||
typedef ExampleShapesWidget<StandaloneWindow> ExampleShapesStandaloneWindow; | typedef ExampleShapesWidget<StandaloneWindow> ExampleShapesStandaloneWindow; | ||||
@@ -62,6 +62,7 @@ protected: | |||||
} | } | ||||
}; | }; | ||||
// SubWidget | |||||
template<> inline | template<> inline | ||||
ExampleTextWidget<NanoSubWidget>::ExampleTextWidget(Widget* const parent) | ExampleTextWidget<NanoSubWidget>::ExampleTextWidget(Widget* const parent) | ||||
: NanoSubWidget(parent) | : NanoSubWidget(parent) | ||||
@@ -70,6 +71,7 @@ ExampleTextWidget<NanoSubWidget>::ExampleTextWidget(Widget* const parent) | |||||
setSize(500, 300); | setSize(500, 300); | ||||
} | } | ||||
// TopLevelWidget | |||||
template<> inline | template<> inline | ||||
ExampleTextWidget<NanoTopLevelWidget>::ExampleTextWidget(Window& windowToMapTo) | ExampleTextWidget<NanoTopLevelWidget>::ExampleTextWidget(Window& windowToMapTo) | ||||
: NanoTopLevelWidget(windowToMapTo) | : NanoTopLevelWidget(windowToMapTo) | ||||
@@ -78,12 +80,14 @@ ExampleTextWidget<NanoTopLevelWidget>::ExampleTextWidget(Window& windowToMapTo) | |||||
setSize(500, 300); | setSize(500, 300); | ||||
} | } | ||||
// StandaloneWindow | |||||
template<> inline | template<> inline | ||||
ExampleTextWidget<NanoStandaloneWindow>::ExampleTextWidget(Application& app) | ExampleTextWidget<NanoStandaloneWindow>::ExampleTextWidget(Application& app) | ||||
: NanoStandaloneWindow(app) | : NanoStandaloneWindow(app) | ||||
{ | { | ||||
loadSharedResources(); | loadSharedResources(); | ||||
setSize(500, 300); | setSize(500, 300); | ||||
done(); | |||||
} | } | ||||
template class ExampleTextWidget<NanoSubWidget>; | template class ExampleTextWidget<NanoSubWidget>; | ||||
@@ -19,7 +19,7 @@ for i in $PLUGINS; do | |||||
cp -r ${DPF_DIR}/utils/plugin.vst/ ${BUNDLE}.vst | cp -r ${DPF_DIR}/utils/plugin.vst/ ${BUNDLE}.vst | ||||
mv ${i} ${BUNDLE}.vst/Contents/MacOS/${BUNDLE} | mv ${i} ${BUNDLE}.vst/Contents/MacOS/${BUNDLE} | ||||
rm -f ${BUNDLE}.vst/Contents/MacOS/deleteme | rm -f ${BUNDLE}.vst/Contents/MacOS/deleteme | ||||
sed -i -e "s/X-PROJECTNAME-X/${BUNDLE}/" ${BUNDLE}.vst/Contents/Info.plist | |||||
sed -i -e "s/@INFO_PLIST_PROJECT_NAME@/${BUNDLE}/" ${BUNDLE}.vst/Contents/Info.plist | |||||
rm -f ${BUNDLE}.vst/Contents/Info.plist-e | rm -f ${BUNDLE}.vst/Contents/Info.plist-e | ||||
done | done | ||||
@@ -5,11 +5,11 @@ | |||||
<key>CFBundleDevelopmentRegion</key> | <key>CFBundleDevelopmentRegion</key> | ||||
<string>English</string> | <string>English</string> | ||||
<key>CFBundleExecutable</key> | <key>CFBundleExecutable</key> | ||||
<string>X-PROJECTNAME-X</string> | |||||
<string>@INFO_PLIST_PROJECT_NAME@</string> | |||||
<key>CFBundleIconFile</key> | <key>CFBundleIconFile</key> | ||||
<string></string> | <string></string> | ||||
<key>CFBundleIdentifier</key> | <key>CFBundleIdentifier</key> | ||||
<string>studio.kx.distrho.X-PROJECTNAME-X</string> | |||||
<string>studio.kx.distrho.@INFO_PLIST_PROJECT_NAME@</string> | |||||
<key>CFBundleInfoDictionaryVersion</key> | <key>CFBundleInfoDictionaryVersion</key> | ||||
<string>6.0</string> | <string>6.0</string> | ||||
<key>CFBundlePackageType</key> | <key>CFBundlePackageType</key> | ||||
@@ -16,9 +16,15 @@ cd repos | |||||
git clone --depth 1 --recursive -b develop git://github.com/DISTRHO/DPF | git clone --depth 1 --recursive -b develop git://github.com/DISTRHO/DPF | ||||
for PLUGIN in ${PLUGINS[@]}; do | for PLUGIN in ${PLUGINS[@]}; do | ||||
git clone --depth 1 --recursive git://github.com/DISTRHO/$PLUGIN | |||||
git clone --depth 1 git://github.com/DISTRHO/$PLUGIN | |||||
done | done | ||||
# special case for ProM | |||||
cd ProM | |||||
git submodule init | |||||
git submodule update | |||||
cd .. | |||||
cd .. | cd .. | ||||
rm -rf dpf | rm -rf dpf | ||||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||||
TARGETS += jack | TARGETS += jack | ||||
TARGETS += ladspa | TARGETS += ladspa | ||||
TARGETS += vst | |||||
TARGETS += vst2 | |||||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ||||
ifeq ($(HAVE_LIBLO),true) | ifeq ($(HAVE_LIBLO),true) | ||||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||||
TARGETS += jack | TARGETS += jack | ||||
TARGETS += ladspa | TARGETS += ladspa | ||||
TARGETS += vst | |||||
TARGETS += vst2 | |||||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ||||
ifeq ($(HAVE_LIBLO),true) | ifeq ($(HAVE_LIBLO),true) | ||||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||||
TARGETS += jack | TARGETS += jack | ||||
TARGETS += ladspa | TARGETS += ladspa | ||||
TARGETS += vst | |||||
TARGETS += vst2 | |||||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ||||
ifeq ($(HAVE_LIBLO),true) | ifeq ($(HAVE_LIBLO),true) | ||||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||||
TARGETS += jack | TARGETS += jack | ||||
TARGETS += ladspa | TARGETS += ladspa | ||||
TARGETS += vst | |||||
TARGETS += vst2 | |||||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ||||
ifeq ($(HAVE_LIBLO),true) | ifeq ($(HAVE_LIBLO),true) | ||||
@@ -23,14 +23,6 @@ include ../../dpf/Makefile.plugins.mk | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Enable all possible plugin types | # Enable all possible plugin types | ||||
ifeq ($(HAVE_JACK),true) | |||||
TARGETS += jack | |||||
endif | |||||
TARGETS += dssi_dsp | |||||
TARGETS += lv2_sep | |||||
TARGETS += vst | |||||
all: $(TARGETS) | |||||
all: jack dssi_dsp lv2_dsp vst2 | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- |
@@ -27,12 +27,9 @@ include ../../dpf/Makefile.plugins.mk | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Enable all possible plugin types | # Enable all possible plugin types | ||||
ifeq ($(HAVE_JACK),true) | |||||
TARGETS += jack | TARGETS += jack | ||||
endif | |||||
TARGETS += ladspa | TARGETS += ladspa | ||||
TARGETS += vst | |||||
TARGETS += vst2 | |||||
ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
ifeq ($(HAVE_LIBLO),true) | ifeq ($(HAVE_LIBLO),true) | ||||
@@ -129,6 +129,11 @@ DistrhoUINekobi::DistrhoUINekobi() | |||||
addIdleCallback(this, 120); | addIdleCallback(this, 120); | ||||
} | } | ||||
DistrhoUINekobi::~DistrhoUINekobi() | |||||
{ | |||||
removeIdleCallback(this); | |||||
} | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// DSP Callbacks | // DSP Callbacks | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Nekobi Plugin, based on Nekobee by Sean Bolton and others. | * DISTRHO Nekobi Plugin, based on Nekobee by Sean Bolton and others. | ||||
* Copyright (C) 2013-2015 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2013-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -42,6 +42,7 @@ class DistrhoUINekobi : public UI, | |||||
{ | { | ||||
public: | public: | ||||
DistrhoUINekobi(); | DistrhoUINekobi(); | ||||
~DistrhoUINekobi() override; | |||||
protected: | protected: | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -48,7 +48,7 @@ else | |||||
TARGETS += lv2_dsp | TARGETS += lv2_dsp | ||||
endif | endif | ||||
TARGETS += vst | |||||
TARGETS += vst2 | |||||
all: $(TARGETS) | all: $(TARGETS) | ||||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||||
TARGETS += jack | TARGETS += jack | ||||
TARGETS += ladspa | TARGETS += ladspa | ||||
TARGETS += vst | |||||
TARGETS += vst2 | |||||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ||||
ifeq ($(HAVE_LIBLO),true) | ifeq ($(HAVE_LIBLO),true) | ||||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||||
TARGETS += jack | TARGETS += jack | ||||
TARGETS += ladspa | TARGETS += ladspa | ||||
TARGETS += vst | |||||
TARGETS += vst2 | |||||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ||||
ifeq ($(HAVE_LIBLO),true) | ifeq ($(HAVE_LIBLO),true) | ||||
@@ -31,10 +31,7 @@ LINK_FLAGS += -lpthread | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Enable all possible plugin types | # Enable all possible plugin types | ||||
ifeq ($(HAVE_JACK),true) | |||||
TARGETS += jack | TARGETS += jack | ||||
endif | |||||
TARGETS += lv2 | TARGETS += lv2 | ||||
TARGETS += vst | TARGETS += vst | ||||