diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp index 99eb2485d..94b36eb96 100644 --- a/source/backend/engine/CarlaEngine.cpp +++ b/source/backend/engine/CarlaEngine.cpp @@ -447,7 +447,9 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, cons else #endif // ! BUILD_BRIDGE { +#ifndef BUILD_BRIDGE bool use16Outs; +#endif setLastError("Invalid or unsupported plugin type"); switch (ptype) @@ -1217,8 +1219,44 @@ void CarlaEngine::callback(const EngineCallbackOpcode action, const uint pluginI if (action == ENGINE_CALLBACK_IDLE) pData->isIdling = true; #ifdef BUILD_BRIDGE - else if (action == ENGINE_CALLBACK_UI_STATE_CHANGED && value1 != 1) - oscSend_bridge_configure("CarlaBridgeHideGUI", ""); + else + { + switch (action) + { + case ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED: + CARLA_SAFE_ASSERT_BREAK(value1 >= 0); + oscSend_bridge_parameter_value(static_cast(value1), value3); + break; + case ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED: + CARLA_SAFE_ASSERT_BREAK(value1 >= 0); + oscSend_bridge_default_value(static_cast(value1), value3); + break; + case ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED: + CARLA_SAFE_ASSERT_BREAK(value1 >= 0); + CARLA_SAFE_ASSERT_BREAK(value2 >= -1 && value2 <= 0x5F); + oscSend_bridge_parameter_midi_cc(static_cast(value1), static_cast(value2)); + break; + case ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED: + CARLA_SAFE_ASSERT_BREAK(value1 >= 0); + CARLA_SAFE_ASSERT_BREAK(value2 >= 0 && value2 < MAX_MIDI_CHANNELS); + oscSend_bridge_parameter_midi_channel(static_cast(value1), static_cast(value2)); + break; + case ENGINE_CALLBACK_PROGRAM_CHANGED: + CARLA_SAFE_ASSERT_BREAK(value1 >= -1); + oscSend_bridge_current_program(value1); + break; + case ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED: + CARLA_SAFE_ASSERT_BREAK(value1 >= -1); + oscSend_bridge_current_midi_program(value1); + break; + case ENGINE_CALLBACK_UI_STATE_CHANGED: + if (value1 != 1) + oscSend_bridge_configure("CarlaBridgeHideGUI", ""); + break; + default: + break; + } + } #endif if (pData->callback != nullptr) diff --git a/source/backend/plugin/CarlaPluginUi.cpp b/source/backend/plugin/CarlaPluginUi.cpp index 7e4548b76..9c4c232c8 100644 --- a/source/backend/plugin/CarlaPluginUi.cpp +++ b/source/backend/plugin/CarlaPluginUi.cpp @@ -30,7 +30,16 @@ // ----------------------------------------------------- // X11 +typedef void (*EventProcPtr)(XEvent* ev); + static const int X11Key_Escape = 9; +static bool gErrorTriggered = false; + +static int temporaryErrorHandler(Display*, XErrorEvent*) +{ + gErrorTriggered = true; + return 0; +} class X11PluginUi : public CarlaPluginUi { @@ -39,7 +48,9 @@ public: : CarlaPluginUi(cb), fDisplay(nullptr), fWindow(0), - fIsVisible(false) + fIsVisible(false), + fFirstShow(true), + fEventProc(nullptr) { fDisplay = XOpenDisplay(nullptr); CARLA_SAFE_ASSERT_RETURN(fDisplay != nullptr,); @@ -66,11 +77,11 @@ public: Atom wmDelete = XInternAtom(fDisplay, "WM_DELETE_WINDOW", True); XSetWMProtocols(fDisplay, fWindow, &wmDelete, 1); - pid_t pid = getpid(); - Atom _nwp = XInternAtom(fDisplay, "_NET_WM_PID", False); + const pid_t pid = getpid(); + const Atom _nwp = XInternAtom(fDisplay, "_NET_WM_PID", False); XChangeProperty(fDisplay, fWindow, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); - Atom _nwi = XInternAtom(fDisplay, "_NET_WM_ICON", False); + const Atom _nwi = XInternAtom(fDisplay, "_NET_WM_ICON", False); XChangeProperty(fDisplay, fWindow, _nwi, XA_CARDINAL, 32, PropModeReplace, (const uchar*)sCarlaX11Icon, sCarlaX11IconSize); if (parentId != 0) @@ -105,7 +116,34 @@ public: CARLA_SAFE_ASSERT_RETURN(fDisplay != nullptr,); CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); + if (fFirstShow) + { + if (const Window childWindow = getChildWindow()) + { + const Atom _xevp = XInternAtom(fDisplay, "_XEventProc", False); + + gErrorTriggered = false; + const XErrorHandler oldErrorHandler(XSetErrorHandler(temporaryErrorHandler)); + + Atom actualType; + int actualFormat; + ulong nitems, bytesAfter; + uchar* data = nullptr; + + XGetWindowProperty(fDisplay, childWindow, _xevp, 0, 1, False, AnyPropertyType, &actualType, &actualFormat, &nitems, &bytesAfter, &data); + XSetErrorHandler(oldErrorHandler); + + if (nitems == 1 && ! gErrorTriggered) + { + fEventProc = *reinterpret_cast(data); + XMapRaised(fDisplay, childWindow); + } + } + } + fIsVisible = true; + fFirstShow = false; + XMapRaised(fDisplay, fWindow); XFlush(fDisplay); } @@ -122,6 +160,11 @@ public: void idle() override { + // prevent recursion + if (fIsIdling) return; + + fIsIdling = true; + for (XEvent event; XPending(fDisplay) > 0;) { XNextEvent(fDisplay, &event); @@ -157,7 +200,11 @@ public: if (type != nullptr) XFree(type); + else if (fEventProc != nullptr) + fEventProc(&event); } + + fIsIdling = false; } void focus() override @@ -219,10 +266,33 @@ public: return fDisplay; } +protected: + Window getChildWindow() const + { + CARLA_SAFE_ASSERT_RETURN(fDisplay != nullptr, 0); + CARLA_SAFE_ASSERT_RETURN(fWindow != 0, 0); + + Window rootWindow, parentWindow, ret = 0; + Window* childWindows = nullptr; + uint numChildren = 0; + + XQueryTree(fDisplay, fWindow, &rootWindow, &parentWindow, &childWindows, &numChildren); + + if (numChildren > 0 && childWindows != nullptr) + { + ret = childWindows[0]; + XFree(childWindows); + } + + return ret; + } + private: Display* fDisplay; Window fWindow; bool fIsVisible; + bool fFirstShow; + EventProcPtr fEventProc; }; #endif @@ -258,10 +328,10 @@ bool CarlaPluginUi::tryTransientWinIdMatch(const uintptr_t pid, const char* cons const ScopedDisplay sd; CARLA_SAFE_ASSERT_RETURN(sd.display != nullptr, true); - Atom _ncl = XInternAtom(sd.display, "_NET_CLIENT_LIST" , False); - Atom _nwn = XInternAtom(sd.display, "_NET_WM_NAME", False); - Atom _nwp = XInternAtom(sd.display, "_NET_WM_PID", False); - Atom utf8 = XInternAtom(sd.display, "UTF8_STRING", True); + const Atom _ncl = XInternAtom(sd.display, "_NET_CLIENT_LIST" , False); + const Atom _nwn = XInternAtom(sd.display, "_NET_WM_NAME", False); + const Atom _nwp = XInternAtom(sd.display, "_NET_WM_PID", False); + const Atom utf8 = XInternAtom(sd.display, "UTF8_STRING", True); Atom actualType; int actualFormat; @@ -360,13 +430,14 @@ bool CarlaPluginUi::tryTransientWinIdMatch(const uintptr_t pid, const char* cons if (lastGoodWindow == 0) return false; - Atom _nwt = XInternAtom(sd.display ,"_NET_WM_STATE", False); - Atom _nws[2]; - _nws[0] = XInternAtom(sd.display, "_NET_WM_STATE_SKIP_TASKBAR", False); - _nws[1] = XInternAtom(sd.display, "_NET_WM_STATE_SKIP_PAGER", False); + const Atom _nwt = XInternAtom(sd.display ,"_NET_WM_STATE", False); + const Atom _nws[2] = { + XInternAtom(sd.display, "_NET_WM_STATE_SKIP_TASKBAR", False), + XInternAtom(sd.display, "_NET_WM_STATE_SKIP_PAGER", False) + }; XChangeProperty(sd.display, lastGoodWindow, _nwt, XA_ATOM, 32, PropModeAppend, (const uchar*)_nws, 2); - Atom _nwi = XInternAtom(sd.display, "_NET_WM_ICON", False); + const Atom _nwi = XInternAtom(sd.display, "_NET_WM_ICON", False); XChangeProperty(sd.display, lastGoodWindow, _nwi, XA_CARDINAL, 32, PropModeReplace, (const uchar*)sCarlaX11Icon, sCarlaX11IconSize); XSetTransientForHint(sd.display, lastGoodWindow, (Window)winId); diff --git a/source/backend/plugin/CarlaPluginUi.hpp b/source/backend/plugin/CarlaPluginUi.hpp index 140255e9c..34651fc2d 100644 --- a/source/backend/plugin/CarlaPluginUi.hpp +++ b/source/backend/plugin/CarlaPluginUi.hpp @@ -57,8 +57,9 @@ public: #endif protected: + bool fIsIdling; CloseCallback* fCallback; - CarlaPluginUi(CloseCallback* const cb) noexcept : fCallback(cb) {} + CarlaPluginUi(CloseCallback* const cb) noexcept : fIsIdling(false), fCallback(cb) {} }; // ----------------------------------------------------- diff --git a/source/backend/plugin/VstPlugin.cpp b/source/backend/plugin/VstPlugin.cpp index 2f63482a8..e7221dde6 100644 --- a/source/backend/plugin/VstPlugin.cpp +++ b/source/backend/plugin/VstPlugin.cpp @@ -19,7 +19,7 @@ #include "CarlaEngine.hpp" #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) -# define USE_JUCE_FOR_VST 1 +# define USE_JUCE_FOR_VST #endif #ifndef USE_JUCE_FOR_VST @@ -1785,7 +1785,7 @@ protected: { #ifdef DEBUG if (opcode != audioMasterGetTime) - carla_debug("VstPlugin::handleAudioMasterCallback(%02i:%s, %i, " P_INTPTR ", %p, %f)", opcode, vstEffectOpcode2str(opcode), index, value, ptr, opt); + carla_debug("VstPlugin::handleAudioMasterCallback(%02i:%s, %i, " P_INTPTR ", %p, %f)", opcode, vstMasterOpcode2str(opcode), index, value, ptr, opt); #endif intptr_t ret = 0; @@ -1793,8 +1793,7 @@ protected: switch (opcode) { case audioMasterAutomate: { - if (! pData->enabled) - break; + CARLA_SAFE_ASSERT_BREAK(pData->enabled); // plugins should never do this: CARLA_SAFE_ASSERT_INT(index >= 0 && index < static_cast(pData->param.count), index); @@ -1835,8 +1834,8 @@ protected: break; case audioMasterIdle: - if (fUi.window != nullptr) - fUi.window->idle(); + //pData->engine->callback(ENGINE_CALLBACK_IDLE, 0, 0, 0, 0.0f, nullptr); + //pData->engine->idle(); break; #if ! VST_FORCE_DEPRECATED @@ -2543,7 +2542,7 @@ CarlaPlugin* CarlaPlugin::newVST(const Initializer& init) { carla_debug("CarlaPlugin::newVST({%p, \"%s\", \"%s\", " P_INT64 "})", init.engine, init.filename, init.name, init.uniqueId); -#if USE_JUCE_FOR_VST +#ifdef USE_JUCE_FOR_VST return newJuce(init, "VST"); #else VstPlugin* const plugin(new VstPlugin(init.engine, init.id));