diff --git a/src/plugin/ChildProcess.hpp b/src/plugin/ChildProcess.hpp
index 4ef01b4..1d298b8 100644
--- a/src/plugin/ChildProcess.hpp
+++ b/src/plugin/ChildProcess.hpp
@@ -55,36 +55,8 @@ class ChildProcess
         stop();
     }
 
-    bool start(const char* const args[])
+    bool start(const char* const args[], char* const* const envp = nullptr)
     {
-        // FIXME
-       #ifdef DISTRHO_OS_WINDOWS
-        const CHAR* const envp = (
-            "MOD_DATA_DIR=" P "\\data\0"
-            "MOD_FACTORY_PEDALBOARDS_DIR=" P "\\pedalboards\0"
-            "LV2_PATH=" P "\\plugins\0"
-            "\0");
-       #else
-        const char* const envp[] = {
-            "MOD_DESKTOP=1",
-            "LANG=en_US.UTF-8",
-           #if defined(DISTRHO_OS_MAC)
-            "DYLD_LIBRARY_PATH=" P "/MacOS",
-            "JACK_DRIVER_DIR=" P "/MacOS/jack",
-            "MOD_DATA_DIR=/Users/falktx/Documents/MOD Desktop",
-            "MOD_FACTORY_PEDALBOARDS_DIR=" P "/Resources/pedalboards",
-            "LV2_PATH=" P "/LV2",
-           #else
-            "LD_LIBRARY_PATH=" P,
-            "JACK_DRIVER_DIR=" P "/jack",
-            "MOD_DATA_DIR=" P "/data",
-            "MOD_FACTORY_PEDALBOARDS_DIR=" P "/pedalboards",
-            "LV2_PATH=" P "/plugins",
-           #endif
-            nullptr
-        };
-       #endif
-
        #ifdef _WIN32
         std::string cmd;
 
@@ -93,6 +65,7 @@ class ChildProcess
             if (i != 0)
                 cmd += " ";
 
+            // TODO quoted
             cmd += args[i];
         }
 
@@ -118,7 +91,10 @@ class ChildProcess
         {
         // child process
         case 0:
-            execve(args[0], const_cast<char* const*>(args), const_cast<char* const*>(envp));
+            if (envp != nullptr)
+                execve(args[0], const_cast<char* const*>(args), envp);
+            else
+                execvp(args[0], const_cast<char* const*>(args));
 
             d_stderr2("exec failed: %d:%s", errno, std::strerror(errno));
             _exit(1);
@@ -134,29 +110,6 @@ class ChildProcess
        #endif
     }
 
-    bool start2(const char* const args[])
-    {
-        const pid_t ret = pid = vfork();
-
-        switch (ret)
-        {
-        // child process
-        case 0:
-            execvp(args[0], const_cast<char* const*>(args));
-
-            d_stderr2("exec failed: %d:%s", errno, std::strerror(errno));
-            _exit(1);
-            break;
-
-        // error
-        case -1:
-            d_stderr2("vfork() failed: %d:%s", errno, std::strerror(errno));
-            break;
-        }
-
-        return ret > 0;
-    }
-
     void stop(const uint32_t timeoutInMilliseconds = 2000)
     {
         const uint32_t timeout = d_gettime_ms() + timeoutInMilliseconds;
@@ -260,6 +213,57 @@ class ChildProcess
        #endif
     }
 
+    bool isRunning()
+    {
+       #ifdef _WIN32
+        if (process.hProcess == INVALID_HANDLE_VALUE)
+            return false;
+
+        if (WaitForSingleObject(process.hProcess, 0) == WAIT_FAILED)
+        {
+            const PROCESS_INFORMATION oprocess = process;
+            process = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 };
+            CloseHandle(oprocess.hThread);
+            CloseHandle(oprocess.hProcess);
+            return false;
+        }
+
+        return true;
+       #else
+        if (pid <= 0)
+            return false;
+        
+        const pid_t ret = ::waitpid(pid, nullptr, WNOHANG);
+
+        if (ret == -1 && errno == ECHILD)
+        {
+            pid = 0;
+            return false;
+        }
+
+        return true;
+       #endif
+    }
+
+   #ifndef _WIN32
+    void signal(const int sig)
+    {
+        if (pid > 0)
+            kill(pid, sig);
+    }
+   #endif
+
+    void terminate()
+    {
+       #ifdef _WIN32
+        if (process.hProcess != INVALID_HANDLE_VALUE)
+            TerminateProcess(process.hProcess, 15);
+       #else
+        if (pid > 0)
+            kill(pid, SIGTERM);
+       #endif
+    }
+
     DISTRHO_DECLARE_NON_COPYABLE(ChildProcess)
 };
 
