|
|
|
@@ -98,7 +98,12 @@ public: |
|
|
|
testResultsBox.setFont ({ Font::getDefaultMonospacedFontName(), 12.0f, Font::plain });
|
|
|
|
|
|
|
|
logMessage (String ("This demo uses the ChildProcessCoordinator and ChildProcessWorker classes to launch and communicate "
|
|
|
|
"with a child process, sending messages in the form of serialised ValueTree objects.") + newLine);
|
|
|
|
"with a child process, sending messages in the form of serialised ValueTree objects.") + newLine
|
|
|
|
+ String ("In this demo, the child process will automatically quit if it fails to receive a ping message at least every ")
|
|
|
|
+ String (timeoutSeconds)
|
|
|
|
+ String (" seconds. To keep the process alive, press the \"")
|
|
|
|
+ pingButton.getButtonText()
|
|
|
|
+ String ("\" button periodically.") + newLine);
|
|
|
|
|
|
|
|
setSize (500, 500);
|
|
|
|
}
|
|
|
|
@@ -136,10 +141,14 @@ public: |
|
|
|
{
|
|
|
|
if (coordinatorProcess.get() == nullptr)
|
|
|
|
{
|
|
|
|
coordinatorProcess.reset (new DemoCoordinatorProcess (*this));
|
|
|
|
coordinatorProcess = std::make_unique<DemoCoordinatorProcess> (*this);
|
|
|
|
|
|
|
|
if (coordinatorProcess->launchWorkerProcess (File::getSpecialLocation (File::currentExecutableFile), demoCommandLineUID))
|
|
|
|
if (coordinatorProcess->launchWorkerProcess (File::getSpecialLocation (File::currentExecutableFile),
|
|
|
|
demoCommandLineUID,
|
|
|
|
timeoutMillis))
|
|
|
|
{
|
|
|
|
logMessage ("Child process started");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -166,11 +175,14 @@ public: |
|
|
|
// This class is used by the main process, acting as the coordinator and receiving messages
|
|
|
|
// from the worker process.
|
|
|
|
class DemoCoordinatorProcess : public ChildProcessCoordinator,
|
|
|
|
private DeletedAtShutdown
|
|
|
|
private DeletedAtShutdown,
|
|
|
|
private AsyncUpdater
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DemoCoordinatorProcess (ChildProcessDemo& d) : demo (d) {}
|
|
|
|
|
|
|
|
~DemoCoordinatorProcess() override { cancelPendingUpdate(); }
|
|
|
|
|
|
|
|
// This gets called when a message arrives from the worker process..
|
|
|
|
void handleMessageFromWorker (const MemoryBlock& mb) override
|
|
|
|
{
|
|
|
|
@@ -183,6 +195,11 @@ public: |
|
|
|
void handleConnectionLost() override
|
|
|
|
{
|
|
|
|
demo.logMessage ("Connection lost to child process!");
|
|
|
|
triggerAsyncUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleAsyncUpdate() override
|
|
|
|
{
|
|
|
|
demo.killChildProcess();
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -203,7 +220,11 @@ public: |
|
|
|
//==============================================================================
|
|
|
|
std::unique_ptr<DemoCoordinatorProcess> coordinatorProcess;
|
|
|
|
|
|
|
|
static constexpr auto timeoutSeconds = 10;
|
|
|
|
static constexpr auto timeoutMillis = timeoutSeconds * 1000;
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
TextButton launchButton { "Launch Child Process" };
|
|
|
|
TextButton pingButton { "Send Ping" };
|
|
|
|
TextButton killButton { "Kill Child Process" };
|
|
|
|
@@ -268,8 +289,8 @@ public: |
|
|
|
}
|
|
|
|
|
|
|
|
/* If no pings are received from the coordinator process for a number of seconds, then this will get invoked.
|
|
|
|
Typically you'll want to use this as a signal to kill the process as quickly as possible, as you
|
|
|
|
don't want to leave it hanging around as a zombie..
|
|
|
|
Typically, you'll want to use this as a signal to kill the process as quickly as possible, as you
|
|
|
|
don't want to leave it hanging around as a zombie.
|
|
|
|
*/
|
|
|
|
void handleConnectionLost() override
|
|
|
|
{
|
|
|
|
@@ -280,13 +301,13 @@ public: |
|
|
|
//==============================================================================
|
|
|
|
/* The JUCEApplication::initialise method calls this function to allow the
|
|
|
|
child process to launch when the command line parameters indicate that we're
|
|
|
|
being asked to run as a child process..
|
|
|
|
being asked to run as a child process.
|
|
|
|
*/
|
|
|
|
bool invokeChildProcessDemo (const String& commandLine)
|
|
|
|
{
|
|
|
|
std::unique_ptr<DemoWorkerProcess> worker (new DemoWorkerProcess());
|
|
|
|
auto worker = std::make_unique<DemoWorkerProcess>();
|
|
|
|
|
|
|
|
if (worker->initialiseFromCommandLine (commandLine, demoCommandLineUID))
|
|
|
|
if (worker->initialiseFromCommandLine (commandLine, demoCommandLineUID, ChildProcessDemo::timeoutMillis))
|
|
|
|
{
|
|
|
|
worker.release(); // allow the worker object to stay alive - it'll handle its own deletion.
|
|
|
|
return true;
|
|
|
|
@@ -316,7 +337,7 @@ bool invokeChildProcessDemo (const String& commandLine) |
|
|
|
if (invokeChildProcessDemo (commandLine))
|
|
|
|
return;
|
|
|
|
|
|
|
|
mainWindow.reset (new MainWindow ("ChildProcessDemo", new ChildProcessDemo()));
|
|
|
|
mainWindow = std::make_unique<MainWindow> ("ChildProcessDemo", std::make_unique<ChildProcessDemo>());
|
|
|
|
}
|
|
|
|
|
|
|
|
void shutdown() override { mainWindow = nullptr; }
|
|
|
|
@@ -325,13 +346,14 @@ bool invokeChildProcessDemo (const String& commandLine) |
|
|
|
class MainWindow : public DocumentWindow
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MainWindow (const String& name, Component* c) : DocumentWindow (name,
|
|
|
|
Desktop::getInstance().getDefaultLookAndFeel()
|
|
|
|
.findColour (ResizableWindow::backgroundColourId),
|
|
|
|
DocumentWindow::allButtons)
|
|
|
|
MainWindow (const String& name, std::unique_ptr<Component> c)
|
|
|
|
: DocumentWindow (name,
|
|
|
|
Desktop::getInstance().getDefaultLookAndFeel()
|
|
|
|
.findColour (ResizableWindow::backgroundColourId),
|
|
|
|
DocumentWindow::allButtons)
|
|
|
|
{
|
|
|
|
setUsingNativeTitleBar (true);
|
|
|
|
setContentOwned (c, true);
|
|
|
|
setContentOwned (c.release(), true);
|
|
|
|
|
|
|
|
centreWithSize (getWidth(), getHeight());
|
|
|
|
|
|
|
|
|