| @@ -420,9 +420,45 @@ public: | |||
| fUiURI = uiURI; | |||
| } | |||
| void startPipeServer() noexcept | |||
| bool startPipeServer() noexcept | |||
| { | |||
| CarlaPipeServer::startPipeServer(fFilename, fPluginURI, fUiURI); | |||
| return CarlaPipeServer::startPipeServer(fFilename, fPluginURI, fUiURI); | |||
| } | |||
| void writeUiOptionsMessage(const bool useTheme, const bool useThemeColors, const char* const windowTitle, uintptr_t transientWindowId) const noexcept | |||
| { | |||
| char tmpBuf[0xff+1]; | |||
| tmpBuf[0xff] = '\0'; | |||
| const CarlaMutexLocker cml(getPipeLock()); | |||
| _writeMsgBuffer("uiOptions\n", 10); | |||
| { | |||
| std::snprintf(tmpBuf, 0xff, "%s\n", bool2str(useTheme)); | |||
| _writeMsgBuffer(tmpBuf, std::strlen(tmpBuf)); | |||
| std::snprintf(tmpBuf, 0xff, "%s\n", bool2str(useThemeColors)); | |||
| _writeMsgBuffer(tmpBuf, std::strlen(tmpBuf)); | |||
| writeAndFixMessage(windowTitle != nullptr ? windowTitle : ""); | |||
| std::snprintf(tmpBuf, 0xff, P_INTPTR "\n", transientWindowId); | |||
| _writeMsgBuffer(tmpBuf, std::strlen(tmpBuf)); | |||
| } | |||
| flushMessages(); | |||
| } | |||
| void writeUiTitleMessage(const char* const title) const noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(title != nullptr && title[0] != '\0',); | |||
| const CarlaMutexLocker cml(getPipeLock()); | |||
| _writeMsgBuffer("uiTitle\n", 8); | |||
| writeAndFixMessage(title); | |||
| flushMessages(); | |||
| } | |||
| protected: | |||
| @@ -1190,6 +1226,8 @@ public: | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fUI.type != UI::TYPE_NULL,); | |||
| const uintptr_t frontendWinId(pData->engine->getOptions().frontendWinId); | |||
| if (! yesNo) | |||
| pData->transientTryCounter = 0; | |||
| @@ -1203,12 +1241,16 @@ public: | |||
| return; | |||
| } | |||
| fPipeServer.startPipeServer(); | |||
| if (! fPipeServer.startPipeServer()) | |||
| { | |||
| pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, 0, 0, 0.0f, nullptr); | |||
| return; | |||
| } | |||
| for (std::size_t i=CARLA_URI_MAP_ID_COUNT, count=fCustomURIDs.count(); i < count; ++i) | |||
| fPipeServer.writeLv2UridMessage(static_cast<uint32_t>(i), fCustomURIDs.getAt(i, nullptr)); | |||
| fPipeServer.writeLv2UridMessage(CARLA_URI_MAP_ID_NULL, "Complete"); | |||
| fPipeServer.writeUiOptionsMessage(true, true, fLv2Options.windowTitle, frontendWinId); | |||
| fPipeServer.writeShowMessage(); | |||
| } | |||
| @@ -1242,7 +1284,6 @@ public: | |||
| if (fUI.type == UI::TYPE_EMBED) | |||
| { | |||
| const char* msg = nullptr; | |||
| const uintptr_t frontendWinId(pData->engine->getOptions().frontendWinId); | |||
| switch (fUI.rdfDescriptor->Type) | |||
| { | |||
| @@ -1285,11 +1326,7 @@ public: | |||
| } | |||
| if (fUI.window == nullptr && fExt.uishow == nullptr) | |||
| { | |||
| return pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, -1, 0, 0.0f, msg); | |||
| // unused | |||
| (void)frontendWinId; | |||
| } | |||
| if (fUI.window != nullptr) | |||
| { | |||
| @@ -180,11 +180,10 @@ protected: | |||
| { | |||
| carla_debug("CarlaBridgeToolkitGtk::handleRealize()"); | |||
| #ifdef CARLA_OS_LINUX | |||
| if (const char* const winIdStr = std::getenv("ENGINE_OPTION_FRONTEND_WIN_ID")) | |||
| if (const long long winId = std::strtoll(winIdStr, nullptr, 16)) | |||
| setTransient(static_cast<uintptr_t>(winId)); | |||
| #endif | |||
| const CarlaBridgeUI::Options& options(ui->getOptions()); | |||
| if (options.transientWindowId != 0) | |||
| setTransient(options.transientWindowId); | |||
| } | |||
| gboolean handleTimeout() | |||
| @@ -203,7 +202,6 @@ protected: | |||
| return true; | |||
| } | |||
| #ifdef CARLA_OS_LINUX | |||
| void setTransient(const uintptr_t winId) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); | |||
| @@ -212,7 +210,7 @@ protected: | |||
| GdkWindow* const gdkWindow(gtk_widget_get_window(fWindow)); | |||
| CARLA_SAFE_ASSERT_RETURN(gdkWindow != nullptr,); | |||
| # ifdef BRIDGE_GTK3 | |||
| #ifdef BRIDGE_GTK3 | |||
| GdkDisplay* const gdkDisplay(gdk_window_get_display(gdkWindow)); | |||
| CARLA_SAFE_ASSERT_RETURN(gdkDisplay != nullptr,); | |||
| @@ -221,17 +219,16 @@ protected: | |||
| const ::XID xid(gdk_x11_window_get_xid(gdkWindow)); | |||
| CARLA_SAFE_ASSERT_RETURN(xid != 0,); | |||
| # else | |||
| #else | |||
| ::Display* const display(gdk_x11_drawable_get_xdisplay(gdkWindow)); | |||
| CARLA_SAFE_ASSERT_RETURN(display != nullptr,); | |||
| const ::XID xid(gdk_x11_drawable_get_xid(gdkWindow)); | |||
| CARLA_SAFE_ASSERT_RETURN(xid != 0,); | |||
| # endif | |||
| #endif | |||
| XSetTransientForHint(display, xid, static_cast< ::Window>(winId)); | |||
| } | |||
| #endif | |||
| // --------------------------------------------------------------------- | |||
| @@ -66,7 +66,9 @@ public: | |||
| CARLA_SAFE_ASSERT_RETURN(fUI != nullptr, false); | |||
| fUI->setTitle(options.windowTitle.buffer()); | |||
| fUI->setTransientWinId(options.transientWindowId); | |||
| if (options.transientWindowId != 0) | |||
| fUI->setTransientWinId(options.transientWindowId); | |||
| return true; | |||
| } | |||
| @@ -606,6 +606,14 @@ public: | |||
| fCustomURIDs.append(carla_strdup(uri)); | |||
| } | |||
| void uiOptionsChanged(const bool useTheme, const bool useThemeColors, const char* const windowTitle, uintptr_t transientWindowId) override | |||
| { | |||
| fUiOptions.useTheme = useTheme; | |||
| fUiOptions.useThemeColors = useThemeColors; | |||
| fUiOptions.windowTitle = windowTitle; | |||
| fUiOptions.transientWindowId = transientWindowId; | |||
| } | |||
| // --------------------------------------------------------------------- | |||
| LV2_URID getCustomURID(const char* const uri) | |||
| @@ -33,9 +33,7 @@ CARLA_BRIDGE_START_NAMESPACE | |||
| CarlaBridgeUI::CarlaBridgeUI() noexcept | |||
| : CarlaPipeClient(), | |||
| fQuitReceived(false), | |||
| #ifdef BRIDGE_LV2 | |||
| fUridMapComplete(false), | |||
| #endif | |||
| fGotOptions(false), | |||
| fToolkit(nullptr), | |||
| fLib(nullptr), | |||
| fLibFilename(), | |||
| @@ -110,11 +108,9 @@ const char* CarlaBridgeUI::libError() const noexcept | |||
| bool CarlaBridgeUI::msgReceived(const char* const msg) noexcept | |||
| { | |||
| #ifdef BRIDGE_LV2 | |||
| if (! fUridMapComplete) { | |||
| CARLA_SAFE_ASSERT_RETURN(std::strcmp(msg, "urid") == 0, true); | |||
| } | |||
| #endif | |||
| if (! fGotOptions) { | |||
| CARLA_SAFE_ASSERT_RETURN(std::strcmp(msg, "urid") == 0 || std::strcmp(msg, "uiOptions") == 0, true); | |||
| } | |||
| if (std::strcmp(msg, "control") == 0) | |||
| { | |||
| @@ -206,21 +202,32 @@ bool CarlaBridgeUI::msgReceived(const char* const msg) noexcept | |||
| CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(urid), true); | |||
| CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uri), true); | |||
| if (urid == 0) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(std::strcmp(uri, "Complete") == 0, true); | |||
| fUridMapComplete = true; | |||
| } | |||
| else | |||
| { | |||
| if (urid != 0) | |||
| dspURIDReceived(urid, uri); | |||
| } | |||
| delete[] uri; | |||
| return true; | |||
| } | |||
| #endif | |||
| if (std::strcmp(msg, "uiOptions") == 0) | |||
| { | |||
| bool useTheme, useThemeColors; | |||
| const char* windowTitle; | |||
| uint64_t transientWindowId; | |||
| CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(useTheme), true); | |||
| CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(useThemeColors), true); | |||
| CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(windowTitle), true); | |||
| CARLA_SAFE_ASSERT_RETURN(readNextLineAsULong(transientWindowId), true); | |||
| fGotOptions = true; | |||
| uiOptionsChanged(useTheme, useThemeColors, windowTitle, transientWindowId); | |||
| delete[] windowTitle; | |||
| return true; | |||
| } | |||
| CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, true); | |||
| if (std::strcmp(msg, "show") == 0) | |||
| @@ -272,40 +279,30 @@ bool CarlaBridgeUI::init(const int argc, const char* argv[]) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, false); | |||
| if (! fToolkit->init(argc, argv)) | |||
| return false; | |||
| if (argc == 7) | |||
| { | |||
| if (! initPipeClient(argv)) | |||
| { | |||
| fToolkit->quit(); | |||
| delete fToolkit; | |||
| fToolkit = nullptr; | |||
| return false; | |||
| } | |||
| #ifdef BRIDGE_LV2 | |||
| // wait for URID map to complete | |||
| for (int i=0; i<20 && ! fUridMapComplete; ++i) | |||
| // wait for ui options, FIXME | |||
| for (int i=0; i<20 && ! fGotOptions; ++i) | |||
| { | |||
| idlePipe(); | |||
| idlePipe(true); | |||
| carla_msleep(100); | |||
| } | |||
| if (! fUridMapComplete) | |||
| if (! fGotOptions) | |||
| { | |||
| fToolkit->quit(); | |||
| delete fToolkit; | |||
| fToolkit = nullptr; | |||
| closePipeClient(); | |||
| return false; | |||
| } | |||
| #endif | |||
| } | |||
| else | |||
| if (! fToolkit->init(argc, argv)) | |||
| { | |||
| // no mapping needed | |||
| fUridMapComplete = true; | |||
| if (argc == 7) | |||
| closePipeClient(); | |||
| return false; | |||
| } | |||
| return true; | |||
| @@ -75,6 +75,8 @@ protected: | |||
| virtual void dspURIDReceived(const LV2_URID urid, const char* const uri) = 0; | |||
| #endif | |||
| virtual void uiOptionsChanged(const bool useTheme, const bool useThemeColors, const char* const windowTitle, uintptr_t transientWindowId) = 0; | |||
| public: | |||
| // --------------------------------------------------------------------- | |||
| // UI initialization | |||
| @@ -143,9 +145,7 @@ public: | |||
| protected: | |||
| bool fQuitReceived; | |||
| #ifdef BRIDGE_LV2 | |||
| bool fUridMapComplete; | |||
| #endif | |||
| bool fGotOptions; | |||
| CarlaBridgeToolkit* fToolkit; | |||
| lib_t fLib; | |||
| @@ -59,12 +59,16 @@ public: | |||
| fUiTitle = uiTitle; | |||
| } | |||
| void startPipeServer(const bool show = true) noexcept | |||
| bool startPipeServer(const bool show = true) noexcept | |||
| { | |||
| CarlaPipeServer::startPipeServer(fFilename, fSampleRate, fUiTitle); | |||
| if (CarlaPipeServer::startPipeServer(fFilename, fSampleRate, fUiTitle)) | |||
| { | |||
| if (show) | |||
| writeShowMessage(); | |||
| return true; | |||
| } | |||
| if (show) | |||
| writeShowMessage(); | |||
| return false; | |||
| } | |||
| protected: | |||
| @@ -481,7 +481,7 @@ bool CarlaPipeCommon::isPipeRunning() const noexcept | |||
| return (pData->pipeRecv != INVALID_PIPE_VALUE && pData->pipeSend != INVALID_PIPE_VALUE); | |||
| } | |||
| void CarlaPipeCommon::idlePipe() noexcept | |||
| void CarlaPipeCommon::idlePipe(const bool onlyOnce) noexcept | |||
| { | |||
| const char* locale = nullptr; | |||
| @@ -492,7 +492,7 @@ void CarlaPipeCommon::idlePipe() noexcept | |||
| if (msg == nullptr) | |||
| break; | |||
| if (locale == nullptr) | |||
| if (locale == nullptr && ! onlyOnce) | |||
| { | |||
| locale = carla_strdup_safe(::setlocale(LC_NUMERIC, nullptr)); | |||
| ::setlocale(LC_NUMERIC, "C"); | |||
| @@ -507,6 +507,9 @@ void CarlaPipeCommon::idlePipe() noexcept | |||
| pData->isReading = false; | |||
| delete[] msg; | |||
| if (onlyOnce) | |||
| break; | |||
| } | |||
| if (locale != nullptr) | |||
| @@ -765,27 +768,6 @@ bool CarlaPipeCommon::flushMessages() const noexcept | |||
| // ------------------------------------------------------------------- | |||
| void CarlaPipeCommon::writeShowMessage() const noexcept | |||
| { | |||
| const CarlaMutexLocker cml(pData->writeLock); | |||
| _writeMsgBuffer("show\n", 5); | |||
| flushMessages(); | |||
| } | |||
| void CarlaPipeCommon::writeFocusMessage() const noexcept | |||
| { | |||
| const CarlaMutexLocker cml(pData->writeLock); | |||
| _writeMsgBuffer("focus\n", 6); | |||
| flushMessages(); | |||
| } | |||
| void CarlaPipeCommon::writeHideMessage() const noexcept | |||
| { | |||
| const CarlaMutexLocker cml(pData->writeLock); | |||
| _writeMsgBuffer("show\n", 5); | |||
| flushMessages(); | |||
| } | |||
| void CarlaPipeCommon::writeErrorMessage(const char* const error) const noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(error != nullptr && error[0] != '\0',); | |||
| @@ -796,8 +778,6 @@ void CarlaPipeCommon::writeErrorMessage(const char* const error) const noexcept | |||
| flushMessages(); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| void CarlaPipeCommon::writeControlMessage(const uint32_t index, const float value) const noexcept | |||
| { | |||
| char tmpBuf[0xff+1]; | |||
| @@ -931,6 +911,7 @@ void CarlaPipeCommon::writeLv2AtomMessage(const uint32_t index, const LV2_Atom* | |||
| void CarlaPipeCommon::writeLv2UridMessage(const uint32_t urid, const char* const uri) const noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(urid != 0,); | |||
| CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0',); | |||
| char tmpBuf[0xff+1]; | |||
| @@ -1380,6 +1361,27 @@ void CarlaPipeServer::closePipeServer() noexcept | |||
| } | |||
| } | |||
| void CarlaPipeServer::writeShowMessage() const noexcept | |||
| { | |||
| const CarlaMutexLocker cml(pData->writeLock); | |||
| _writeMsgBuffer("show\n", 5); | |||
| flushMessages(); | |||
| } | |||
| void CarlaPipeServer::writeFocusMessage() const noexcept | |||
| { | |||
| const CarlaMutexLocker cml(pData->writeLock); | |||
| _writeMsgBuffer("focus\n", 6); | |||
| flushMessages(); | |||
| } | |||
| void CarlaPipeServer::writeHideMessage() const noexcept | |||
| { | |||
| const CarlaMutexLocker cml(pData->writeLock); | |||
| _writeMsgBuffer("show\n", 5); | |||
| flushMessages(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| CarlaPipeClient::CarlaPipeClient() noexcept | |||
| @@ -65,7 +65,7 @@ public: | |||
| /*! | |||
| * Check the pipe for new messages and send them to msgReceived(). | |||
| */ | |||
| void idlePipe() noexcept; | |||
| void idlePipe(const bool onlyOnce = false) noexcept; | |||
| // ------------------------------------------------------------------- | |||
| // write lock | |||
| @@ -168,21 +168,6 @@ public: | |||
| // ------------------------------------------------------------------- | |||
| // write prepared messages, no lock or flush needed (done internally) | |||
| /*! | |||
| * Write a single "show" message. | |||
| */ | |||
| void writeShowMessage() const noexcept; | |||
| /*! | |||
| * Write a single "focus" message. | |||
| */ | |||
| void writeFocusMessage() const noexcept; | |||
| /*! | |||
| * Write a single "hide" message. | |||
| */ | |||
| void writeHideMessage() const noexcept; | |||
| /*! | |||
| * Write an "error" message. | |||
| */ | |||
| @@ -276,6 +261,24 @@ public: | |||
| */ | |||
| void closePipeServer() noexcept; | |||
| // ------------------------------------------------------------------- | |||
| // write prepared messages, no lock or flush needed (done internally) | |||
| /*! | |||
| * Write a single "show" message. | |||
| */ | |||
| void writeShowMessage() const noexcept; | |||
| /*! | |||
| * Write a single "focus" message. | |||
| */ | |||
| void writeFocusMessage() const noexcept; | |||
| /*! | |||
| * Write a single "hide" message. | |||
| */ | |||
| void writeHideMessage() const noexcept; | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPipeServer) | |||
| }; | |||