@@ -66,6 +66,13 @@ protected: | |||
return pHost->uiName; | |||
} | |||
uintptr_t getUiParentId() const noexcept | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(pHost != nullptr, 0); | |||
return pHost->uiParentId; | |||
} | |||
uint32_t getBufferSize() const | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(pHost != nullptr, 0); | |||
@@ -20,22 +20,34 @@ | |||
#include "juce_audio_processors.h" | |||
#include "juce_gui_extra.h" | |||
#ifdef HAVE_X11 | |||
# include <X11/Xlib.h> | |||
# undef KeyPress | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
namespace juce { | |||
#include "jucepluginhost/juce_MidiKeyboardComponent.h" | |||
#include "jucepluginhost/juce_MidiKeyboardComponent.cpp" | |||
} | |||
using namespace juce; | |||
// ----------------------------------------------------------------------- | |||
#include "jucepluginhost/FilterGraph.h" | |||
#include "jucepluginhost/InternalFilters.h" | |||
#include "jucepluginhost/GraphEditorPanel.h" | |||
#include "jucepluginhost/MainHostWindow.h" | |||
#include "jucepluginhost/FilterGraph.cpp" | |||
#include "jucepluginhost/InternalFilters.cpp" | |||
#include "jucepluginhost/GraphEditorPanel.cpp" | |||
#include "jucepluginhost/MainHostWindow.cpp" | |||
#ifdef HAVE_X11 | |||
extern Display* display; | |||
#endif | |||
} | |||
using namespace juce; | |||
// ----------------------------------------------------------------------- | |||
class JucePatchbayPlugin : public NativePluginClass | |||
@@ -152,6 +164,13 @@ protected: | |||
{ | |||
fWindow = new MainHostWindow(fFormatManager, fGraph, *fAppProperties); | |||
fWindow->setName(getUiName()); | |||
#ifdef HAVE_X11 | |||
::Window thisWinId = (::Window)fWindow->getWindowHandle(); | |||
::Window hostWinId = (::Window)getUiParentId(); | |||
if (display != nullptr && thisWinId != 0 && hostWinId != 0) | |||
XSetTransientForHint(display, thisWinId, hostWinId); | |||
#endif | |||
} | |||
{ | |||
const ScopedLock csl(fMidiKeyMutex); | |||
@@ -242,7 +261,7 @@ private: | |||
static const NativePluginDescriptor jucepatchbayDesc = { | |||
/* category */ PLUGIN_CATEGORY_UTILITY, | |||
/* hints */ static_cast<NativePluginHints>(PLUGIN_IS_SYNTH|PLUGIN_HAS_UI|PLUGIN_NEEDS_FIXED_BUFFERS|PLUGIN_NEEDS_UI_JUCE|PLUGIN_USES_STATE/*|PLUGIN_USES_TIME*/), | |||
/* hints */ static_cast<NativePluginHints>(PLUGIN_IS_SYNTH|PLUGIN_HAS_UI|PLUGIN_NEEDS_FIXED_BUFFERS|PLUGIN_NEEDS_UI_JUCE|PLUGIN_USES_STATE/*|PLUGIN_USES_TIME*/|PLUGIN_USES_PARENT_ID), | |||
/* supports */ static_cast<NativePluginSupports>(0x0), | |||
/* audioIns */ 2, | |||
/* audioOuts */ 2, | |||
@@ -266,10 +285,3 @@ void carla_register_native_plugin_jucepatchbay() | |||
} | |||
// ----------------------------------------------------------------------- | |||
#include "jucepluginhost/FilterGraph.cpp" | |||
#include "jucepluginhost/InternalFilters.cpp" | |||
#include "jucepluginhost/GraphEditorPanel.cpp" | |||
#include "jucepluginhost/MainHostWindow.cpp" | |||
// ----------------------------------------------------------------------- |
@@ -347,6 +347,9 @@ protected: | |||
} | |||
fWindow->show(fView); | |||
if (const uintptr_t winId = getUiParentId()) | |||
fWindow->setTransientWinId(winId); | |||
} | |||
else if (fWindow != nullptr) | |||
{ | |||
@@ -820,7 +823,7 @@ private: | |||
static const NativePluginDescriptor vexArpDesc = { | |||
/* category */ PLUGIN_CATEGORY_UTILITY, | |||
/* hints */ static_cast<NativePluginHints>(PLUGIN_HAS_UI|PLUGIN_NEEDS_UI_JUCE|PLUGIN_USES_TIME), | |||
/* hints */ static_cast<NativePluginHints>(PLUGIN_HAS_UI|PLUGIN_NEEDS_UI_JUCE|PLUGIN_USES_TIME|PLUGIN_USES_PARENT_ID), | |||
/* supports */ static_cast<NativePluginSupports>(PLUGIN_SUPPORTS_EVERYTHING), | |||
/* audioIns */ 0, | |||
/* audioOuts */ 0, | |||
@@ -1033,6 +1033,9 @@ protected: | |||
fView = new VexEditorComponent(this, fArpSet1, fArpSet2, fArpSet3); | |||
fWindow->show(fView); | |||
if (const uintptr_t winId = getUiParentId()) | |||
fWindow->setTransientWinId(winId); | |||
} | |||
else if (fWindow != nullptr) | |||
{ | |||
@@ -1220,7 +1223,7 @@ private: | |||
static const NativePluginDescriptor vexsynthDesc = { | |||
/* category */ PLUGIN_CATEGORY_SYNTH, | |||
/* hints */ static_cast<NativePluginHints>(PLUGIN_IS_SYNTH|PLUGIN_HAS_UI|PLUGIN_NEEDS_UI_JUCE|PLUGIN_USES_STATE|PLUGIN_USES_TIME), | |||
/* hints */ static_cast<NativePluginHints>(PLUGIN_IS_SYNTH|PLUGIN_HAS_UI|PLUGIN_NEEDS_UI_JUCE|PLUGIN_USES_STATE|PLUGIN_USES_TIME|PLUGIN_USES_PARENT_ID), | |||
/* supports */ static_cast<NativePluginSupports>(0x0), | |||
/* audioIns */ 0, | |||
/* audioOuts */ 2, | |||
@@ -88,7 +88,7 @@ public: | |||
void processBlock(AudioSampleBuffer* const outBuffer) | |||
{ | |||
processBlock(outBuffer->getSampleData(0, 0), outBuffer->getSampleData(1, 0), outBuffer->getNumSamples()); | |||
processBlock(outBuffer->getWritePointer(0), outBuffer->getWritePointer(1), outBuffer->getNumSamples()); | |||
} | |||
void processBlock(float* const outBufferL, float* const outBufferR, const int numSamples) | |||
@@ -99,8 +99,8 @@ public: | |||
const int delay = int(cycle * 0.5f); | |||
const float lfoC = 2.0f * sinf(float_Pi * (speed * 5.0f) / sampleRate); | |||
float* const bufferL = buffer.getSampleData(0, 0); | |||
float* const bufferR = buffer.getSampleData(1, 0); | |||
float* const bufferL = buffer.getWritePointer(0); | |||
float* const bufferR = buffer.getWritePointer(1); | |||
float a, b, alpha, readpoint; | |||
int rp; | |||
@@ -83,7 +83,7 @@ public: | |||
void processBlock(AudioSampleBuffer* const outBuffer, double bpm) | |||
{ | |||
processBlock(outBuffer->getSampleData(0, 0), outBuffer->getSampleData(1, 0), outBuffer->getNumSamples(), bpm); | |||
processBlock(outBuffer->getWritePointer(0), outBuffer->getWritePointer(1), outBuffer->getNumSamples(), bpm); | |||
} | |||
void processBlock(float* const outBufferL, float* const outBufferR, const int numSamples, double bpm) | |||
@@ -93,8 +93,8 @@ public: | |||
const int delay = jmin(int(parameters[73] * 8.0f) * int(((60.0 / bpm) * sampleRate) / 4.0), 44100); | |||
const float feedback = parameters[74]; | |||
float* const bufferL = buffer.getSampleData(0, 0); | |||
float* const bufferR = buffer.getSampleData(1, 0); | |||
float* const bufferL = buffer.getWritePointer(0); | |||
float* const bufferR = buffer.getWritePointer(1); | |||
for (int i = 0; i < numSamples; ++i) | |||
{ | |||
@@ -64,7 +64,7 @@ public: | |||
void processBlock(AudioSampleBuffer* const outBuffer) | |||
{ | |||
processBlock(outBuffer->getSampleData(0, 0), outBuffer->getSampleData(1, 0), outBuffer->getNumSamples()); | |||
processBlock(outBuffer->getWritePointer(0), outBuffer->getWritePointer(1), outBuffer->getNumSamples()); | |||
} | |||
void processBlock(float* const outBufferL, float* const outBufferR, const int numSamples) | |||
@@ -80,8 +80,8 @@ public: | |||
void doProcess(AudioSampleBuffer& obf, AudioSampleBuffer& assbf, AudioSampleBuffer& ebf1, AudioSampleBuffer& ebf2, AudioSampleBuffer& ebf3) | |||
{ | |||
const int numSamples = obf.getNumSamples(); | |||
float* const outPtrL = assbf.getSampleData(0,0); | |||
float* const outPtrR = assbf.getSampleData(1,0); | |||
float* const outPtrL = assbf.getWritePointer(0); | |||
float* const outPtrR = assbf.getWritePointer(1); | |||
if (part1) | |||
{ | |||
@@ -47,17 +47,17 @@ MyLookAndFeel::MyLookAndFeel() | |||
// Topaz->setHorizontalScale (1.0f); | |||
} | |||
MyLookAndFeel::~MyLookAndFeel() | |||
MyLookAndFeel::~MyLookAndFeel() override | |||
{ | |||
delete Topaz; | |||
} | |||
Font MyLookAndFeel::getComboBoxFont (ComboBox& box) | |||
Font MyLookAndFeel::getComboBoxFont(ComboBox&) override | |||
{ | |||
return *Topaz; | |||
} | |||
Font MyLookAndFeel::getPopupMenuFont() | |||
Font MyLookAndFeel::getPopupMenuFont() override | |||
{ | |||
return *Topaz; | |||
} | |||
@@ -66,7 +66,7 @@ void MyLookAndFeel::getIdealPopupMenuItemSize(const String& text, | |||
const bool isSeparator, | |||
int standardMenuItemHeight, | |||
int& idealWidth, | |||
int& idealHeight) | |||
int& idealHeight) override | |||
{ | |||
if (isSeparator) | |||
{ | |||
@@ -86,7 +86,7 @@ void MyLookAndFeel::getIdealPopupMenuItemSize(const String& text, | |||
void MyLookAndFeel::drawToggleButton(Graphics& g, | |||
ToggleButton& button, | |||
bool isMouseOverButton, | |||
bool isButtonDown) | |||
bool isButtonDown) override | |||
{ | |||
const int tickWidth = jmin (20, button.getHeight() - 4); | |||
@@ -108,13 +108,13 @@ void MyLookAndFeel::drawToggleButton(Graphics& g, | |||
Justification::centredLeft, 10); | |||
} | |||
void MyLookAndFeel::drawRotarySlider (Graphics& g, | |||
int x, int y, | |||
int width, int height, | |||
float sliderPos, | |||
const float rotaryStartAngle, | |||
const float rotaryEndAngle, | |||
Slider& slider) | |||
void MyLookAndFeel::drawRotarySlider(Graphics& g, | |||
int x, int y, | |||
int width, int height, | |||
float sliderPos, | |||
const float rotaryStartAngle, | |||
const float rotaryEndAngle, | |||
Slider& slider) override | |||
{ | |||
const float radius = jmin (width / 2, height / 2) - 2.0f; | |||
const float centreX = x + width * 0.5f; | |||
@@ -50,31 +50,31 @@ class MyLookAndFeel : public LookAndFeel_V2 | |||
{ | |||
public: | |||
MyLookAndFeel(); | |||
~MyLookAndFeel(); | |||
Font getComboBoxFont (ComboBox& box); | |||
Font getPopupMenuFont(); | |||
void getIdealPopupMenuItemSize (const String& text, | |||
const bool isSeparator, | |||
int standardMenuItemHeight, | |||
int& idealWidth, | |||
int& idealHeight); | |||
void drawToggleButton (Graphics& g, | |||
ToggleButton& button, | |||
bool isMouseOverButton, | |||
bool isButtonDown); | |||
void drawRotarySlider (Graphics& g, | |||
int x, int y, | |||
int width, int height, | |||
float sliderPosProportional, | |||
const float rotaryStartAngle, | |||
const float rotaryEndAngle, | |||
Slider& slider); | |||
~MyLookAndFeel() override; | |||
juce::Font getComboBoxFont (ComboBox& box) override; | |||
juce::Font getPopupMenuFont() override; | |||
void getIdealPopupMenuItemSize(const String& text, | |||
const bool isSeparator, | |||
int standardMenuItemHeight, | |||
int& idealWidth, | |||
int& idealHeight) override; | |||
void drawToggleButton(Graphics& g, | |||
ToggleButton& button, | |||
bool isMouseOverButton, | |||
bool isButtonDown) override; | |||
void drawRotarySlider(Graphics& g, | |||
int x, int y, | |||
int width, int height, | |||
float sliderPosProportional, | |||
const float rotaryStartAngle, | |||
const float rotaryEndAngle, | |||
Slider& slider) override; | |||
public: | |||
Font* Topaz; | |||
juce::Font* Topaz; | |||
}; | |||
#endif |
@@ -18,12 +18,22 @@ | |||
#ifndef JUCE_PLUGIN_WINDOW_HPP_INCLUDED | |||
#define JUCE_PLUGIN_WINDOW_HPP_INCLUDED | |||
#include "CarlaUtils.hpp" | |||
#include "juce_gui_basics.h" | |||
#ifdef HAVE_X11 | |||
# include <X11/Xlib.h> | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
namespace juce { | |||
#ifdef HAVE_X11 | |||
extern Display* display; | |||
#endif | |||
class JucePluginWindow : public DocumentWindow | |||
{ | |||
public: | |||
@@ -70,6 +80,21 @@ public: | |||
return fClosed; | |||
} | |||
void setTransientWinId(const uintptr_t winId) const override | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(winId != 0,); | |||
#ifdef HAVE_X11 | |||
CARLA_SAFE_ASSERT_RETURN(display != nullptr,); | |||
::Window window = (::Window)getWindowHandle(); | |||
CARLA_SAFE_ASSERT_RETURN(window != 0,); | |||
XSetTransientForHint(display, window, static_cast<Window>(winId)); | |||
#endif | |||
} | |||
protected: | |||
void closeButtonPressed() override | |||
{ | |||