| @@ -19,6 +19,14 @@ | |||||
| #include "../DistrhoUtils.hpp" | #include "../DistrhoUtils.hpp" | ||||
| #ifdef DISTRHO_OS_UNIX | |||||
| # include <cerrno> | |||||
| # include <sys/wait.h> | |||||
| # include <unistd.h> | |||||
| #else | |||||
| # error Unsupported platform! | |||||
| #endif | |||||
| START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -29,7 +37,13 @@ class ExternalWindow | |||||
| public: | public: | ||||
| ExternalWindow(const uint w = 1, const uint h = 1) | ExternalWindow(const uint w = 1, const uint h = 1) | ||||
| : width(w), | : width(w), | ||||
| height(h) {} | |||||
| height(h), | |||||
| pid(0) {} | |||||
| ~ExternalWindow() | |||||
| { | |||||
| terminateAndWaitForProcess(); | |||||
| } | |||||
| uint getWidth() const noexcept | uint getWidth() const noexcept | ||||
| { | { | ||||
| @@ -41,17 +55,99 @@ public: | |||||
| return height; | return height; | ||||
| } | } | ||||
| void setSize(const uint w, const uint h) noexcept | |||||
| bool isRunning() noexcept | |||||
| { | |||||
| if (pid <= 0) | |||||
| return false; | |||||
| const pid_t p = ::waitpid(pid, nullptr, WNOHANG); | |||||
| if (p == pid || (p == -1 && errno == ECHILD)) | |||||
| { | |||||
| printf("NOTICE: Child process exited while idle\n"); | |||||
| pid = 0; | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| protected: | |||||
| bool startExternalProcess(const char* args[]) | |||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(w > 0 && h > 0,) | |||||
| terminateAndWaitForProcess(); | |||||
| pid = vfork(); | |||||
| switch (pid) | |||||
| { | |||||
| case 0: | |||||
| execvp(args[0], (char**)args); | |||||
| _exit(1); | |||||
| return false; | |||||
| width = w; | |||||
| height = h; | |||||
| case -1: | |||||
| printf("Could not start external ui\n"); | |||||
| return false; | |||||
| default: | |||||
| return true; | |||||
| } | |||||
| } | } | ||||
| private: | private: | ||||
| uint width; | uint width; | ||||
| uint height; | uint height; | ||||
| pid_t pid; | |||||
| friend class UIExporter; | |||||
| void terminateAndWaitForProcess() | |||||
| { | |||||
| if (pid <= 0) | |||||
| return; | |||||
| printf("Waiting for previous process to stop,,,\n"); | |||||
| bool sendTerm = true; | |||||
| for (pid_t p;;) | |||||
| { | |||||
| p = ::waitpid(pid, nullptr, WNOHANG); | |||||
| switch (p) | |||||
| { | |||||
| case 0: | |||||
| if (sendTerm) | |||||
| { | |||||
| sendTerm = false; | |||||
| ::kill(pid, SIGTERM); | |||||
| } | |||||
| break; | |||||
| case -1: | |||||
| if (errno == ECHILD) | |||||
| { | |||||
| printf("Done! (no such process)\n"); | |||||
| pid = 0; | |||||
| return; | |||||
| } | |||||
| break; | |||||
| default: | |||||
| if (p == pid) | |||||
| { | |||||
| printf("Done! (clean wait)\n"); | |||||
| pid = 0; | |||||
| return; | |||||
| } | |||||
| break; | |||||
| } | |||||
| // 5 msec | |||||
| usleep(5*1000); | |||||
| } | |||||
| } | |||||
| DISTRHO_DECLARE_NON_COPY_CLASS(ExternalWindow) | DISTRHO_DECLARE_NON_COPY_CLASS(ExternalWindow) | ||||
| }; | }; | ||||