diff --git a/src/plugin/DesktopAudioDriver.cpp b/src/plugin/DesktopAudioDriver.cpp
index 2b3b6d8..247751b 100644
--- a/src/plugin/DesktopAudioDriver.cpp
+++ b/src/plugin/DesktopAudioDriver.cpp
@@ -133,6 +133,13 @@ class DesktopAudioDriver : public JackAudioDriver
             if (! wait())
                 continue;
 
+            if (fShmData->magic == 7331)
+            {
+                fIsProcessing = false;
+                post();
+                return;
+            }
+
             CycleTakeBeginTime();
 
             if (Process() != 0)
@@ -157,11 +164,13 @@ class DesktopAudioDriver : public JackAudioDriver
           fIsRunning(false)
     {
         printf("%03d:%s\n", __LINE__, __FUNCTION__);
+        fflush(stdout);
     }
 
     ~DesktopAudioDriver() override
     {
         printf("%03d:%s\n", __LINE__, __FUNCTION__);
+        fflush(stdout);
     }
 
     int Open(jack_nframes_t buffersize,
@@ -177,6 +186,7 @@ class DesktopAudioDriver : public JackAudioDriver
              jack_nframes_t playback_latency) override
     {
         printf("%03d:%s\n", __LINE__, __FUNCTION__);
+        fflush(stdout);
         if (JackAudioDriver::Open(buffersize, samplerate, capturing, playing, chan_in, chan_out, monitor,
             capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) {
             return -1;
@@ -262,38 +272,14 @@ class DesktopAudioDriver : public JackAudioDriver
         }
        #endif
 
-        jack_port_id_t port_index;
-        JackPort* port;
-        if (fEngine->PortRegister(fClientControl.fRefNum, "system:midi_capture_1", JACK_DEFAULT_MIDI_TYPE,
-                                  CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0)
-        {
-            Close();
-            jack_error("Can't open default MOD Desktop driver 6");
-            return -1;
-        }
-        fCaptureMidiPort = port_index;
-        port = fGraphManager->GetPort(port_index);
-        port->SetAlias("MOD Desktop MIDI Capture");
-
-        if (fEngine->PortRegister(fClientControl.fRefNum, "system:midi_playback_1", JACK_DEFAULT_MIDI_TYPE,
-                                  PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0)
-        {
-        {
-            Close();
-            jack_error("Can't open default MOD Desktop driver 7");
-            return -1;
-        }
-        }
-        fPlaybackMidiPort = port_index;
-        port = fGraphManager->GetPort(port_index);
-        port->SetAlias("MOD Desktop MIDI Playback");
-
         return 0;
     }
 
     int Close() override
     {
         printf("%03d:%s\n", __LINE__, __FUNCTION__);
+        fflush(stdout);
+
         JackAudioDriver::Close();
 
        #ifdef __APPLE__
@@ -339,13 +325,60 @@ class DesktopAudioDriver : public JackAudioDriver
         return 0;
     }
 
-//         int Attach() override
-//         {
-//         }
+    int Attach() override
+    {
+        printf("%03d:%s | %u\n", __LINE__, __FUNCTION__, fShmData->magic);
+        fflush(stdout);
+
+        if (JackAudioDriver::Attach() != 0)
+            return -1;
+
+        jack_port_id_t port_index;
+        JackPort* port;
+        if (fEngine->PortRegister(fClientControl.fRefNum, "system:midi_capture_1", JACK_DEFAULT_MIDI_TYPE,
+                                  CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0)
+        {
+            Close();
+            jack_error("Can't open default MOD Desktop driver 6");
+            return -1;
+        }
+        fCaptureMidiPort = port_index;
+        port = fGraphManager->GetPort(port_index);
+        port->SetAlias("MOD Desktop MIDI Capture");
+
+        if (fEngine->PortRegister(fClientControl.fRefNum, "system:midi_playback_1", JACK_DEFAULT_MIDI_TYPE,
+                                  PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0)
+        {
+        {
+            Close();
+            jack_error("Can't open default MOD Desktop driver 7");
+            return -1;
+        }
+        }
+        fPlaybackMidiPort = port_index;
+        port = fGraphManager->GetPort(port_index);
+        port->SetAlias("MOD Desktop MIDI Playback");
+
+        return 0;
+    }
+
+    int Detach() override
+    {
+        printf("%03d:%s | %u\n", __LINE__, __FUNCTION__, fShmData->magic);
+        fflush(stdout);
+
+        if (JackAudioDriver::Detach() != 0)
+            return -1;
+
+        fEngine->PortUnRegister(fClientControl.fRefNum, fCaptureMidiPort);
+        fEngine->PortUnRegister(fClientControl.fRefNum, fPlaybackMidiPort);
+        return 0;
+    }
 
     int Start() override
     {
         printf("%03d:%s\n", __LINE__, __FUNCTION__);
+        fflush(stdout);
         if (JackAudioDriver::Start() != 0)
             return -1;
 
@@ -361,7 +394,9 @@ class DesktopAudioDriver : public JackAudioDriver
 
     int Stop() override
     {
-        printf("%03d:%s\n", __LINE__, __FUNCTION__);
+        printf("%03d:%s | %u\n", __LINE__, __FUNCTION__, fShmData->magic);
+        fflush(stdout);
+
         fIsProcessing = false;
 
         if (fIsRunning)
diff --git a/src/plugin/DesktopPlugin.cpp b/src/plugin/DesktopPlugin.cpp
index 5f82c50..bd09373 100644
--- a/src/plugin/DesktopPlugin.cpp
+++ b/src/plugin/DesktopPlugin.cpp
@@ -24,6 +24,12 @@ class DesktopPlugin : public Plugin
     uint32_t numFramesInShmBuffer = 0;
     uint32_t numFramesInTmpBuffer = 0;
 
+   #ifdef DISTRHO_OS_WINDOWS
+    const CHAR* envp;
+   #else
+    char** envp;
+   #endif
+
 public:
     DesktopPlugin()
         : Plugin(0, 0, 0)
@@ -31,6 +37,42 @@ class DesktopPlugin : public Plugin
         if (isDummyInstance())
             return;
 
+      #ifdef DISTRHO_OS_WINDOWS
+        envp = (
+            "MOD_DATA_DIR=" P "\\data\0"
+            "MOD_FACTORY_PEDALBOARDS_DIR=" P "\\pedalboards\0"
+            "LV2_PATH=" P "\\plugins\0"
+            "\0"
+        );
+      #else
+        uint envsize = 0;
+        while (environ[envsize] != nullptr)
+            ++envsize;
+
+        envp = new char*[envsize + 8];
+
+        for (uint i = 0; i < envsize; ++i)
+            envp[i] = strdup(environ[i]);
+
+        envp[envsize] = strdup("MOD_DESKTOP=1");
+        envp[envsize + 1] = strdup("LANG=en_US.UTF-8");
+       #ifdef DISTRHO_OS_MAC
+        envp[envsize + 2] = strdup("DYLD_LIBRARY_PATH=" P "/MacOS");
+        envp[envsize + 3] = strdup("JACK_DRIVER_DIR=" P "/MacOS/jack");
+        envp[envsize + 4] = strdup("MOD_DATA_DIR=/Users/falktx/Documents/MOD Desktop");
+        envp[envsize + 5] = strdup("MOD_FACTORY_PEDALBOARDS_DIR=" P "/Resources/pedalboards");
+        envp[envsize + 6] = strdup("LV2_PATH=" P "/LV2");
+        envp[envsize + 7] = nullptr;
+       #else
+        envp[envsize + 2] = strdup("LD_LIBRARY_PATH=" P);
+        envp[envsize + 3] = strdup("JACK_DRIVER_DIR=" P "/jack");
+        envp[envsize + 4] = strdup("MOD_DATA_DIR=" P "/data");
+        envp[envsize + 5] = strdup("MOD_FACTORY_PEDALBOARDS_DIR=" P "/pedalboards");
+        envp[envsize + 6] = strdup("LV2_PATH=" P "/plugins");
+        envp[envsize + 7] = nullptr;
+       #endif
+      #endif
+
         const String sampleRateStr(static_cast<int>(getSampleRate()));
         const char* const jackd_args[] = {
            #if defined(DISTRHO_OS_MAC)
@@ -63,24 +105,36 @@ class DesktopPlugin : public Plugin
             nullptr
         };
 
-        if (shm.init() && jackd.start(jackd_args))
+        if (shm.init() && jackd.start(jackd_args, envp))
         {
             processing = true;
             bufferSizeChanged(getBufferSize());
 
             d_msleep(500);
-            mod_ui.start(mod_ui_args);
+            mod_ui.start(mod_ui_args, envp);
         }
     }
 
     ~DesktopPlugin()
     {
-        mod_ui.stop();
+        if (processing && jackd.isRunning())
+            shm.stopWait();
+
         jackd.stop();
+        mod_ui.stop();
+
         shm.deinit();
 
         delete[] tmpBuffers[0];
         delete[] tmpBuffers[1];
+
+       #ifdef DISTRHO_OS_WINDOWS
+       #else
+        for (uint i = 0; envp[i] != nullptr; ++i)
+            std::free(envp[i]);
+
+        delete[] envp;
+       #endif
     }
 
 protected:
diff --git a/src/plugin/SharedMemory.hpp b/src/plugin/SharedMemory.hpp
index f3f2475..35da376 100644
--- a/src/plugin/SharedMemory.hpp
+++ b/src/plugin/SharedMemory.hpp
@@ -204,6 +204,16 @@ class SharedMemory
         std::memset(data->audio, 0, sizeof(float) * 128 * 2);
     }
 
+    void stopWait()
+    {
+        if (data == nullptr)
+            return;
+
+        data->magic = 7331;
+        post();
+        wait();
+    }
+
     bool process(float** output, const uint32_t offset)
     {
         // unlock RT waiter
diff --git a/src/plugin/WebView.mm b/src/plugin/WebView.mm
index 8e82e1e..f1b30be 100644
--- a/src/plugin/WebView.mm
+++ b/src/plugin/WebView.mm
@@ -19,7 +19,7 @@
                                    DISTRHO_UI_DEFAULT_WIDTH,
                                    DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset);
 
-    WKWebView* const webview = [[WKWebView alloc] initWithFrame: rect];
+    WKWebView* const webview = [[[WKWebView alloc] initWithFrame: rect] retain];
 
     [[[webview configuration] preferences] setValue: @(true) forKey: @"developerExtrasEnabled"];
 
@@ -29,6 +29,14 @@
     return webview;
 }
 
+void destroyWebView(void* const webviewptr)
+{
+    WKWebView* const webview = static_cast<WKWebView*>(webviewptr);
+
+    [webview setHidden:YES];
+    [[webview dealloc] release];
+}
+
 void reloadWebView(void* const webviewptr)
 {
     WKWebView* const webview = static_cast<WKWebView*>(webviewptr);
diff --git a/src/plugin/WebViewX11.cpp b/src/plugin/WebViewX11.cpp
index c05fa49..a1e2f9d 100644
--- a/src/plugin/WebViewX11.cpp
+++ b/src/plugin/WebViewX11.cpp
@@ -26,16 +26,7 @@ struct WebViewIPC {
 
 void* addWebView(uintptr_t viewptr)
 {
-    ::Display* const display = XOpenDisplay(nullptr);
-    DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, nullptr);
-
-    WebViewIPC* const ipc = new WebViewIPC();
-    ipc->display = display;
-    ipc->childWindow = 0;
-    ipc->ourWindow = viewptr;
-
     char webviewTool[PATH_MAX] = {};
-
     {
         Dl_info info = {};
         dladdr((void*)addWebView, &info);
@@ -55,16 +46,25 @@ void* addWebView(uintptr_t viewptr)
         {
             std::strncpy(webviewTool, info.dli_fname, PATH_MAX - 1);
         }
+
+        char* const lastsep = std::strrchr(webviewTool, '/');
+        DISTRHO_SAFE_ASSERT_RETURN(lastsep != nullptr, nullptr);
+
+        *lastsep = '\0';
+        std::strncat(webviewTool, "/MOD-Desktop-WebView", PATH_MAX - 1);
     }
 
-    if (char* const c = std::strrchr(webviewTool, '/'))
-        *c = 0;
+    ::Display* const display = XOpenDisplay(nullptr);
+    DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, nullptr);
 
-    std::strncat(webviewTool, "/MOD-Desktop-WebView", PATH_MAX - 1);
+    WebViewIPC* const ipc = new WebViewIPC();
+    ipc->display = display;
+    ipc->childWindow = 0;
+    ipc->ourWindow = viewptr;
 
     const String viewStr(viewptr);
     const char* const args[] = { webviewTool, "-platform", "xcb", "-xembed", viewStr.buffer(), nullptr };
-    ipc->p.start2(args);
+    ipc->p.start(args);
 
     return ipc;
 }
@@ -79,6 +79,9 @@ void destroyWebView(void* const webviewptr)
 
 void reloadWebView(void* const webviewptr)
 {
+    WebViewIPC* const ipc = static_cast<WebViewIPC*>(webviewptr);
+
+    ipc->p.signal(SIGUSR1);
 }
 
 void resizeWebView(void* const webviewptr, const uint offset, const uint width, const uint height)