@@ -1,5 +1,7 @@ | |||
# 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/> | |||
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 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: | |||
@@ -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/) | |||
- [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:>" | |||
OUTPUT_NAME "${NAME}-vst2" | |||
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() | |||
# dpf__add_dgl_cairo | |||
@@ -64,7 +64,6 @@ public: | |||
Quit the application. | |||
This stops the event-loop and closes all Windows. | |||
This function is thread-safe. | |||
@note This function is meant for standalones only, *never* call this from plugins. | |||
*/ | |||
void quit(); | |||
@@ -923,6 +923,7 @@ private: | |||
*/ | |||
inline void onDisplay() override | |||
{ | |||
// NOTE maybe should use BaseWidget::getWindow().getScaleFactor() as 3rd arg ? | |||
NanoVG::beginFrame(BaseWidget::getWidth(), BaseWidget::getHeight()); | |||
onNanoDisplay(); | |||
NanoVG::endFrame(); | |||
@@ -33,14 +33,25 @@ public: | |||
*/ | |||
StandaloneWindow(Application& 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. | |||
@@ -66,6 +77,9 @@ public: | |||
bool keepAspectRatio = false, bool automaticallyScale = false) | |||
{ Window::setGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, automaticallyScale); } | |||
private: | |||
ScopedGraphicsContext sgc; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(StandaloneWindow) | |||
}; | |||
@@ -49,6 +49,8 @@ class TopLevelWidget; | |||
*/ | |||
class Window | |||
{ | |||
struct PrivateData; | |||
public: | |||
#ifndef DGL_FILE_BROWSER_DISABLED | |||
/** | |||
@@ -59,6 +61,7 @@ public: | |||
/** | |||
File browser button state. | |||
This allows to customize the behaviour of the file browse dialog buttons. | |||
Note these are merely hints, not all systems support them. | |||
*/ | |||
enum ButtonState { | |||
kButtonInvisible, | |||
@@ -87,7 +90,7 @@ public: | |||
Buttons() | |||
: listAllFiles(kButtonVisibleChecked), | |||
showHidden(kButtonVisibleUnchecked), | |||
showPlaces(kButtonVisibleUnchecked) {} | |||
showPlaces(kButtonVisibleChecked) {} | |||
} buttons; | |||
/** Constructor for default values */ | |||
@@ -113,7 +116,7 @@ public: | |||
Window win(app); | |||
ScopedPointer<MyCustomTopLevelWidget> widget; | |||
{ | |||
const ScopedGraphicsContext sgc(win); | |||
const Window::ScopedGraphicsContext sgc(win); | |||
widget = new MyCustomTopLevelWidget(win); | |||
} | |||
app.exec(); | |||
@@ -127,12 +130,25 @@ public: | |||
*/ | |||
struct ScopedGraphicsContext | |||
{ | |||
/** Constructor that will make the @a window graphics context the current one */ | |||
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(); | |||
/** Early context clearing, useful for standalone windows not created by you. */ | |||
void done(); | |||
DISTRHO_DECLARE_NON_COPYABLE(ScopedGraphicsContext) | |||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||
private: | |||
Window& window; | |||
Window::PrivateData* ppData; | |||
bool active; | |||
}; | |||
/** | |||
@@ -441,7 +457,6 @@ protected: | |||
#endif | |||
private: | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
friend class Application; | |||
friend class PluginWindow; | |||
@@ -43,8 +43,6 @@ void Application::exec(const uint idleTimeInMs) | |||
void Application::quit() | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(pData->isStandalone,); | |||
pData->quit(); | |||
} | |||
@@ -127,8 +127,6 @@ void Application::PrivateData::idle(const uint timeoutInMs) | |||
void Application::PrivateData::quit() | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(isStandalone,); | |||
if (! isThisTheMainThread(mainThreadHandle)) | |||
{ | |||
if (! isQuittingInNextCycle) | |||
@@ -29,11 +29,13 @@ ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(Window& parentWindow, cons | |||
setResizable(false); | |||
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> | |||
@@ -44,11 +46,13 @@ ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(TopLevelWidget* const pare | |||
setResizable(false); | |||
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> | |||
@@ -24,14 +24,37 @@ START_NAMESPACE_DGL | |||
// ScopedGraphicsContext | |||
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() | |||
{ | |||
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), | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#endif | |||
@@ -118,12 +119,12 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||
minWidth(0), | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#endif | |||
modal(ppData) | |||
{ | |||
puglBackendLeave(transientParentView); | |||
puglSetTransientFor(view, puglGetNativeWindow(transientParentView)); | |||
initPre(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | |||
@@ -147,6 +148,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
minWidth(0), | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#endif | |||
@@ -177,6 +179,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
minWidth(0), | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#endif | |||
@@ -266,10 +269,6 @@ bool Window::PrivateData::initPost() | |||
puglShow(view); | |||
} | |||
// give context back to transient parent window | |||
if (transientParentView != nullptr) | |||
puglBackendEnter(transientParentView); | |||
return true; | |||
} | |||
@@ -317,8 +316,10 @@ void Window::PrivateData::show() | |||
PuglRect rect = puglGetFrame(view); | |||
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 | |||
puglShow(view); | |||
#endif | |||
@@ -419,6 +420,9 @@ void Window::PrivateData::idleCallback() | |||
bool Window::PrivateData::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | |||
{ | |||
if (ignoreIdleCallbacks) | |||
return false; | |||
if (timerFrequencyInMs == 0) | |||
{ | |||
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) | |||
{ | |||
if (ignoreIdleCallbacks) | |||
return false; | |||
if (std::find(appData->idleCallbacks.begin(), | |||
appData->idleCallbacks.end(), callback) != appData->idleCallbacks.end()) | |||
{ | |||
@@ -459,19 +466,19 @@ bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& opti | |||
if (startDir.isEmpty()) | |||
{ | |||
// TESTING verify this whole thing... | |||
#ifdef DISTRHO_OS_WINDOWS | |||
# ifdef DISTRHO_OS_WINDOWS | |||
if (char* const cwd = _getcwd(nullptr, 0)) | |||
{ | |||
startDir = cwd; | |||
std::free(cwd); | |||
} | |||
#else | |||
# else | |||
if (char* const cwd = getcwd(nullptr, 0)) | |||
{ | |||
startDir = cwd; | |||
std::free(cwd); | |||
} | |||
#endif | |||
# endif | |||
} | |||
DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false); | |||
@@ -497,7 +504,22 @@ bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& opti | |||
# ifdef DISTRHO_OS_MAC | |||
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); | |||
# endif | |||
@@ -529,6 +551,13 @@ bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& opti | |||
ofn.lpstrFile = fileNameW.data(); | |||
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. | |||
// threading might work, if someone is motivated to risk it. | |||
if (GetOpenFileNameW(&ofn)) | |||
@@ -552,7 +581,22 @@ bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& opti | |||
# ifdef HAVE_X11 | |||
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); | |||
# endif | |||
@@ -872,9 +916,9 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
///< View created, a #PuglEventCreate | |||
case PUGL_CREATE: | |||
#ifdef DGL_PUGL_USING_X11 | |||
#ifdef HAVE_X11 | |||
if (! pData->isEmbed) | |||
puglExtraSetWindowTypeAndPID(view); | |||
puglX11SetWindowTypeAndPID(view); | |||
#endif | |||
break; | |||
@@ -74,6 +74,9 @@ struct Window::PrivateData : IdleCallback { | |||
uint minWidth, minHeight; | |||
bool keepAspectRatio; | |||
/** Whether to ignore idle callback requests, useful for temporary windows. */ | |||
bool ignoreIdleCallbacks; | |||
#ifdef DISTRHO_OS_WINDOWS | |||
/** Selected file for openFileBrowser on windows, stored for fake async operation. */ | |||
const char* win32SelectedFile; | |||
@@ -159,9 +159,9 @@ START_NAMESPACE_DGL | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
// 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_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 | |||
@@ -494,6 +501,33 @@ puglMacOSRemoveChildWindow(PuglView* const view, PuglView* const child) | |||
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 | |||
@@ -505,13 +539,18 @@ bool puglMacOSFilePanelOpen(PuglView* const view, | |||
NSOpenPanel* const panel = [NSOpenPanel openPanel]; | |||
// TODO flags | |||
[panel setAllowsMultipleSelection:NO]; | |||
[panel setCanChooseFiles:YES]; | |||
[panel setCanChooseDirectories:NO]; | |||
[panel setAllowsMultipleSelection:NO]; | |||
[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] | |||
initWithBytes: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) | |||
void puglWin32ShowWindowCentered(PuglView* const view) | |||
void puglWin32ShowCentered(PuglView* const view) | |||
{ | |||
PuglInternals* impl = view->impl; | |||
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 | |||
PuglStatus puglX11GrabFocus(PuglView* const view) | |||
PuglStatus puglX11GrabFocus(const PuglView* const view) | |||
{ | |||
PuglInternals* const impl = view->impl; | |||
const PuglInternals* const impl = view->impl; | |||
XWindowAttributes wa; | |||
std::memset(&wa, 0, sizeof(wa)); | |||
@@ -615,6 +654,29 @@ PuglStatus puglX11GrabFocus(PuglView* const view) | |||
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 | |||
@@ -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(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); | |||
} | |||
@@ -48,7 +48,7 @@ USE_NAMESPACE_DGL | |||
PUGL_BEGIN_DECLS | |||
// expose backend enter | |||
PUGL_API void | |||
PUGL_API bool | |||
puglBackendEnter(PuglView* view); | |||
// expose backend leave | |||
@@ -108,6 +108,10 @@ puglMacOSAddChildWindow(PuglView* view, PuglView* child); | |||
PUGL_API PuglStatus | |||
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 | |||
typedef void (*openPanelCallback)(PuglView* view, const char* path); | |||
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) | |||
PUGL_API void | |||
puglWin32ShowWindowCentered(PuglView* view); | |||
puglWin32ShowCentered(PuglView* view); | |||
// win32 specific, set or unset WS_SIZEBOX style flag | |||
PUGL_API void | |||
@@ -130,7 +134,11 @@ puglWin32SetWindowResizable(PuglView* view, bool resizable); | |||
#ifdef HAVE_X11 | |||
// X11 specific, safer way to grab focus | |||
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 | |||
PUGL_API bool | |||
@@ -2072,7 +2072,7 @@ int x_fib_show (Display *dpy, Window parent, int x, int y, double scalefactor) { | |||
sync_button_states () ; | |||
_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); | |||
@@ -303,17 +303,26 @@ protected: | |||
*/ | |||
virtual void uiFileBrowserSelected(const char* filename); | |||
# endif | |||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
/* -------------------------------------------------------------------------------------------------------- | |||
* 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. | |||
@see Widget::onResize(const ResizeEvent&) | |||
*/ | |||
void onResize(const ResizeEvent& ev) override; | |||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
#endif | |||
// ------------------------------------------------------------------------------------------------------- | |||
@@ -19,6 +19,28 @@ | |||
#endif | |||
#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" | |||
#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) | |||
#import "src/pugl.mm" | |||
#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI |
@@ -19,9 +19,7 @@ | |||
#include "String.hpp" | |||
#ifdef DISTRHO_OS_WINDOWS | |||
# error Unsupported platform! | |||
#else | |||
#ifndef DISTRHO_OS_WINDOWS | |||
# include <cerrno> | |||
# include <signal.h> | |||
# include <sys/wait.h> | |||
@@ -106,9 +104,10 @@ public: | |||
*/ | |||
virtual bool isRunning() const | |||
{ | |||
#ifndef DISTRHO_OS_WINDOWS | |||
if (ext.inUse) | |||
return ext.isRunning(); | |||
#endif | |||
return isVisible(); | |||
} | |||
@@ -119,7 +118,11 @@ public: | |||
*/ | |||
virtual bool isQuitting() const | |||
{ | |||
#ifndef DISTRHO_OS_WINDOWS | |||
return ext.inUse ? ext.isQuitting : pData.isQuitting; | |||
#else | |||
return pData.isQuitting; | |||
#endif | |||
} | |||
/** | |||
@@ -259,9 +262,10 @@ public: | |||
{ | |||
pData.isQuitting = true; | |||
hide(); | |||
#ifndef DISTRHO_OS_WINDOWS | |||
if (ext.inUse) | |||
terminateAndWaitForExternalProcess(); | |||
#endif | |||
} | |||
/** | |||
@@ -293,7 +297,7 @@ public: | |||
{ | |||
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; | |||
pData.width = width; | |||
@@ -357,15 +361,24 @@ protected: | |||
bool startExternalProcess(const char* args[]) | |||
{ | |||
#ifndef DISTRHO_OS_WINDOWS | |||
ext.inUse = true; | |||
return ext.start(args); | |||
#else | |||
(void)args; | |||
return false; // TODO | |||
#endif | |||
} | |||
void terminateAndWaitForExternalProcess() | |||
{ | |||
#ifndef DISTRHO_OS_WINDOWS | |||
ext.isQuitting = true; | |||
ext.terminateAndWait(); | |||
#else | |||
// TODO | |||
#endif | |||
} | |||
/* -------------------------------------------------------------------------------------------------------- | |||
@@ -414,6 +427,7 @@ private: | |||
friend class PluginWindow; | |||
friend class UI; | |||
#ifndef DISTRHO_OS_WINDOWS | |||
struct ExternalProcess { | |||
bool inUse; | |||
bool isQuitting; | |||
@@ -510,6 +524,7 @@ private: | |||
} | |||
} | |||
} ext; | |||
#endif | |||
struct PrivateData { | |||
uintptr_t parentWindowHandle; | |||
@@ -85,9 +85,11 @@ public: | |||
fLastControlValues(nullptr), | |||
fSampleRate(sampleRate), | |||
fURIDs(uridMap), | |||
#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST | |||
fCtrlInPortChangeReq(ctrlInPortChangeReq), | |||
#endif | |||
fUridMap(uridMap), | |||
fWorker(worker), | |||
fCtrlInPortChangeReq(ctrlInPortChangeReq) | |||
fWorker(worker) | |||
{ | |||
#if DISTRHO_PLUGIN_NUM_INPUTS > 0 | |||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) | |||
@@ -157,6 +159,11 @@ public: | |||
// unused | |||
(void)fWorker; | |||
#endif | |||
#if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST | |||
// unused | |||
(void)ctrlInPortChangeReq; | |||
#endif | |||
} | |||
~PluginLv2() | |||
@@ -1178,9 +1185,11 @@ private: | |||
} fURIDs; | |||
// 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_Worker_Schedule* const fWorker; | |||
const LV2_ControlInputPort_Change_Request* const fCtrlInPortChangeReq; | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
StringToStringMap fStateMap; | |||
@@ -14,21 +14,117 @@ | |||
* 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/WindowPrivateData.hpp" | |||
#endif | |||
#include "DistrhoUIPrivateData.hpp" | |||
START_NAMESPACE_DISTRHO | |||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Static data, see DistrhoUIInternal.hpp */ | |||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
uintptr_t g_nextWindowId = 0; | |||
double g_nextScaleFactor = 1.0; | |||
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 | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
@@ -50,12 +146,17 @@ UI::PrivateData::createNextWindow(UI* const ui, const uint width, const uint hei | |||
ewData.parentWindowHandle = pData->winId; | |||
ewData.width = width; | |||
ewData.height = height; | |||
ewData.scaleFactor = pData->scaleFactor; | |||
ewData.scaleFactor = pData->scaleFactor != 0.0 ? pData->scaleFactor : getDesktopScaleFactor(pData->winId); | |||
ewData.title = DISTRHO_PLUGIN_NAME; | |||
ewData.isStandalone = DISTRHO_UI_IS_STANDALONE; | |||
return ewData; | |||
#else | |||
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(); | |||
#endif | |||
} | |||
@@ -209,10 +310,19 @@ void UI::uiFileBrowserSelected(const char*) | |||
{ | |||
} | |||
# endif | |||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* 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) | |||
{ | |||
UIWidget::onResize(ev); | |||
@@ -221,7 +331,7 @@ void UI::onResize(const ResizeEvent& ev) | |||
const uint height = ev.size.getHeight(); | |||
uiData->setSizeCallback(width, height); | |||
} | |||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
#endif | |||
// ----------------------------------------------------------------------------------------------------------- | |||
@@ -91,6 +91,7 @@ public: | |||
g_nextScaleFactor = 0.0; | |||
g_nextBundlePath = nullptr; | |||
#else | |||
// Leave context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp | |||
uiData->window->leaveContext(); | |||
#endif | |||
UI::PrivateData::s_nextPrivateData = nullptr; | |||
@@ -106,6 +107,7 @@ public: | |||
~UIExporter() | |||
{ | |||
quit(); | |||
delete ui; | |||
delete uiData; | |||
} | |||
@@ -227,9 +229,7 @@ public: | |||
void quit() | |||
{ | |||
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 | |||
struct PluginApplication | |||
{ | |||
IdleCallback* idleCallback; | |||
DGL_NAMESPACE::IdleCallback* idleCallback; | |||
UI* ui; | |||
explicit PluginApplication() | |||
: idleCallback(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(idleCallback == nullptr,); | |||
@@ -187,6 +187,11 @@ public: | |||
puglBackendLeave(pData->view); | |||
} | |||
void setIgnoreIdleCallbacks(const bool ignore = true) | |||
{ | |||
pData->ignoreIdleCallbacks = ignore; | |||
} | |||
protected: | |||
void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override | |||
{ | |||
@@ -42,6 +42,19 @@ typedef DGL_NAMESPACE::VulkanImage DemoImage; | |||
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<TopLevelWidget, DemoImage> ExampleImagesTopLevelWidget; | |||
typedef ExampleImagesWidget<StandaloneWindow, DemoImage> ExampleImagesStandaloneWindow; | |||
@@ -435,6 +448,7 @@ public: | |||
resizer = new ResizeHandle(this); | |||
curPageChanged(0); | |||
done(); | |||
} | |||
protected: | |||
@@ -37,6 +37,11 @@ public: | |||
#ifndef DGL_NO_SHARED_RESOURCES | |||
loadSharedResources(); | |||
#endif | |||
setResizable(true); | |||
setSize(500, 200); | |||
setGeometryConstraints(500, 200, true); | |||
setTitle("FileBrowserDialog"); | |||
done(); | |||
} | |||
protected: | |||
@@ -170,8 +175,6 @@ int main() | |||
Application app(true); | |||
NanoFilePicker win(app); | |||
win.setSize(500, 200); | |||
win.setTitle("FileBrowserDialog"); | |||
win.show(); | |||
app.exec(); | |||
@@ -127,9 +127,13 @@ class NanoExampleWindow : public Window | |||
{ | |||
public: | |||
explicit NanoExampleWindow(Application& app) | |||
: Window(app), | |||
container(*this) | |||
: Window(app) | |||
{ | |||
{ | |||
const ScopedGraphicsContext sgc(*this); | |||
container = new NanoRectanglesContainer(*this); | |||
} | |||
const uint targetWidth = 400; | |||
const uint targetHeight = 400; | |||
const double scaleFactor = getScaleFactor(); | |||
@@ -141,7 +145,7 @@ public: | |||
} | |||
private: | |||
NanoRectanglesContainer container; | |||
ScopedPointer<NanoRectanglesContainer> container; | |||
}; | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
@@ -154,7 +158,6 @@ int main() | |||
Application app; | |||
NanoExampleWindow win(app); | |||
win.show(); | |||
app.exec(); | |||
@@ -165,6 +165,7 @@ ExampleColorWidget<StandaloneWindow>::ExampleColorWidget(Application& app) | |||
{ | |||
setSize(300, 300); | |||
addIdleCallback(this); | |||
done(); | |||
} | |||
typedef ExampleColorWidget<SubWidget> ExampleColorSubWidget; | |||
@@ -21,8 +21,8 @@ | |||
// DGL Stuff | |||
#include "../../dgl/ImageBase.hpp" | |||
#include "../../dgl/StandaloneWindow.hpp" | |||
#include "../../dgl/SubWidget.hpp" | |||
#include "../../dgl/TopLevelWidget.hpp" | |||
// ------------------------------------------------------ | |||
// Images | |||
@@ -55,69 +55,34 @@ public: | |||
static constexpr const char* kExampleWidgetName = "Images"; | |||
// 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 | |||
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 | |||
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); | |||
} | |||
protected: | |||
void idleCallback() noexcept override | |||
{ | |||
if (img1rev) | |||
@@ -21,8 +21,8 @@ | |||
// DGL Stuff | |||
#include "../../dgl/Color.hpp" | |||
#include "../../dgl/StandaloneWindow.hpp" | |||
#include "../../dgl/SubWidget.hpp" | |||
#include "../../dgl/TopLevelWidget.hpp" | |||
START_NAMESPACE_DGL | |||
@@ -37,23 +37,14 @@ class ExampleRectanglesWidget : public BaseWidget | |||
public: | |||
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() | |||
{ | |||
@@ -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<TopLevelWidget> ExampleRectanglesTopLevelWidget; | |||
typedef ExampleRectanglesWidget<StandaloneWindow> ExampleRectanglesStandaloneWindow; | |||
@@ -21,8 +21,8 @@ | |||
// DGL Stuff | |||
#include "../../dgl/Color.hpp" | |||
#include "../../dgl/StandaloneWindow.hpp" | |||
#include "../../dgl/SubWidget.hpp" | |||
#include "../../dgl/TopLevelWidget.hpp" | |||
START_NAMESPACE_DGL | |||
@@ -40,23 +40,14 @@ class ExampleShapesWidget : public BaseWidget | |||
public: | |||
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: | |||
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<TopLevelWidget> ExampleShapesTopLevelWidget; | |||
typedef ExampleShapesWidget<StandaloneWindow> ExampleShapesStandaloneWindow; | |||
@@ -62,6 +62,7 @@ protected: | |||
} | |||
}; | |||
// SubWidget | |||
template<> inline | |||
ExampleTextWidget<NanoSubWidget>::ExampleTextWidget(Widget* const parent) | |||
: NanoSubWidget(parent) | |||
@@ -70,6 +71,7 @@ ExampleTextWidget<NanoSubWidget>::ExampleTextWidget(Widget* const parent) | |||
setSize(500, 300); | |||
} | |||
// TopLevelWidget | |||
template<> inline | |||
ExampleTextWidget<NanoTopLevelWidget>::ExampleTextWidget(Window& windowToMapTo) | |||
: NanoTopLevelWidget(windowToMapTo) | |||
@@ -78,12 +80,14 @@ ExampleTextWidget<NanoTopLevelWidget>::ExampleTextWidget(Window& windowToMapTo) | |||
setSize(500, 300); | |||
} | |||
// StandaloneWindow | |||
template<> inline | |||
ExampleTextWidget<NanoStandaloneWindow>::ExampleTextWidget(Application& app) | |||
: NanoStandaloneWindow(app) | |||
{ | |||
loadSharedResources(); | |||
setSize(500, 300); | |||
done(); | |||
} | |||
template class ExampleTextWidget<NanoSubWidget>; | |||
@@ -19,7 +19,7 @@ for i in $PLUGINS; do | |||
cp -r ${DPF_DIR}/utils/plugin.vst/ ${BUNDLE}.vst | |||
mv ${i} ${BUNDLE}.vst/Contents/MacOS/${BUNDLE} | |||
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 | |||
done | |||
@@ -5,11 +5,11 @@ | |||
<key>CFBundleDevelopmentRegion</key> | |||
<string>English</string> | |||
<key>CFBundleExecutable</key> | |||
<string>X-PROJECTNAME-X</string> | |||
<string>@INFO_PLIST_PROJECT_NAME@</string> | |||
<key>CFBundleIconFile</key> | |||
<string></string> | |||
<key>CFBundleIdentifier</key> | |||
<string>studio.kx.distrho.X-PROJECTNAME-X</string> | |||
<string>studio.kx.distrho.@INFO_PLIST_PROJECT_NAME@</string> | |||
<key>CFBundleInfoDictionaryVersion</key> | |||
<string>6.0</string> | |||
<key>CFBundlePackageType</key> | |||
@@ -16,9 +16,15 @@ cd repos | |||
git clone --depth 1 --recursive -b develop git://github.com/DISTRHO/DPF | |||
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 | |||
# special case for ProM | |||
cd ProM | |||
git submodule init | |||
git submodule update | |||
cd .. | |||
cd .. | |||
rm -rf dpf | |||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||
TARGETS += jack | |||
TARGETS += ladspa | |||
TARGETS += vst | |||
TARGETS += vst2 | |||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | |||
ifeq ($(HAVE_LIBLO),true) | |||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||
TARGETS += jack | |||
TARGETS += ladspa | |||
TARGETS += vst | |||
TARGETS += vst2 | |||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | |||
ifeq ($(HAVE_LIBLO),true) | |||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||
TARGETS += jack | |||
TARGETS += ladspa | |||
TARGETS += vst | |||
TARGETS += vst2 | |||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | |||
ifeq ($(HAVE_LIBLO),true) | |||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||
TARGETS += jack | |||
TARGETS += ladspa | |||
TARGETS += vst | |||
TARGETS += vst2 | |||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | |||
ifeq ($(HAVE_LIBLO),true) | |||
@@ -23,14 +23,6 @@ include ../../dpf/Makefile.plugins.mk | |||
# -------------------------------------------------------------- | |||
# 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 | |||
ifeq ($(HAVE_JACK),true) | |||
TARGETS += jack | |||
endif | |||
TARGETS += ladspa | |||
TARGETS += vst | |||
TARGETS += vst2 | |||
ifeq ($(HAVE_DGL),true) | |||
ifeq ($(HAVE_LIBLO),true) | |||
@@ -129,6 +129,11 @@ DistrhoUINekobi::DistrhoUINekobi() | |||
addIdleCallback(this, 120); | |||
} | |||
DistrhoUINekobi::~DistrhoUINekobi() | |||
{ | |||
removeIdleCallback(this); | |||
} | |||
// ----------------------------------------------------------------------- | |||
// DSP Callbacks | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* modify it under the terms of the GNU General Public License as | |||
@@ -42,6 +42,7 @@ class DistrhoUINekobi : public UI, | |||
{ | |||
public: | |||
DistrhoUINekobi(); | |||
~DistrhoUINekobi() override; | |||
protected: | |||
// ------------------------------------------------------------------- | |||
@@ -48,7 +48,7 @@ else | |||
TARGETS += lv2_dsp | |||
endif | |||
TARGETS += vst | |||
TARGETS += vst2 | |||
all: $(TARGETS) | |||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||
TARGETS += jack | |||
TARGETS += ladspa | |||
TARGETS += vst | |||
TARGETS += vst2 | |||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | |||
ifeq ($(HAVE_LIBLO),true) | |||
@@ -30,7 +30,7 @@ include ../../dpf/Makefile.plugins.mk | |||
TARGETS += jack | |||
TARGETS += ladspa | |||
TARGETS += vst | |||
TARGETS += vst2 | |||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | |||
ifeq ($(HAVE_LIBLO),true) | |||
@@ -31,10 +31,7 @@ LINK_FLAGS += -lpthread | |||
# -------------------------------------------------------------- | |||
# Enable all possible plugin types | |||
ifeq ($(HAVE_JACK),true) | |||
TARGETS += jack | |||
endif | |||
TARGETS += lv2 | |||
TARGETS += vst | |||