| @@ -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 | |||