@@ -21,6 +21,7 @@ | |||
#include "DistrhoUI.hpp" | |||
#include "DistrhoPlugin.hpp" | |||
#include "PluginHostWindow.hpp" | |||
#include "SizeUtils.hpp" | |||
#include "extra/Thread.hpp" | |||
@@ -52,7 +53,9 @@ using namespace CarlaBackend; | |||
// shared resource pointer | |||
// carla_juce_init(); | |||
class IldaeilUI : public UI, public Thread | |||
class IldaeilUI : public UI, | |||
public Thread, | |||
public PluginHostWindow::Callbacks | |||
{ | |||
static constexpr const uint kInitialWidth = 1220; | |||
static constexpr const uint kInitialHeight = 640; | |||
@@ -70,6 +73,7 @@ class IldaeilUI : public UI, public Thread | |||
} fDrawingState; | |||
IldaeilPlugin* const fPlugin; | |||
PluginHostWindow fPluginHostWindow; | |||
uint fPluginCount; | |||
uint fPluginSelected; | |||
@@ -78,21 +82,17 @@ class IldaeilUI : public UI, public Thread | |||
bool fPluginSearchActive; | |||
char fPluginSearchString[0xff]; | |||
bool fInitialSizeHasBeenSet; | |||
const uintptr_t fOurWindowId; | |||
public: | |||
IldaeilUI() | |||
: UI(kInitialWidth, kInitialHeight), | |||
Thread("IldaeilScanner"), | |||
fDrawingState(kDrawingInit), | |||
fPlugin((IldaeilPlugin*)getPluginInstancePointer()), | |||
fPluginHostWindow(getWindow(), this), | |||
fPluginCount(0), | |||
fPluginSelected(0), | |||
fPlugins(nullptr), | |||
fPluginSearchActive(false), | |||
fInitialSizeHasBeenSet(false), | |||
fOurWindowId(getWindow().getNativeWindowHandle()) | |||
fPluginSearchActive(false) | |||
{ | |||
if (fPlugin == nullptr || fPlugin->fCarlaHostHandle == nullptr) | |||
{ | |||
@@ -107,10 +107,21 @@ public: | |||
const double scaleFactor = getScaleFactor(); | |||
if (d_isNotEqual(scaleFactor, 1.0)) | |||
{ | |||
setSize(kInitialWidth * scaleFactor, kInitialHeight * scaleFactor); | |||
fPluginHostWindow.setPositionAndSize(0, kExtraHeight * scaleFactor, | |||
kInitialWidth * scaleFactor, (kInitialHeight - kExtraHeight) * scaleFactor); | |||
} | |||
else | |||
{ | |||
fPluginHostWindow.setPositionAndSize(0, kExtraHeight, kInitialWidth, kInitialHeight-kExtraHeight); | |||
} | |||
const CarlaHostHandle handle = fPlugin->fCarlaHostHandle; | |||
// carla_set_engine_option(handle, ENGINE_OPTION_FRONTEND_WIN_ID, 0, winIdStr); | |||
carla_set_engine_option(handle, ENGINE_OPTION_FRONTEND_UI_SCALE, getScaleFactor()*1000, nullptr); | |||
if (carla_get_current_plugin_count(handle) != 0) | |||
{ | |||
showPluginUI(handle); | |||
@@ -128,9 +139,10 @@ public: | |||
fPlugin->fUI = nullptr; | |||
if (fDrawingState == kDrawingPluginCustomUI) | |||
if (fDrawingState == kDrawingPluginGenericUI || fDrawingState == kDrawingPluginCustomUI) | |||
carla_show_custom_ui(fPlugin->fCarlaHostHandle, 0, false); | |||
fPluginHostWindow.detach(); | |||
delete[] fPlugins; | |||
} | |||
@@ -140,14 +152,8 @@ public: | |||
if (info->hints & PLUGIN_HAS_CUSTOM_EMBED_UI) | |||
{ | |||
// carla_set_engine_option(handle, ENGINE_OPTION_FRONTEND_WIN_ID, 0, winIdStr); | |||
carla_set_engine_option(handle, ENGINE_OPTION_FRONTEND_UI_SCALE, getScaleFactor()*1000, nullptr); | |||
carla_embed_custom_ui(handle, 0, (void*)fOurWindowId); | |||
fDrawingState = kDrawingPluginCustomUI; | |||
fInitialSizeHasBeenSet = false; | |||
tryResizingToChildWindowContent(); | |||
carla_embed_custom_ui(handle, 0, fPluginHostWindow.attachAndGetWindowHandle()); | |||
} | |||
else | |||
{ | |||
@@ -161,6 +167,11 @@ public: | |||
} | |||
protected: | |||
void pluginWindowResized(uint width, uint height) override | |||
{ | |||
setSize(width, height + kExtraHeight * getScaleFactor()); | |||
} | |||
void uiIdle() override | |||
{ | |||
switch (fDrawingState) | |||
@@ -172,9 +183,9 @@ protected: | |||
break; | |||
case kDrawingPluginCustomUI: | |||
if (! fInitialSizeHasBeenSet) | |||
tryResizingToChildWindowContent(); | |||
// fall-through | |||
fPlugin->fCarlaPluginDescriptor->ui_idle(fPlugin->fCarlaPluginHandle); | |||
fPluginHostWindow.idle(); | |||
break; | |||
case kDrawingPluginGenericUI: | |||
fPlugin->fCarlaPluginDescriptor->ui_idle(fPlugin->fCarlaPluginHandle); | |||
@@ -225,14 +236,14 @@ protected: | |||
drawGenericUI(); | |||
// fall-through | |||
case kDrawingPluginCustomUI: | |||
drawBottomBar(); | |||
drawTopBar(); | |||
break; | |||
} | |||
} | |||
void drawBottomBar() | |||
void drawTopBar() | |||
{ | |||
ImGui::SetNextWindowPos(ImVec2(0, getHeight() - kExtraHeight * getScaleFactor())); | |||
ImGui::SetNextWindowPos(ImVec2(0, 0)); | |||
ImGui::SetNextWindowSize(ImVec2(getWidth(), kExtraHeight * getScaleFactor())); | |||
if (ImGui::Begin("Current Plugin", nullptr, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize)) | |||
@@ -368,6 +379,7 @@ protected: | |||
{ | |||
const CarlaCachedPluginInfo& info(fPlugins[i]); | |||
/* | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
if (info.midiIns != 1 || info.audioOuts != 2) | |||
continue; | |||
@@ -380,6 +392,7 @@ protected: | |||
if (info.audioIns != 2 || info.audioOuts != 2) | |||
continue; | |||
#endif | |||
*/ | |||
const char* const slash = std::strchr(info.label, DISTRHO_OS_SEP); | |||
DISTRHO_SAFE_ASSERT_CONTINUE(slash != nullptr); | |||
@@ -409,19 +422,6 @@ protected: | |||
ImGui::End(); | |||
} | |||
private: | |||
void tryResizingToChildWindowContent() | |||
{ | |||
Size<uint> size(getChildWindowSize(fOurWindowId)); | |||
if (size.isValid()) | |||
{ | |||
fInitialSizeHasBeenSet = true; | |||
size.setHeight(size.getHeight() + kExtraHeight * getScaleFactor()); | |||
setSize(size); | |||
} | |||
} | |||
protected: | |||
/* -------------------------------------------------------------------------------------------------------- | |||
* DSP/Plugin Callbacks */ | |||
@@ -0,0 +1,200 @@ | |||
/* | |||
* DISTRHO Ildaeil Plugin | |||
* Copyright (C) 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 | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the LICENSE file. | |||
*/ | |||
#include "src/DistrhoDefines.h" | |||
#if defined(DISTRHO_OS_HAIKU) | |||
#elif defined(DISTRHO_OS_MAC) | |||
# import <Cocoa/Cocoa.h> | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
#else | |||
# include <X11/Xlib.h> | |||
# include <X11/Xutil.h> | |||
#endif | |||
#include "PluginHostWindow.hpp" | |||
#ifdef DISTRHO_OS_MAC | |||
@interface IldaeilPluginView : NSView | |||
- (void)resizeWithOldSuperviewSize:(NSSize)oldSize; | |||
@end | |||
@implementation IldaeilPluginView | |||
- (void)resizeWithOldSuperviewSize:(NSSize)oldSize | |||
{ | |||
[super resizeWithOldSuperviewSize:oldSize]; | |||
} | |||
@end | |||
#endif | |||
START_NAMESPACE_DGL | |||
#if defined(DISTRHO_OS_HAIKU) | |||
#elif defined(DISTRHO_OS_MAC) | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
#else | |||
#endif | |||
struct PluginHostWindow::PrivateData | |||
{ | |||
Window& parentWindow; | |||
const uintptr_t parentWindowId; | |||
Callbacks* const pluginWindowCallbacks; | |||
#if defined(DISTRHO_OS_HAIKU) | |||
#elif defined(DISTRHO_OS_MAC) | |||
IldaeilPluginView* view; | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
#else | |||
#endif | |||
bool lookingForChildren; | |||
PrivateData(Window& pw, Callbacks* const cbs) | |||
: parentWindow(pw), | |||
parentWindowId(pw.getNativeWindowHandle()), | |||
pluginWindowCallbacks(cbs), | |||
#if defined(DISTRHO_OS_HAIKU) | |||
#elif defined(DISTRHO_OS_MAC) | |||
view(nullptr), | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
#else | |||
#endif | |||
lookingForChildren(false) | |||
{ | |||
view = [[IldaeilPluginView new]retain]; | |||
DISTRHO_SAFE_ASSERT_RETURN(view != nullptr,) | |||
[view setAutoresizingMask:NSViewNotSizable]; | |||
[view setAutoresizesSubviews:YES]; | |||
[view setHidden:YES]; | |||
[(NSView*)parentWindowId addSubview:view]; | |||
} | |||
~PrivateData() | |||
{ | |||
#if defined(DISTRHO_OS_HAIKU) | |||
#elif defined(DISTRHO_OS_MAC) | |||
if (view != nullptr) | |||
{ | |||
[view release]; | |||
view = nullptr; | |||
} | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
#else | |||
#endif | |||
} | |||
void* attachAndGetWindowHandle() | |||
{ | |||
lookingForChildren = true; | |||
#if defined(DISTRHO_OS_HAIKU) | |||
#elif defined(DISTRHO_OS_MAC) | |||
return view; | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
#else | |||
#endif | |||
} | |||
void detach() | |||
{ | |||
#if defined(DISTRHO_OS_HAIKU) | |||
#elif defined(DISTRHO_OS_MAC) | |||
if (view != nullptr) | |||
[view setHidden:YES]; | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
#else | |||
#endif | |||
} | |||
void idle() | |||
{ | |||
if (lookingForChildren) | |||
{ | |||
#if defined(DISTRHO_OS_HAIKU) | |||
#elif defined(DISTRHO_OS_MAC) | |||
if (view == nullptr) | |||
return; | |||
for (NSView* subview in [view subviews]) | |||
{ | |||
const double scaleFactor = [[[view window] screen] backingScaleFactor]; | |||
const NSSize size = [subview frame].size; | |||
const double width = size.width; | |||
const double height = size.height; | |||
d_stdout("found subview %f %f", width, height); | |||
if (width <= 1 || height <= 1) | |||
break; | |||
lookingForChildren = false; | |||
[view setFrameSize:size]; | |||
[view setHidden:NO]; | |||
[view setNeedsDisplay:YES]; | |||
pluginWindowCallbacks->pluginWindowResized(width * scaleFactor, height * scaleFactor); | |||
break; | |||
} | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
#else | |||
#endif | |||
} | |||
} | |||
void setPositionAndSize(const uint x, const uint y, const uint width, const uint height) | |||
{ | |||
#if defined(DISTRHO_OS_HAIKU) | |||
#elif defined(DISTRHO_OS_MAC) | |||
if (view != nullptr) | |||
{ | |||
const double scaleFactor = [[[view window] screen] backingScaleFactor]; | |||
[view setFrame:NSMakeRect(x / scaleFactor, y / scaleFactor, width / scaleFactor, height / scaleFactor)]; | |||
} | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
#else | |||
#endif | |||
} | |||
}; | |||
PluginHostWindow::PluginHostWindow(Window& parentWindow, Callbacks* const cbs) | |||
: pData(new PrivateData(parentWindow, cbs)) {} | |||
PluginHostWindow::~PluginHostWindow() | |||
{ | |||
delete pData; | |||
} | |||
void* PluginHostWindow::attachAndGetWindowHandle() | |||
{ | |||
return pData->attachAndGetWindowHandle(); | |||
} | |||
void PluginHostWindow::detach() | |||
{ | |||
pData->detach(); | |||
} | |||
void PluginHostWindow::idle() | |||
{ | |||
pData->idle(); | |||
} | |||
void PluginHostWindow::setPositionAndSize(const uint x, const uint y, const uint width, const uint height) | |||
{ | |||
pData->setPositionAndSize(x, y, width, height); | |||
} | |||
END_NAMESPACE_DGL |
@@ -0,0 +1,42 @@ | |||
/* | |||
* DISTRHO Ildaeil Plugin | |||
* Copyright (C) 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 | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the LICENSE file. | |||
*/ | |||
#include "Window.hpp" | |||
START_NAMESPACE_DGL | |||
class PluginHostWindow | |||
{ | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
public: | |||
struct Callbacks { | |||
virtual ~Callbacks() {} | |||
virtual void pluginWindowResized(uint width, uint height) = 0; | |||
}; | |||
explicit PluginHostWindow(Window& parentWindow, Callbacks* cbs); | |||
~PluginHostWindow(); | |||
void* attachAndGetWindowHandle(); | |||
void detach(); | |||
void idle(); | |||
void setPositionAndSize(uint x, uint y, uint width, uint height); | |||
}; | |||
END_NAMESPACE_DGL |
@@ -56,12 +56,14 @@ Size<uint> getChildWindowSize(const uintptr_t winId) | |||
{ | |||
#if defined(DISTRHO_OS_HAIKU) | |||
#elif defined(DISTRHO_OS_MAC) | |||
/* | |||
for (NSView* subview in [(NSView*)winId subviews]) | |||
{ | |||
// [subview setFrame:NSMakeRect(0, 0, width, height)]; | |||
d_stdout("found subview"); | |||
return Size<uint>(subview.frame.size.width, subview.frame.size.height); | |||
} | |||
*/ | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
#else | |||
if (::Display* const display = XOpenDisplay(nullptr)) | |||
@@ -17,6 +17,7 @@ FILES_DSP = \ | |||
FILES_UI = \ | |||
IldaeilUI.cpp \ | |||
../Common/PluginHostWindow.cpp \ | |||
../Common/SizeUtils.cpp \ | |||
../../dpf-widgets/opengl/DearImGui.cpp | |||
@@ -65,6 +66,7 @@ BUILD_CXX_FLAGS += -I../../carla/source/backend | |||
BUILD_CXX_FLAGS += -I../../carla/source/includes | |||
ifeq ($(MACOS),true) | |||
$(BUILD_DIR)/../Common/PluginHostWindow.cpp.o: BUILD_CXX_FLAGS += -ObjC++ | |||
$(BUILD_DIR)/../Common/SizeUtils.cpp.o: BUILD_CXX_FLAGS += -ObjC++ | |||
LINK_FLAGS += -framework AppKit | |||
LINK_FLAGS += -framework Accelerate | |||