| @@ -19,6 +19,14 @@ | |||
| #include "../DistrhoUtils.hpp" | |||
| #ifdef DISTRHO_OS_UNIX | |||
| # include <cerrno> | |||
| # include <sys/wait.h> | |||
| # include <unistd.h> | |||
| #else | |||
| # error Unsupported platform! | |||
| #endif | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| @@ -29,7 +37,13 @@ class ExternalWindow | |||
| public: | |||
| ExternalWindow(const uint w = 1, const uint h = 1) | |||
| : width(w), | |||
| height(h) {} | |||
| height(h), | |||
| pid(0) {} | |||
| ~ExternalWindow() | |||
| { | |||
| terminateAndWaitForProcess(); | |||
| } | |||
| uint getWidth() const noexcept | |||
| { | |||
| @@ -41,17 +55,99 @@ public: | |||
| 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: | |||
| uint width; | |||
| 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) | |||
| }; | |||