@@ -133,6 +133,7 @@ endif | |||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
CFLAGS += -isystem /opt/kxstudio/include | CFLAGS += -isystem /opt/kxstudio/include | ||||
CXXFLAGS += -isystem /opt/kxstudio/include | CXXFLAGS += -isystem /opt/kxstudio/include | ||||
CXXFLAGS += -isystem /System/Library/Frameworks | |||||
endif | endif | ||||
ifeq ($(WIN64),true) | ifeq ($(WIN64),true) | ||||
CFLAGS += -isystem /opt/mingw64/include | CFLAGS += -isystem /opt/mingw64/include | ||||
@@ -20,6 +20,12 @@ | |||||
#include "CarlaPluginUI.hpp" | #include "CarlaPluginUI.hpp" | ||||
#if defined(CARLA_OS_WIN) || defined(CARLA_OS_MAC) | |||||
# include "juce_events.h" | |||||
using juce::MessageManager; | |||||
using juce::ScopedJuceInitialiser_GUI; | |||||
#endif | |||||
CARLA_BRIDGE_START_NAMESPACE | CARLA_BRIDGE_START_NAMESPACE | ||||
// ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
@@ -79,7 +85,12 @@ public: | |||||
if (! kClient->oscIdle()) | if (! kClient->oscIdle()) | ||||
break; | break; | ||||
#if defined(CARLA_OS_WIN) || defined(CARLA_OS_MAC) | |||||
if (MessageManager* const msgMgr = MessageManager::getInstance()) | |||||
msgMgr->runDispatchLoopUntil(20); | |||||
#else | |||||
carla_msleep(20); | carla_msleep(20); | ||||
#endif | |||||
} | } | ||||
} | } | ||||
@@ -154,6 +165,10 @@ private: | |||||
CarlaPluginUI* fUI; | CarlaPluginUI* fUI; | ||||
bool fIdling; | bool fIdling; | ||||
#if defined(CARLA_OS_WIN) || defined(CARLA_OS_MAC) | |||||
const ScopedJuceInitialiser_GUI kJuceInit; | |||||
#endif | |||||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaBridgeToolkitPlugin) | CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaBridgeToolkitPlugin) | ||||
}; | }; | ||||
@@ -168,6 +183,7 @@ CarlaBridgeToolkit* CarlaBridgeToolkit::createNew(CarlaBridgeClient* const clien | |||||
CARLA_BRIDGE_END_NAMESPACE | CARLA_BRIDGE_END_NAMESPACE | ||||
#define CARLA_PLUGIN_UI_WITHOUT_JUCE_PROCESSORS | |||||
#include "CarlaPluginUI.cpp" | #include "CarlaPluginUI.cpp" | ||||
// ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- |
@@ -1236,7 +1236,7 @@ int main(int argc, char* argv[]) | |||||
if (argc != 6) | if (argc != 6) | ||||
{ | { | ||||
carla_stderr("usage: %s <osc-url|\"null\"> <plugin-bundle> <plugin-uri> <ui-uri> <ui-title>", argv[0]); | |||||
carla_stderr("usage: %s <osc-url|\"null\"><plugin-uri> <ui-uri> <ui-bundle> <ui-title>", argv[0]); | |||||
return 1; | return 1; | ||||
} | } | ||||
@@ -40,7 +40,7 @@ BUILD_LV2_X11_FLAGS = $(BUILD_LV2_FLAGS) -DBRIDGE_X11 -DBRIDGE_LV2_X11 $(X11 | |||||
LINK_LV2_X11_FLAGS = $(LINK_FLAGS) $(X11_LIBS) -ldl | LINK_LV2_X11_FLAGS = $(LINK_FLAGS) $(X11_LIBS) -ldl | ||||
BUILD_LV2_COCOA_FLAGS = $(BUILD_LV2_FLAGS) -DBRIDGE_COCOA -DBRIDGE_LV2_COCOA | BUILD_LV2_COCOA_FLAGS = $(BUILD_LV2_FLAGS) -DBRIDGE_COCOA -DBRIDGE_LV2_COCOA | ||||
LINK_LV2_COCOA_FLAGS = $(LINK_FLAGS) -ldl | |||||
LINK_LV2_COCOA_FLAGS = $(LINK_FLAGS) -framework Cocoa -framework IOKit -framework QuartzCore -ldl | |||||
BUILD_LV2_WINDOWS_FLAGS = $(BUILD_LV2_FLAGS) -DBRIDGE_HWND -DBRIDGE_LV2_HWND | BUILD_LV2_WINDOWS_FLAGS = $(BUILD_LV2_FLAGS) -DBRIDGE_HWND -DBRIDGE_LV2_HWND | ||||
LINK_LV2_WINDOWS_FLAGS = $(LINK_FLAGS) -static -mwindows | LINK_LV2_WINDOWS_FLAGS = $(LINK_FLAGS) -static -mwindows | ||||
@@ -72,13 +72,11 @@ TARGETS += ui_vst-x11 | |||||
endif | endif | ||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
# TODO | |||||
# TARGETS += ui_lv2-cocoa | |||||
TARGETS += ui_lv2-cocoa | |||||
endif | endif | ||||
ifeq ($(WIN32),true) | ifeq ($(WIN32),true) | ||||
# TODO | |||||
# TARGETS += ui_lv2-windows | |||||
TARGETS += ui_lv2-windows | |||||
endif | endif | ||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
@@ -101,6 +99,18 @@ OBJS_LV2_LIBS = \ | |||||
../modules/juce_core.a \ | ../modules/juce_core.a \ | ||||
../modules/lilv.a | ../modules/lilv.a | ||||
OBJS_LV2_LIBS_JUCE_UI = \ | |||||
$(OBJS_LV2_LIBS) \ | |||||
../modules/juce_data_structures.a \ | |||||
../modules/juce_events.a \ | |||||
../modules/juce_graphics.a \ | |||||
../modules/juce_gui_basics.a | |||||
ifeq ($(MACOS),true) | |||||
OBJS_LV2_LIBS_JUCE_UI += \ | |||||
../modules/juce_gui_extra.a | |||||
endif | |||||
OBJS_VST_LIBS = \ | OBJS_VST_LIBS = \ | ||||
../modules/juce_core.a | ../modules/juce_core.a | ||||
@@ -206,11 +216,11 @@ OBJS_LV2_COCOA = \ | |||||
CarlaBridgeToolkitPlugin__lv2-cocoa.o \ | CarlaBridgeToolkitPlugin__lv2-cocoa.o \ | ||||
CarlaBridgeUI-LV2__lv2-cocoa.o | CarlaBridgeUI-LV2__lv2-cocoa.o | ||||
../../bin/carla-bridge-lv2-cocoa: $(OBJS_LV2_COCOA) $(OBJS_LV2_LIBS) | |||||
../../bin/carla-bridge-lv2-cocoa: $(OBJS_LV2_COCOA) $(OBJS_LV2_LIBS_JUCE_UI) | |||||
$(CXX) $^ $(LINK_LV2_COCOA_FLAGS) -o $@ | $(CXX) $^ $(LINK_LV2_COCOA_FLAGS) -o $@ | ||||
%__lv2-cocoa.o: %.cpp | %__lv2-cocoa.o: %.cpp | ||||
$(CXX) $< $(BUILD_LV2_COCOA_FLAGS) -c -o $@ | |||||
$(CXX) $< $(BUILD_LV2_COCOA_FLAGS) -ObjC++ -c -o $@ | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# ui_lv2-windows | # ui_lv2-windows | ||||
@@ -221,7 +231,7 @@ OBJS_LV2_WINDOWS = \ | |||||
CarlaBridgeToolkitPlugin__lv2-windows.o \ | CarlaBridgeToolkitPlugin__lv2-windows.o \ | ||||
CarlaBridgeUI-LV2__lv2-windows.o | CarlaBridgeUI-LV2__lv2-windows.o | ||||
../../bin/carla-bridge-lv2-windows.exe: $(OBJS_LV2_WINDOWS) $(OBJS_LV2_LIBS) | |||||
../../bin/carla-bridge-lv2-windows.exe: $(OBJS_LV2_WINDOWS) $(OBJS_LV2_LIBS_JUCE_UI) | |||||
$(CXX) $^ $(LINK_LV2_WINDOWS_FLAGS) -o $@ | $(CXX) $^ $(LINK_LV2_WINDOWS_FLAGS) -o $@ | ||||
%__lv2-windows.o: %.cpp | %__lv2-windows.o: %.cpp | ||||
@@ -21,8 +21,10 @@ | |||||
#if defined(CARLA_OS_WIN) || defined(CARLA_OS_MAC) | #if defined(CARLA_OS_WIN) || defined(CARLA_OS_MAC) | ||||
# include "juce_gui_basics.h" | # include "juce_gui_basics.h" | ||||
using juce::Colour; | using juce::Colour; | ||||
using juce::Colours; | |||||
using juce::ComponentPeer; | using juce::ComponentPeer; | ||||
using juce::DocumentWindow; | using juce::DocumentWindow; | ||||
using juce::Graphics; | |||||
#endif | #endif | ||||
#ifdef HAVE_X11 | #ifdef HAVE_X11 | ||||
@@ -32,6 +34,92 @@ using juce::DocumentWindow; | |||||
# include <X11/Xutil.h> | # include <X11/Xutil.h> | ||||
#endif | #endif | ||||
// ----------------------------------------------------- | |||||
// AutoResizingNSViewComponentWithParent, see juce_audio_processors.cpp | |||||
#ifdef CARLA_OS_MAC | |||||
# include "juce_gui_extra.h" | |||||
# ifdef CARLA_PLUGIN_UI_WITHOUT_JUCE_PROCESSORS | |||||
# include "juce_core/native/juce_BasicNativeHeaders.h" | |||||
# else | |||||
struct NSView; | |||||
# endif | |||||
namespace juce { | |||||
//============================================================================== | |||||
struct AutoResizingNSViewComponent : public NSViewComponent, | |||||
private AsyncUpdater { | |||||
AutoResizingNSViewComponent(); | |||||
void childBoundsChanged(Component*) override; | |||||
void handleAsyncUpdate() override; | |||||
bool recursive; | |||||
}; | |||||
struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewComponent, | |||||
private Timer { | |||||
AutoResizingNSViewComponentWithParent(); | |||||
NSView* getChildView() const; | |||||
void timerCallback() override; | |||||
}; | |||||
//============================================================================== | |||||
# ifdef CARLA_PLUGIN_UI_WITHOUT_JUCE_PROCESSORS | |||||
# include "juce_core/native/juce_BasicNativeHeaders.h" | |||||
AutoResizingNSViewComponent::AutoResizingNSViewComponent() | |||||
: recursive (false) {} | |||||
void AutoResizingNSViewComponent::childBoundsChanged(Component*) override | |||||
{ | |||||
if (recursive) | |||||
{ | |||||
triggerAsyncUpdate(); | |||||
} | |||||
else | |||||
{ | |||||
recursive = true; | |||||
resizeToFitView(); | |||||
recursive = true; | |||||
} | |||||
} | |||||
void AutoResizingNSViewComponent::handleAsyncUpdate() override | |||||
{ | |||||
resizeToFitView(); | |||||
} | |||||
AutoResizingNSViewComponentWithParent::AutoResizingNSViewComponentWithParent() | |||||
{ | |||||
NSView* v = [[NSView alloc] init]; | |||||
setView (v); | |||||
[v release]; | |||||
startTimer(500); | |||||
} | |||||
NSView* AutoResizingNSViewComponentWithParent::getChildView() const | |||||
{ | |||||
if (NSView* parent = (NSView*)getView()) | |||||
if ([[parent subviews] count] > 0) | |||||
return [[parent subviews] objectAtIndex: 0]; | |||||
return nil; | |||||
} | |||||
void AutoResizingNSViewComponentWithParent::timerCallback() override | |||||
{ | |||||
if (NSView* child = getChildView()) | |||||
{ | |||||
stopTimer(); | |||||
setView(child); | |||||
} | |||||
} | |||||
#endif | |||||
} // namespace juce | |||||
using juce::AutoResizingNSViewComponentWithParent; | |||||
#endif | |||||
// ----------------------------------------------------- | // ----------------------------------------------------- | ||||
// JUCE | // JUCE | ||||
@@ -44,6 +132,9 @@ public: | |||||
: CarlaPluginUI(cb, false), | : CarlaPluginUI(cb, false), | ||||
DocumentWindow("JucePluginUI", Colour(50, 50, 200), DocumentWindow::closeButton, false), | DocumentWindow("JucePluginUI", Colour(50, 50, 200), DocumentWindow::closeButton, false), | ||||
fClosed(false), | fClosed(false), | ||||
#ifdef CARLA_OS_MAC | |||||
fCocoaWrapper(), | |||||
#endif | |||||
leakDetector_JucePluginUI() | leakDetector_JucePluginUI() | ||||
{ | { | ||||
setVisible(false); | setVisible(false); | ||||
@@ -52,10 +143,23 @@ public: | |||||
setResizable(false, false); | setResizable(false, false); | ||||
setUsingNativeTitleBar(true); | setUsingNativeTitleBar(true); | ||||
#ifdef CARLA_OS_MAC | |||||
addAndMakeVisible(fCocoaWrapper = new AutoResizingNSViewComponentWithParent()); | |||||
#endif | |||||
addToDesktop(); | addToDesktop(); | ||||
} | } | ||||
~JucePluginUI() override | |||||
{ | |||||
#ifdef CARLA_OS_MAC | |||||
// deleted before window | |||||
fCocoaWrapper = nullptr; | |||||
#endif | |||||
} | |||||
protected: | protected: | ||||
// CarlaPluginUI calls | |||||
void closeButtonPressed() override | void closeButtonPressed() override | ||||
{ | { | ||||
fClosed = true; | fClosed = true; | ||||
@@ -104,16 +208,64 @@ protected: | |||||
void* getPtr() const noexcept override | void* getPtr() const noexcept override | ||||
{ | { | ||||
#ifdef CARLA_OS_MAC | |||||
return fCocoaWrapper->getView(); | |||||
#else | |||||
if (ComponentPeer* const peer = getPeer()) | if (ComponentPeer* const peer = getPeer()) | ||||
return peer->getNativeHandle(); | return peer->getNativeHandle(); | ||||
carla_stdout("getPtr() failed"); | carla_stdout("getPtr() failed"); | ||||
return nullptr; | return nullptr; | ||||
#endif | |||||
} | |||||
#ifdef CARLA_OS_MAC | |||||
// JUCE MacOS calls | |||||
void childBoundsChanged(Component*) override | |||||
{ | |||||
if (fCocoaWrapper != nullptr) | |||||
{ | |||||
const int w = fCocoaWrapper->getWidth(); | |||||
const int h = fCocoaWrapper->getHeight(); | |||||
if (w != DocumentWindow::getWidth() || h != DocumentWindow::getHeight()) | |||||
DocumentWindow::setSize(w, h); | |||||
} | |||||
} | } | ||||
void resized() override | |||||
{ | |||||
if (fCocoaWrapper != nullptr) | |||||
fCocoaWrapper->setSize(DocumentWindow::getWidth(), DocumentWindow::getHeight()); | |||||
} | |||||
#endif | |||||
#ifdef CARLA_OS_WINDOWS | |||||
// JUCE Windows calls | |||||
void mouseDown(const MouseEvent&) override | |||||
{ | |||||
DocumentWindow::toFront(true); | |||||
} | |||||
#endif | |||||
void paint(Graphics& g) override | |||||
{ | |||||
g.fillAll(Colours::black); | |||||
} | |||||
#if 0 | |||||
//============================================================================== | |||||
bool keyStateChanged (bool) override { return pluginWantsKeys; } | |||||
bool keyPressed (const juce::KeyPress&) override { return pluginWantsKeys; } | |||||
#endif | |||||
private: | private: | ||||
volatile bool fClosed; | volatile bool fClosed; | ||||
#ifdef CARLA_OS_MAC | |||||
juce::ScopedPointer<AutoResizingNSViewComponentWithParent> fCocoaWrapper; | |||||
#endif | |||||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JucePluginUI) | CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JucePluginUI) | ||||
}; | }; | ||||
#endif | #endif | ||||