commit 85ab63ade88fe7ec0f6f3d6c9261f3a3b1cdd3fb
parent 1d80bc8b8c989dca2dece2acf4225dc3b8993a7a
Author: falkTX <falktx@falktx.com>
Date: Sun, 22 Aug 2021 23:24:43 +0100
ExternalWindow mostly working now, update old hacky example too
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
4 files changed, 170 insertions(+), 113 deletions(-)
diff --git a/distrho/extra/ExternalWindow.hpp b/distrho/extra/ExternalWindow.hpp
@@ -43,26 +43,7 @@ START_NAMESPACE_DISTRHO
*/
class ExternalWindow
{
- struct PrivateData {
- uintptr_t parentWindowHandle;
- uintptr_t transientWinId;
- uint width;
- uint height;
- double scaleFactor;
- String title;
- bool visible;
- pid_t pid;
-
- PrivateData()
- : parentWindowHandle(0),
- transientWinId(0),
- width(1),
- height(1),
- scaleFactor(1.0),
- title(),
- visible(false),
- pid(0) {}
- } pData;
+ struct PrivateData;
public:
/**
@@ -82,9 +63,7 @@ public:
*/
virtual ~ExternalWindow()
{
- /*
- terminateAndWaitForProcess();
- */
+ DISTRHO_SAFE_ASSERT(!pData.visible);
}
/* --------------------------------------------------------------------------------------------------------
@@ -92,11 +71,17 @@ public:
virtual bool isRunning() const
{
+ if (ext.inUse)
+ return ext.isRunning();
+
return isVisible();
}
virtual bool isQuiting() const
{
+ if (ext.inUse)
+ return ext.isQuiting;
+
return !isVisible();
}
@@ -113,6 +98,14 @@ public:
transientWindowChanged(winId);
}
+ void close()
+ {
+ hide();
+
+ if (ext.inUse)
+ terminateAndWaitForExternalProcess();
+ }
+
#if DISTRHO_PLUGIN_HAS_EMBED_UI
/**
Whether this Window is embed into another (usually not DGL-controlled) Window.
@@ -280,6 +273,25 @@ public:
virtual void focus() {}
protected:
+ /* --------------------------------------------------------------------------------------------------------
+ * ExternalWindow special calls for running externals tools */
+
+ bool startExternalProcess(const char* args[])
+ {
+ ext.inUse = true;
+
+ return ext.start(args);
+ }
+
+ void terminateAndWaitForExternalProcess()
+ {
+ ext.isQuiting = true;
+ ext.terminateAndWait();
+ }
+
+ /* --------------------------------------------------------------------------------------------------------
+ * ExternalWindow specific callbacks */
+
/**
A function called when the window is resized.
*/
@@ -309,101 +321,125 @@ protected:
return; (void)winId;
}
- /*
- bool isRunning() noexcept
- {
- if (pid <= 0)
- return false;
+private:
+ friend class PluginWindow;
+ friend class UI;
- const pid_t p = ::waitpid(pid, nullptr, WNOHANG);
+ struct ExternalProcess {
+ bool inUse;
+ bool isQuiting;
+ mutable pid_t pid;
- if (p == pid || (p == -1 && errno == ECHILD))
- {
- printf("NOTICE: Child process exited while idle\n");
- pid = 0;
- return false;
- }
+ ExternalProcess()
+ : inUse(false),
+ isQuiting(false),
+ pid(0) {}
- return true;
- }
+ bool isRunning() const noexcept
+ {
+ if (pid <= 0)
+ return false;
- */
+ const pid_t p = ::waitpid(pid, nullptr, WNOHANG);
-protected:
- /*
- bool startExternalProcess(const char* args[])
- {
- terminateAndWaitForProcess();
+ if (p == pid || (p == -1 && errno == ECHILD))
+ {
+ d_stdout("NOTICE: Child process exited while idle");
+ pid = 0;
+ return false;
+ }
- pid = vfork();
+ return true;
+ }
- switch (pid)
+ bool start(const char* args[])
{
- case 0:
- execvp(args[0], (char**)args);
- _exit(1);
- return false;
-
- case -1:
- printf("Could not start external ui\n");
- return false;
+ terminateAndWait();
- default:
- return true;
- }
- }
+ pid = vfork();
- void terminateAndWaitForProcess()
- {
- if (pid <= 0)
- return;
+ switch (pid)
+ {
+ case 0:
+ execvp(args[0], (char**)args);
+ _exit(1);
+ return false;
- printf("Waiting for previous process to stop,,,\n");
+ case -1:
+ d_stderr("Could not start external ui");
+ return false;
- bool sendTerm = true;
+ default:
+ return true;
+ }
+ }
- for (pid_t p;;)
+ void terminateAndWait()
{
- p = ::waitpid(pid, nullptr, WNOHANG);
+ if (pid <= 0)
+ return;
+
+ d_stdout("Waiting for external process to stop,,,");
+
+ bool sendTerm = true;
- switch (p)
+ for (pid_t p;;)
{
- case 0:
- if (sendTerm)
- {
- sendTerm = false;
- ::kill(pid, SIGTERM);
- }
- break;
+ p = ::waitpid(pid, nullptr, WNOHANG);
- case -1:
- if (errno == ECHILD)
+ switch (p)
{
- printf("Done! (no such process)\n");
- pid = 0;
- return;
+ case 0:
+ if (sendTerm)
+ {
+ sendTerm = false;
+ ::kill(pid, SIGTERM);
+ }
+ break;
+
+ case -1:
+ if (errno == ECHILD)
+ {
+ d_stdout("Done! (no such process)");
+ pid = 0;
+ return;
+ }
+ break;
+
+ default:
+ if (p == pid)
+ {
+ d_stdout("Done! (clean wait)");
+ pid = 0;
+ return;
+ }
+ break;
}
- break;
- default:
- if (p == pid)
- {
- printf("Done! (clean wait)\n");
- pid = 0;
- return;
- }
- break;
+ // 5 msec
+ usleep(5*1000);
}
-
- // 5 msec
- usleep(5*1000);
}
- }
- */
+ } ext;
-private:
- friend class PluginWindow;
- friend class UI;
+ struct PrivateData {
+ uintptr_t parentWindowHandle;
+ uintptr_t transientWinId;
+ uint width;
+ uint height;
+ double scaleFactor;
+ String title;
+ bool visible;
+
+ PrivateData()
+ : parentWindowHandle(0),
+ transientWinId(0),
+ width(1),
+ height(1),
+ scaleFactor(1.0),
+ title(),
+ visible(false) {}
+ } pData;
DISTRHO_DECLARE_NON_COPYABLE(ExternalWindow)
};
diff --git a/distrho/src/DistrhoUIPrivateData.hpp b/distrho/src/DistrhoUIPrivateData.hpp
@@ -84,6 +84,9 @@ struct PluginApplication
d_msleep(30);
idleCallback->idleCallback();
}
+
+ if (! ui->isQuiting())
+ ui->close();
}
// these are not needed
@@ -136,18 +139,13 @@ public:
uintptr_t getNativeWindowHandle() const noexcept { return ui->pData.parentWindowHandle; }
// direct mappings
- bool isVisible() const noexcept { return ui->isVisible(); }
+ void close() { ui->close(); }
void focus() { ui->focus(); }
void show() { ui->show(); }
+ bool isVisible() const noexcept { return ui->isVisible(); }
void setTitle(const char* const title) { ui->setTitle(title); }
void setVisible(const bool visible) { ui->setVisible(visible); }
- // custom
- void close()
- {
- ui->hide();
- }
-
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
};
#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
diff --git a/examples/ExternalUI/ExternalExampleUI.cpp b/examples/ExternalUI/ExternalExampleUI.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com>
+ * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
@@ -14,6 +14,9 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+// needed for IDE
+#include "DistrhoPluginInfo.h"
+
#include "DistrhoUI.hpp"
// Extra includes for current path and fifo stuff
@@ -46,13 +49,14 @@ static bool fileExists(const char* const filename)
static ssize_t
writeRetry(int fd, const void* src, size_t size)
{
- ssize_t error;
+ ssize_t error;
+ int attempts = 0;
- do {
- error = write(fd, src, size);
- } while (error == -1 && (errno == EINTR || errno == EPIPE));
+ do {
+ error = write(fd, src, size);
+ } while (error == -1 && (errno == EINTR || errno == EPIPE) && ++attempts < 5);
- return error;
+ return error;
}
// -----------------------------------------------------------------------------------------------------------
@@ -72,7 +76,7 @@ public:
fExternalScript.truncate(fExternalScript.rfind('/'));
}
- fExternalScript += "/d_extui.sh";
+ fExternalScript += "/ExternalLauncher.sh";
d_stdout("External script = %s", fExternalScript.buffer());
}
@@ -106,6 +110,17 @@ protected:
* External Window overrides */
/**
+ Keep-alive.
+ */
+ void uiIdle() override
+ {
+ if (fFifo == -1)
+ return;
+
+ writeRetry(fFifo, "idle\n", 5);
+ }
+
+ /**
Manage external process and IPC when UI is requested to be visible.
*/
void setVisible(const bool yesNo) override
@@ -119,7 +134,7 @@ protected:
char winIdStr[24];
std::memset(winIdStr, 0, sizeof(winIdStr));
- std::snprintf(winIdStr, 23, "%lu", getTransientWinId());
+ std::snprintf(winIdStr, 23, "%lu", getTransientWindowId());
const char* args[] = {
fExternalScript.buffer(),
@@ -145,12 +160,12 @@ protected:
DISTRHO_SAFE_ASSERT(writeRetry(fFifo, "quit\n", 5) == 5);
fsync(fFifo);
}
- close(fFifo);
+ ::close(fFifo);
fFifo = -1;
}
unlink(kFifoFilename);
- terminateAndWaitForProcess();
+ terminateAndWaitForExternalProcess();
}
UI::setVisible(yesNo);
diff --git a/examples/ExternalUI/ExternalLauncher.sh b/examples/ExternalUI/ExternalLauncher.sh
@@ -20,13 +20,21 @@ fi
# Setup cancellation point for this script
quitfn() {
qdbus ${dbusRef} close 2>/dev/null
+ exit 0
}
trap quitfn SIGINT
trap quitfn SIGTERM
# Read Fifo for new values or a quit message
-while read line <"${FIFO}"; do
+while read -t 5 line < "${FIFO}"; do
+ if [ $? != 0 ]; then
+ echo "Timed out, closing"
+ break
+ fi
+ if echo "${line}" | grep -q "idle"; then
+ continue
+ fi
if echo "${line}" | grep -q "quit"; then
break
fi