| @@ -97,7 +97,7 @@ public: | |||
| testResultsBox.setMultiLine (true); | |||
| testResultsBox.setFont ({ Font::getDefaultMonospacedFontName(), 12.0f, Font::plain }); | |||
| logMessage (String ("This demo uses the ChildProcessMaster and ChildProcessSlave classes to launch and communicate " | |||
| 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); | |||
| setSize (500, 500); | |||
| @@ -105,7 +105,7 @@ public: | |||
| ~ChildProcessDemo() override | |||
| { | |||
| masterProcess.reset(); | |||
| coordinatorProcess.reset(); | |||
| } | |||
| void paint (Graphics& g) override | |||
| @@ -134,11 +134,11 @@ public: | |||
| // invoked by the 'launch' button. | |||
| void launchChildProcess() | |||
| { | |||
| if (masterProcess.get() == nullptr) | |||
| if (coordinatorProcess.get() == nullptr) | |||
| { | |||
| masterProcess.reset (new DemoMasterProcess (*this)); | |||
| coordinatorProcess.reset (new DemoCoordinatorProcess (*this)); | |||
| if (masterProcess->launchSlaveProcess (File::getSpecialLocation (File::currentExecutableFile), demoCommandLineUID)) | |||
| if (coordinatorProcess->launchWorkerProcess (File::getSpecialLocation (File::currentExecutableFile), demoCommandLineUID)) | |||
| logMessage ("Child process started"); | |||
| } | |||
| } | |||
| @@ -146,8 +146,8 @@ public: | |||
| // invoked by the 'ping' button. | |||
| void pingChildProcess() | |||
| { | |||
| if (masterProcess.get() != nullptr) | |||
| masterProcess->sendPingMessageToSlave(); | |||
| if (coordinatorProcess.get() != nullptr) | |||
| coordinatorProcess->sendPingMessageToWorker(); | |||
| else | |||
| logMessage ("Child process is not running!"); | |||
| } | |||
| @@ -155,45 +155,45 @@ public: | |||
| // invoked by the 'kill' button. | |||
| void killChildProcess() | |||
| { | |||
| if (masterProcess.get() != nullptr) | |||
| if (coordinatorProcess.get() != nullptr) | |||
| { | |||
| masterProcess.reset(); | |||
| coordinatorProcess.reset(); | |||
| logMessage ("Child process killed"); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| // This class is used by the main process, acting as the master and receiving messages | |||
| // from the slave process. | |||
| class DemoMasterProcess : public ChildProcessMaster, | |||
| private DeletedAtShutdown | |||
| // 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 | |||
| { | |||
| public: | |||
| DemoMasterProcess (ChildProcessDemo& d) : demo (d) {} | |||
| DemoCoordinatorProcess (ChildProcessDemo& d) : demo (d) {} | |||
| // This gets called when a message arrives from the slave process.. | |||
| void handleMessageFromSlave (const MemoryBlock& mb) override | |||
| // This gets called when a message arrives from the worker process.. | |||
| void handleMessageFromWorker (const MemoryBlock& mb) override | |||
| { | |||
| auto incomingMessage = memoryBlockToValueTree (mb); | |||
| demo.logMessage ("Received: " + valueTreeToString (incomingMessage)); | |||
| } | |||
| // This gets called if the slave process dies. | |||
| // This gets called if the worker process dies. | |||
| void handleConnectionLost() override | |||
| { | |||
| demo.logMessage ("Connection lost to child process!"); | |||
| demo.killChildProcess(); | |||
| } | |||
| void sendPingMessageToSlave() | |||
| void sendPingMessageToWorker() | |||
| { | |||
| ValueTree message ("MESSAGE"); | |||
| message.setProperty ("count", count++, nullptr); | |||
| demo.logMessage ("Sending: " + valueTreeToString (message)); | |||
| sendMessageToSlave (valueTreeToMemoryBlock (message)); | |||
| sendMessageToWorker (valueTreeToMemoryBlock (message)); | |||
| } | |||
| ChildProcessDemo& demo; | |||
| @@ -201,7 +201,7 @@ public: | |||
| }; | |||
| //============================================================================== | |||
| std::unique_ptr<DemoMasterProcess> masterProcess; | |||
| std::unique_ptr<DemoCoordinatorProcess> coordinatorProcess; | |||
| private: | |||
| TextButton launchButton { "Launch Child Process" }; | |||
| @@ -234,15 +234,15 @@ private: | |||
| //============================================================================== | |||
| /* This class gets instantiated in the child process, and receives messages from | |||
| the master process. | |||
| the coordinator process. | |||
| */ | |||
| class DemoSlaveProcess : public ChildProcessSlave, | |||
| private DeletedAtShutdown | |||
| class DemoWorkerProcess : public ChildProcessWorker, | |||
| private DeletedAtShutdown | |||
| { | |||
| public: | |||
| DemoSlaveProcess() {} | |||
| DemoWorkerProcess() = default; | |||
| void handleMessageFromMaster (const MemoryBlock& mb) override | |||
| void handleMessageFromCoordinator (const MemoryBlock& mb) override | |||
| { | |||
| ValueTree incomingMessage (memoryBlockToValueTree (mb)); | |||
| @@ -256,7 +256,7 @@ public: | |||
| ValueTree reply ("REPLY"); | |||
| reply.setProperty ("countPlusOne", static_cast<int> (incomingMessage["count"]) + 1, nullptr); | |||
| sendMessageToMaster (valueTreeToMemoryBlock (reply)); | |||
| sendMessageToCoordinator (valueTreeToMemoryBlock (reply)); | |||
| } | |||
| void handleConnectionMade() override | |||
| @@ -264,10 +264,10 @@ public: | |||
| // This method is called when the connection is established, and in response, we'll just | |||
| // send off a message to say hello. | |||
| ValueTree reply ("HelloWorld"); | |||
| sendMessageToMaster (valueTreeToMemoryBlock (reply)); | |||
| sendMessageToCoordinator (valueTreeToMemoryBlock (reply)); | |||
| } | |||
| /* If no pings are received from the master process for a number of seconds, then this will get invoked. | |||
| /* 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.. | |||
| */ | |||
| @@ -284,11 +284,11 @@ public: | |||
| */ | |||
| bool invokeChildProcessDemo (const String& commandLine) | |||
| { | |||
| std::unique_ptr<DemoSlaveProcess> slave (new DemoSlaveProcess()); | |||
| std::unique_ptr<DemoWorkerProcess> worker (new DemoWorkerProcess()); | |||
| if (slave->initialiseFromCommandLine (commandLine, demoCommandLineUID)) | |||
| if (worker->initialiseFromCommandLine (commandLine, demoCommandLineUID)) | |||
| { | |||
| slave.release(); // allow the slave object to stay alive - it'll handle its own deletion. | |||
| worker.release(); // allow the worker object to stay alive - it'll handle its own deletion. | |||
| return true; | |||
| } | |||
| @@ -31,7 +31,7 @@ | |||
| #error "If you're building the audio plugin host, you probably want to enable VST and/or AU support" | |||
| #endif | |||
| class PluginScannerSubprocess : private ChildProcessSlave, | |||
| class PluginScannerSubprocess : private ChildProcessWorker, | |||
| private AsyncUpdater | |||
| { | |||
| public: | |||
| @@ -40,10 +40,10 @@ public: | |||
| formatManager.addDefaultFormats(); | |||
| } | |||
| using ChildProcessSlave::initialiseFromCommandLine; | |||
| using ChildProcessWorker::initialiseFromCommandLine; | |||
| private: | |||
| void handleMessageFromMaster (const MemoryBlock& mb) override | |||
| void handleMessageFromCoordinator (const MemoryBlock& mb) override | |||
| { | |||
| { | |||
| const std::lock_guard<std::mutex> lock (mutex); | |||
| @@ -94,7 +94,7 @@ private: | |||
| xml.addChildElement (desc->createXml().release()); | |||
| const auto str = xml.toString(); | |||
| sendMessageToMaster ({ str.toRawUTF8(), str.getNumBytesAsUTF8() }); | |||
| sendMessageToCoordinator ({ str.toRawUTF8(), str.getNumBytesAsUTF8() }); | |||
| } | |||
| } | |||
| @@ -71,7 +71,7 @@ public: | |||
| stream.writeString (format.getName()); | |||
| stream.writeString (fileOrIdentifier); | |||
| if (superprocess->sendMessageToSlave (block)) | |||
| if (superprocess->sendMessageToWorker (block)) | |||
| { | |||
| std::unique_lock<std::mutex> lock (mutex); | |||
| gotResponse = false; | |||
| @@ -123,17 +123,19 @@ public: | |||
| } | |||
| private: | |||
| class Superprocess : public ChildProcessMaster | |||
| class Superprocess : private ChildProcessCoordinator | |||
| { | |||
| public: | |||
| explicit Superprocess (CustomPluginScanner& o) | |||
| : owner (o) | |||
| { | |||
| launchSlaveProcess (File::getSpecialLocation (File::currentExecutableFile), processUID, 0, 0); | |||
| launchWorkerProcess (File::getSpecialLocation (File::currentExecutableFile), processUID, 0, 0); | |||
| } | |||
| using ChildProcessCoordinator::sendMessageToWorker; | |||
| private: | |||
| void handleMessageFromSlave (const MemoryBlock& mb) override | |||
| void handleMessageFromWorker (const MemoryBlock& mb) override | |||
| { | |||
| auto xml = parseXML (mb.toString()); | |||
| @@ -37,7 +37,7 @@ add_library( ${BINARY_NAME} | |||
| "../../../Source/Demos.h" | |||
| "../../../Source/Main.cpp" | |||
| "../../../Source/MasterComponent.h" | |||
| "../../../Source/SlaveComponent.h" | |||
| "../../../Source/ClientComponent.h" | |||
| "../../../Source/SharedCanvas.h" | |||
| "../../../Source/juce_icon.png" | |||
| "../../../../../modules/juce_audio_basics/audio_play_head/juce_AudioPlayHead.h" | |||
| @@ -1623,7 +1623,7 @@ add_library( ${BINARY_NAME} | |||
| set_source_files_properties("../../../Source/Demos.h" PROPERTIES HEADER_FILE_ONLY TRUE) | |||
| set_source_files_properties("../../../Source/MasterComponent.h" PROPERTIES HEADER_FILE_ONLY TRUE) | |||
| set_source_files_properties("../../../Source/SlaveComponent.h" PROPERTIES HEADER_FILE_ONLY TRUE) | |||
| set_source_files_properties("../../../Source/ClientComponent.h" PROPERTIES HEADER_FILE_ONLY TRUE) | |||
| set_source_files_properties("../../../Source/SharedCanvas.h" PROPERTIES HEADER_FILE_ONLY TRUE) | |||
| set_source_files_properties("../../../Source/juce_icon.png" PROPERTIES HEADER_FILE_ONLY TRUE) | |||
| set_source_files_properties("../../../../../modules/juce_audio_basics/audio_play_head/juce_AudioPlayHead.h" PROPERTIES HEADER_FILE_ONLY TRUE) | |||
| @@ -67,7 +67,6 @@ | |||
| 7BE6330821794919A88ED8ED /* include_juce_gui_extra.mm */ /* include_juce_gui_extra.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_gui_extra.mm; path = ../../JuceLibraryCode/include_juce_gui_extra.mm; sourceTree = SOURCE_ROOT; }; | |||
| 84B287BB2AD252B7D69AC47E /* include_juce_gui_basics.mm */ /* include_juce_gui_basics.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_gui_basics.mm; path = ../../JuceLibraryCode/include_juce_gui_basics.mm; sourceTree = SOURCE_ROOT; }; | |||
| 89583CD42AD218E9753DF11C /* juce_audio_devices */ /* juce_audio_devices */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_devices; path = ../../../../modules/juce_audio_devices; sourceTree = SOURCE_ROOT; }; | |||
| 8E2F72AFA0CDA64F0C07F105 /* SlaveComponent.h */ /* SlaveComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SlaveComponent.h; path = ../../Source/SlaveComponent.h; sourceTree = SOURCE_ROOT; }; | |||
| 8EACAADD3A23DED3E252C92F /* juce_core */ /* juce_core */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_core; path = ../../../../modules/juce_core; sourceTree = SOURCE_ROOT; }; | |||
| 92800676AF753D1A60108F11 /* BinaryData.h */ /* BinaryData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BinaryData.h; path = ../../JuceLibraryCode/BinaryData.h; sourceTree = SOURCE_ROOT; }; | |||
| 935CA85EF98714D3A17AE737 /* QuartzCore.framework */ /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; | |||
| @@ -83,6 +82,7 @@ | |||
| AFF729977947528F3E4AAA96 /* include_juce_cryptography.mm */ /* include_juce_cryptography.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_cryptography.mm; path = ../../JuceLibraryCode/include_juce_cryptography.mm; sourceTree = SOURCE_ROOT; }; | |||
| B5433B00F012AD87AADBFCD6 /* juce_cryptography */ /* juce_cryptography */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_cryptography; path = ../../../../modules/juce_cryptography; sourceTree = SOURCE_ROOT; }; | |||
| B76F10A7778664E164A01934 /* juce_audio_basics */ /* juce_audio_basics */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_basics; path = ../../../../modules/juce_audio_basics; sourceTree = SOURCE_ROOT; }; | |||
| B9B80E3572715F63FFC3678B /* ClientComponent.h */ /* ClientComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ClientComponent.h; path = ../../Source/ClientComponent.h; sourceTree = SOURCE_ROOT; }; | |||
| BA2E40409255F1B078406221 /* juce_data_structures */ /* juce_data_structures */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_data_structures; path = ../../../../modules/juce_data_structures; sourceTree = SOURCE_ROOT; }; | |||
| C6E2284D86D93F1D9D5C7666 /* include_juce_audio_formats.mm */ /* include_juce_audio_formats.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_audio_formats.mm; path = ../../JuceLibraryCode/include_juce_audio_formats.mm; sourceTree = SOURCE_ROOT; }; | |||
| C78806A6727F44EACFDED4A5 /* Cocoa.framework */ /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; | |||
| @@ -138,7 +138,7 @@ | |||
| 4FF648D72D6F1A78956CDA1B, | |||
| 77C0AC21C1028911123844FC, | |||
| 9982F39121710EFFD5FEEAEF, | |||
| 8E2F72AFA0CDA64F0C07F105, | |||
| B9B80E3572715F63FFC3678B, | |||
| 25DEDA8C9F94A6C8DFC8E53E, | |||
| ); | |||
| name = Source; | |||
| @@ -2174,7 +2174,7 @@ | |||
| <ItemGroup> | |||
| <ClInclude Include="..\..\Source\Demos.h"/> | |||
| <ClInclude Include="..\..\Source\MasterComponent.h"/> | |||
| <ClInclude Include="..\..\Source\SlaveComponent.h"/> | |||
| <ClInclude Include="..\..\Source\ClientComponent.h"/> | |||
| <ClInclude Include="..\..\Source\SharedCanvas.h"/> | |||
| <ClInclude Include="..\..\..\..\modules\juce_audio_basics\audio_play_head\juce_AudioPlayHead.h"/> | |||
| <ClInclude Include="..\..\..\..\modules\juce_audio_basics\buffers\juce_AudioChannelSet.h"/> | |||
| @@ -2667,7 +2667,7 @@ | |||
| <ClInclude Include="..\..\Source\MasterComponent.h"> | |||
| <Filter>NetworkGraphicsDemo\Source</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\Source\SlaveComponent.h"> | |||
| <ClInclude Include="..\..\Source\ClientComponent.h"> | |||
| <Filter>NetworkGraphicsDemo\Source</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="..\..\Source\SharedCanvas.h"> | |||
| @@ -71,7 +71,6 @@ | |||
| 7BE6330821794919A88ED8ED /* include_juce_gui_extra.mm */ /* include_juce_gui_extra.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_gui_extra.mm; path = ../../JuceLibraryCode/include_juce_gui_extra.mm; sourceTree = SOURCE_ROOT; }; | |||
| 84B287BB2AD252B7D69AC47E /* include_juce_gui_basics.mm */ /* include_juce_gui_basics.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_gui_basics.mm; path = ../../JuceLibraryCode/include_juce_gui_basics.mm; sourceTree = SOURCE_ROOT; }; | |||
| 89583CD42AD218E9753DF11C /* juce_audio_devices */ /* juce_audio_devices */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_devices; path = ../../../../modules/juce_audio_devices; sourceTree = SOURCE_ROOT; }; | |||
| 8E2F72AFA0CDA64F0C07F105 /* SlaveComponent.h */ /* SlaveComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SlaveComponent.h; path = ../../Source/SlaveComponent.h; sourceTree = SOURCE_ROOT; }; | |||
| 8EACAADD3A23DED3E252C92F /* juce_core */ /* juce_core */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_core; path = ../../../../modules/juce_core; sourceTree = SOURCE_ROOT; }; | |||
| 9193D2A3C463BEAA07FD424D /* CoreText.framework */ /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; | |||
| 92800676AF753D1A60108F11 /* BinaryData.h */ /* BinaryData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BinaryData.h; path = ../../JuceLibraryCode/BinaryData.h; sourceTree = SOURCE_ROOT; }; | |||
| @@ -88,6 +87,7 @@ | |||
| AFF729977947528F3E4AAA96 /* include_juce_cryptography.mm */ /* include_juce_cryptography.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_cryptography.mm; path = ../../JuceLibraryCode/include_juce_cryptography.mm; sourceTree = SOURCE_ROOT; }; | |||
| B5433B00F012AD87AADBFCD6 /* juce_cryptography */ /* juce_cryptography */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_cryptography; path = ../../../../modules/juce_cryptography; sourceTree = SOURCE_ROOT; }; | |||
| B76F10A7778664E164A01934 /* juce_audio_basics */ /* juce_audio_basics */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_basics; path = ../../../../modules/juce_audio_basics; sourceTree = SOURCE_ROOT; }; | |||
| B9B80E3572715F63FFC3678B /* ClientComponent.h */ /* ClientComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ClientComponent.h; path = ../../Source/ClientComponent.h; sourceTree = SOURCE_ROOT; }; | |||
| BA2E40409255F1B078406221 /* juce_data_structures */ /* juce_data_structures */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_data_structures; path = ../../../../modules/juce_data_structures; sourceTree = SOURCE_ROOT; }; | |||
| C6E2284D86D93F1D9D5C7666 /* include_juce_audio_formats.mm */ /* include_juce_audio_formats.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_audio_formats.mm; path = ../../JuceLibraryCode/include_juce_audio_formats.mm; sourceTree = SOURCE_ROOT; }; | |||
| C821C5805007FFDC2636BBE6 /* OpenGLES.framework */ /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; | |||
| @@ -147,7 +147,7 @@ | |||
| 4FF648D72D6F1A78956CDA1B, | |||
| 77C0AC21C1028911123844FC, | |||
| 9982F39121710EFFD5FEEAEF, | |||
| 8E2F72AFA0CDA64F0C07F105, | |||
| B9B80E3572715F63FFC3678B, | |||
| 25DEDA8C9F94A6C8DFC8E53E, | |||
| ); | |||
| name = Source; | |||
| @@ -10,8 +10,8 @@ | |||
| <FILE id="xdUc9q" name="Main.cpp" compile="1" resource="0" file="Source/Main.cpp"/> | |||
| <FILE id="Vjuvqu" name="MasterComponent.h" compile="0" resource="0" | |||
| file="Source/MasterComponent.h"/> | |||
| <FILE id="KbZNxO" name="SlaveComponent.h" compile="0" resource="0" | |||
| file="Source/SlaveComponent.h"/> | |||
| <FILE id="KbZNxO" name="ClientComponent.h" compile="0" resource="0" | |||
| file="Source/ClientComponent.h"/> | |||
| <FILE id="F7A4kl" name="SharedCanvas.h" compile="0" resource="0" file="Source/SharedCanvas.h"/> | |||
| </GROUP> | |||
| <FILE id="Ww6bQw" name="juce_icon.png" compile="0" resource="1" file="Source/juce_icon.png"/> | |||
| @@ -25,19 +25,19 @@ | |||
| /** | |||
| This component runs in a slave process, draws the part of the canvas that this | |||
| This component runs in a client process, draws the part of the canvas that this | |||
| particular client covers, and updates itself when messages arrive from the master | |||
| containing new canvas states. | |||
| */ | |||
| class SlaveCanvasComponent : public Component, | |||
| private OSCSender, | |||
| private OSCReceiver, | |||
| private OSCReceiver::Listener<OSCReceiver::RealtimeCallback>, | |||
| private AsyncUpdater, | |||
| private Timer | |||
| class ClientCanvasComponent : public Component, | |||
| private OSCSender, | |||
| private OSCReceiver, | |||
| private OSCReceiver::Listener<OSCReceiver::RealtimeCallback>, | |||
| private AsyncUpdater, | |||
| private Timer | |||
| { | |||
| public: | |||
| SlaveCanvasComponent (PropertiesFile& p, int windowIndex) : properties (p) | |||
| ClientCanvasComponent (PropertiesFile& p, int windowIndex) : properties (p) | |||
| { | |||
| { | |||
| String uuidPropName ("UUID" + String (windowIndex)); | |||
| @@ -65,7 +65,7 @@ public: | |||
| startTimer (2000); | |||
| } | |||
| ~SlaveCanvasComponent() override | |||
| ~ClientCanvasComponent() override | |||
| { | |||
| OSCReceiver::removeListener (this); | |||
| } | |||
| @@ -220,5 +220,5 @@ private: | |||
| CriticalSection canvasLock; | |||
| BlockPacketiser packetiser; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SlaveCanvasComponent) | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ClientCanvasComponent) | |||
| }; | |||
| @@ -41,7 +41,7 @@ namespace | |||
| } | |||
| #include "SharedCanvas.h" | |||
| #include "SlaveComponent.h" | |||
| #include "ClientComponent.h" | |||
| #include "Demos.h" | |||
| #include "MasterComponent.h" | |||
| @@ -107,7 +107,7 @@ public: | |||
| : DocumentWindow ("JUCE Networked Graphics Demo", Colours::black, DocumentWindow::allButtons) | |||
| { | |||
| setUsingNativeTitleBar (true); | |||
| setContentOwned (new SlaveCanvasComponent (props, windowIndex), true); | |||
| setContentOwned (new ClientCanvasComponent (props, windowIndex), true); | |||
| setBounds (500, 100, getWidth(), getHeight()); | |||
| setResizable (true, false); | |||
| setVisible (true); | |||
| @@ -23,7 +23,7 @@ | |||
| namespace juce | |||
| { | |||
| enum { magicMastSlaveConnectionHeader = 0x712baf04 }; | |||
| enum { magicCoordWorkerConnectionHeader = 0x712baf04 }; | |||
| static const char* startMessage = "__ipc_st"; | |||
| static const char* killMessage = "__ipc_k_"; | |||
| @@ -82,11 +82,11 @@ private: | |||
| }; | |||
| //============================================================================== | |||
| struct ChildProcessMaster::Connection : public InterprocessConnection, | |||
| private ChildProcessPingThread | |||
| struct ChildProcessCoordinator::Connection : public InterprocessConnection, | |||
| private ChildProcessPingThread | |||
| { | |||
| Connection (ChildProcessMaster& m, const String& pipeName, int timeout) | |||
| : InterprocessConnection (false, magicMastSlaveConnectionHeader), | |||
| Connection (ChildProcessCoordinator& m, const String& pipeName, int timeout) | |||
| : InterprocessConnection (false, magicCoordWorkerConnectionHeader), | |||
| ChildProcessPingThread (timeout), | |||
| owner (m) | |||
| { | |||
| @@ -103,7 +103,7 @@ private: | |||
| void connectionMade() override {} | |||
| void connectionLost() override { owner.handleConnectionLost(); } | |||
| bool sendPingMessage (const MemoryBlock& m) override { return owner.sendMessageToSlave (m); } | |||
| bool sendPingMessage (const MemoryBlock& m) override { return owner.sendMessageToWorker (m); } | |||
| void pingFailed() override { connectionLost(); } | |||
| void messageReceived (const MemoryBlock& m) override | |||
| @@ -111,25 +111,34 @@ private: | |||
| pingReceived(); | |||
| if (m.getSize() != specialMessageSize || ! isMessageType (m, pingMessage)) | |||
| owner.handleMessageFromSlave (m); | |||
| owner.handleMessageFromWorker (m); | |||
| } | |||
| ChildProcessMaster& owner; | |||
| ChildProcessCoordinator& owner; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Connection) | |||
| }; | |||
| //============================================================================== | |||
| ChildProcessMaster::ChildProcessMaster() {} | |||
| ChildProcessCoordinator::ChildProcessCoordinator() = default; | |||
| ChildProcessMaster::~ChildProcessMaster() | |||
| ChildProcessCoordinator::~ChildProcessCoordinator() | |||
| { | |||
| killSlaveProcess(); | |||
| killWorkerProcess(); | |||
| } | |||
| void ChildProcessMaster::handleConnectionLost() {} | |||
| void ChildProcessCoordinator::handleConnectionLost() {} | |||
| void ChildProcessCoordinator::handleMessageFromWorker (const MemoryBlock& mb) | |||
| { | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") | |||
| JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996) | |||
| handleMessageFromSlave (mb); | |||
| JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||
| JUCE_END_IGNORE_WARNINGS_MSVC | |||
| } | |||
| bool ChildProcessMaster::sendMessageToSlave (const MemoryBlock& mb) | |||
| bool ChildProcessCoordinator::sendMessageToWorker (const MemoryBlock& mb) | |||
| { | |||
| if (connection != nullptr) | |||
| return connection->sendMessage (mb); | |||
| @@ -138,10 +147,10 @@ bool ChildProcessMaster::sendMessageToSlave (const MemoryBlock& mb) | |||
| return false; | |||
| } | |||
| bool ChildProcessMaster::launchSlaveProcess (const File& executable, const String& commandLineUniqueID, | |||
| int timeoutMs, int streamFlags) | |||
| bool ChildProcessCoordinator::launchWorkerProcess (const File& executable, const String& commandLineUniqueID, | |||
| int timeoutMs, int streamFlags) | |||
| { | |||
| killSlaveProcess(); | |||
| killWorkerProcess(); | |||
| auto pipeName = "p" + String::toHexString (Random().nextInt64()); | |||
| @@ -157,7 +166,7 @@ bool ChildProcessMaster::launchSlaveProcess (const File& executable, const Strin | |||
| if (connection->isConnected()) | |||
| { | |||
| sendMessageToSlave ({ startMessage, specialMessageSize }); | |||
| sendMessageToWorker ({ startMessage, specialMessageSize }); | |||
| return true; | |||
| } | |||
| @@ -167,11 +176,11 @@ bool ChildProcessMaster::launchSlaveProcess (const File& executable, const Strin | |||
| return false; | |||
| } | |||
| void ChildProcessMaster::killSlaveProcess() | |||
| void ChildProcessCoordinator::killWorkerProcess() | |||
| { | |||
| if (connection != nullptr) | |||
| { | |||
| sendMessageToSlave ({ killMessage, specialMessageSize }); | |||
| sendMessageToWorker ({ killMessage, specialMessageSize }); | |||
| connection->disconnect(); | |||
| connection.reset(); | |||
| } | |||
| @@ -180,11 +189,11 @@ void ChildProcessMaster::killSlaveProcess() | |||
| } | |||
| //============================================================================== | |||
| struct ChildProcessSlave::Connection : public InterprocessConnection, | |||
| private ChildProcessPingThread | |||
| struct ChildProcessWorker::Connection : public InterprocessConnection, | |||
| private ChildProcessPingThread | |||
| { | |||
| Connection (ChildProcessSlave& p, const String& pipeName, int timeout) | |||
| : InterprocessConnection (false, magicMastSlaveConnectionHeader), | |||
| Connection (ChildProcessWorker& p, const String& pipeName, int timeout) | |||
| : InterprocessConnection (false, magicCoordWorkerConnectionHeader), | |||
| ChildProcessPingThread (timeout), | |||
| owner (p) | |||
| { | |||
| @@ -198,12 +207,12 @@ struct ChildProcessSlave::Connection : public InterprocessConnection, | |||
| } | |||
| private: | |||
| ChildProcessSlave& owner; | |||
| ChildProcessWorker& owner; | |||
| void connectionMade() override {} | |||
| void connectionLost() override { owner.handleConnectionLost(); } | |||
| bool sendPingMessage (const MemoryBlock& m) override { return owner.sendMessageToMaster (m); } | |||
| bool sendPingMessage (const MemoryBlock& m) override { return owner.sendMessageToCoordinator (m); } | |||
| void pingFailed() override { connectionLost(); } | |||
| void messageReceived (const MemoryBlock& m) override | |||
| @@ -219,20 +228,29 @@ private: | |||
| if (isMessageType (m, startMessage)) | |||
| return owner.handleConnectionMade(); | |||
| owner.handleMessageFromMaster (m); | |||
| owner.handleMessageFromCoordinator (m); | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Connection) | |||
| }; | |||
| //============================================================================== | |||
| ChildProcessSlave::ChildProcessSlave() {} | |||
| ChildProcessSlave::~ChildProcessSlave() {} | |||
| ChildProcessWorker::ChildProcessWorker() = default; | |||
| ChildProcessWorker::~ChildProcessWorker() = default; | |||
| void ChildProcessWorker::handleConnectionMade() {} | |||
| void ChildProcessWorker::handleConnectionLost() {} | |||
| void ChildProcessSlave::handleConnectionMade() {} | |||
| void ChildProcessSlave::handleConnectionLost() {} | |||
| void ChildProcessWorker::handleMessageFromCoordinator (const MemoryBlock& mb) | |||
| { | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") | |||
| JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996) | |||
| handleMessageFromMaster (mb); | |||
| JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||
| JUCE_END_IGNORE_WARNINGS_MSVC | |||
| } | |||
| bool ChildProcessSlave::sendMessageToMaster (const MemoryBlock& mb) | |||
| bool ChildProcessWorker::sendMessageToCoordinator (const MemoryBlock& mb) | |||
| { | |||
| if (connection != nullptr) | |||
| return connection->sendMessage (mb); | |||
| @@ -241,9 +259,9 @@ bool ChildProcessSlave::sendMessageToMaster (const MemoryBlock& mb) | |||
| return false; | |||
| } | |||
| bool ChildProcessSlave::initialiseFromCommandLine (const String& commandLine, | |||
| const String& commandLineUniqueID, | |||
| int timeoutMs) | |||
| bool ChildProcessWorker::initialiseFromCommandLine (const String& commandLine, | |||
| const String& commandLineUniqueID, | |||
| int timeoutMs) | |||
| { | |||
| auto prefix = getCommandLinePrefix (commandLineUniqueID); | |||
| @@ -25,47 +25,47 @@ namespace juce | |||
| //============================================================================== | |||
| /** | |||
| Acts as the slave end of a master/slave pair of connected processes. | |||
| Acts as the worker end of a coordinator/worker pair of connected processes. | |||
| The ChildProcessSlave and ChildProcessMaster classes make it easy for an app | |||
| The ChildProcessWorker and ChildProcessCoordinator classes make it easy for an app | |||
| to spawn a child process, and to manage a 2-way messaging connection to control it. | |||
| To use the system, you need to create subclasses of both ChildProcessSlave and | |||
| ChildProcessMaster. To instantiate the ChildProcessSlave object, you must | |||
| To use the system, you need to create subclasses of both ChildProcessWorker and | |||
| ChildProcessCoordinator. To instantiate the ChildProcessWorker object, you must | |||
| add some code to your main() or JUCEApplication::initialise() function that | |||
| calls the initialiseFromCommandLine() method to check the app's command-line | |||
| parameters to see whether it's being launched as a child process. If this returns | |||
| true then the slave process can be allowed to run, and its handleMessageFromMaster() | |||
| true then the worker process can be allowed to run, and its handleMessageFromCoordinator() | |||
| method will be called whenever a message arrives. | |||
| The juce demo app has a good example of this class in action. | |||
| @see ChildProcessMaster, InterprocessConnection, ChildProcess | |||
| @see ChildProcessCoordinator, InterprocessConnection, ChildProcess | |||
| @tags{Events} | |||
| */ | |||
| class JUCE_API ChildProcessSlave | |||
| class JUCE_API ChildProcessWorker | |||
| { | |||
| public: | |||
| /** Creates a non-connected slave process. | |||
| Use initialiseFromCommandLine to connect to a master process. | |||
| /** Creates a non-connected worker process. | |||
| Use initialiseFromCommandLine to connect to a coordinator process. | |||
| */ | |||
| ChildProcessSlave(); | |||
| ChildProcessWorker(); | |||
| /** Destructor. */ | |||
| virtual ~ChildProcessSlave(); | |||
| virtual ~ChildProcessWorker(); | |||
| /** This checks some command-line parameters to see whether they were generated by | |||
| ChildProcessMaster::launchSlaveProcess(), and if so, connects to that master process. | |||
| ChildProcessCoordinator::launchWorkerProcess(), and if so, connects to that coordinator process. | |||
| In an exe that can be used as a child process, you should add some code to your | |||
| main() or JUCEApplication::initialise() that calls this method. | |||
| The commandLineUniqueID should be a short alphanumeric identifier (no spaces!) | |||
| that matches the string passed to ChildProcessMaster::launchSlaveProcess(). | |||
| that matches the string passed to ChildProcessCoordinator::launchWorkerProcess(). | |||
| The timeoutMs parameter lets you specify how long the child process is allowed | |||
| to run without receiving a ping from the master before the master is considered to | |||
| to run without receiving a ping from the coordinator before the coordinator is considered to | |||
| have died, and handleConnectionLost() will be called. Passing <= 0 for this timeout | |||
| makes it use a default value. | |||
| @@ -76,78 +76,86 @@ public: | |||
| int timeoutMs = 0); | |||
| //============================================================================== | |||
| /** This will be called to deliver messages from the master process. | |||
| /** This will be called to deliver messages from the coordinator process. | |||
| The call will probably be made on a background thread, so be careful with your | |||
| thread-safety! You may want to respond by sending back a message with | |||
| sendMessageToMaster() | |||
| sendMessageToCoordinator() | |||
| */ | |||
| virtual void handleMessageFromMaster (const MemoryBlock&) = 0; | |||
| virtual void handleMessageFromCoordinator (const MemoryBlock& mb); | |||
| /** This will be called when the master process finishes connecting to this slave. | |||
| [[deprecated ("Replaced by handleMessageFromCoordinator.")]] | |||
| virtual void handleMessageFromMaster (const MemoryBlock&) {} | |||
| /** This will be called when the coordinator process finishes connecting to this worker. | |||
| The call will probably be made on a background thread, so be careful with your thread-safety! | |||
| */ | |||
| virtual void handleConnectionMade(); | |||
| /** This will be called when the connection to the master process is lost. | |||
| /** This will be called when the connection to the coordinator process is lost. | |||
| The call may be made from any thread (including the message thread). | |||
| Typically, if your process only exists to act as a slave, you should probably exit | |||
| Typically, if your process only exists to act as a worker, you should probably exit | |||
| when this happens. | |||
| */ | |||
| virtual void handleConnectionLost(); | |||
| /** Tries to send a message to the master process. | |||
| /** Tries to send a message to the coordinator process. | |||
| This returns true if the message was sent, but doesn't check that it actually gets | |||
| delivered at the other end. If successful, the data will emerge in a call to your | |||
| ChildProcessMaster::handleMessageFromSlave(). | |||
| ChildProcessCoordinator::handleMessageFromWorker(). | |||
| */ | |||
| bool sendMessageToMaster (const MemoryBlock&); | |||
| bool sendMessageToCoordinator (const MemoryBlock&); | |||
| [[deprecated ("Replaced by sendMessageToCoordinator.")]] | |||
| bool sendMessageToMaster (const MemoryBlock& mb) { return sendMessageToCoordinator (mb); } | |||
| private: | |||
| struct Connection; | |||
| std::unique_ptr<Connection> connection; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessSlave) | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessWorker) | |||
| }; | |||
| using ChildProcessSlave [[deprecated ("Replaced by ChildProcessWorker.")]] = ChildProcessWorker; | |||
| //============================================================================== | |||
| /** | |||
| Acts as the master in a master/slave pair of connected processes. | |||
| Acts as the coordinator in a coordinator/worker pair of connected processes. | |||
| The ChildProcessSlave and ChildProcessMaster classes make it easy for an app | |||
| The ChildProcessWorker and ChildProcessCoordinator classes make it easy for an app | |||
| to spawn a child process, and to manage a 2-way messaging connection to control it. | |||
| To use the system, you need to create subclasses of both ChildProcessSlave and | |||
| ChildProcessMaster. When you want your master process to launch the slave, you | |||
| just call launchSlaveProcess(), and it'll attempt to launch the executable that | |||
| To use the system, you need to create subclasses of both ChildProcessWorker and | |||
| ChildProcessCoordinator. When you want your coordinator process to launch the worker, you | |||
| just call launchWorkerProcess(), and it'll attempt to launch the executable that | |||
| you specify (which may be the same exe), and assuming it has been set-up to | |||
| correctly parse the command-line parameters (see ChildProcessSlave) then a | |||
| correctly parse the command-line parameters (see ChildProcessWorker) then a | |||
| two-way connection will be created. | |||
| The juce demo app has a good example of this class in action. | |||
| @see ChildProcessSlave, InterprocessConnection, ChildProcess | |||
| @see ChildProcessWorker, InterprocessConnection, ChildProcess | |||
| @tags{Events} | |||
| */ | |||
| class JUCE_API ChildProcessMaster | |||
| class JUCE_API ChildProcessCoordinator | |||
| { | |||
| public: | |||
| /** Creates an uninitialised master process object. | |||
| Use launchSlaveProcess to launch and connect to a child process. | |||
| /** Creates an uninitialised coordinator process object. | |||
| Use launchWorkerProcess to launch and connect to a child process. | |||
| */ | |||
| ChildProcessMaster(); | |||
| ChildProcessCoordinator(); | |||
| /** Destructor. | |||
| Note that the destructor calls killSlaveProcess(), but doesn't wait for | |||
| Note that the destructor calls killWorkerProcess(), but doesn't wait for | |||
| the child process to finish terminating. | |||
| */ | |||
| virtual ~ChildProcessMaster(); | |||
| virtual ~ChildProcessCoordinator(); | |||
| /** Attempts to launch and connect to a slave process. | |||
| /** Attempts to launch and connect to a worker process. | |||
| This will start the given executable, passing it a special command-line | |||
| parameter based around the commandLineUniqueID string, which must be a | |||
| short alphanumeric string (no spaces!) that identifies your app. The exe | |||
| that gets launched must respond by calling ChildProcessSlave::initialiseFromCommandLine() | |||
| that gets launched must respond by calling ChildProcessWorker::initialiseFromCommandLine() | |||
| in its startup code, and must use a matching ID to commandLineUniqueID. | |||
| The timeoutMs parameter lets you specify how long the child process is allowed | |||
| @@ -156,37 +164,55 @@ public: | |||
| it use a default value. | |||
| If this all works, the method returns true, and you can begin sending and | |||
| receiving messages with the slave process. | |||
| receiving messages with the worker process. | |||
| If a child process is already running, this will call killSlaveProcess() and | |||
| If a child process is already running, this will call killWorkerProcess() and | |||
| start a new one. | |||
| */ | |||
| bool launchWorkerProcess (const File& executableToLaunch, | |||
| const String& commandLineUniqueID, | |||
| int timeoutMs = 0, | |||
| int streamFlags = ChildProcess::wantStdOut | ChildProcess::wantStdErr); | |||
| [[deprecated ("Replaced by launchWorkerProcess.")]] | |||
| bool launchSlaveProcess (const File& executableToLaunch, | |||
| const String& commandLineUniqueID, | |||
| int timeoutMs = 0, | |||
| int streamFlags = ChildProcess::wantStdOut | ChildProcess::wantStdErr); | |||
| int streamFlags = ChildProcess::wantStdOut | ChildProcess::wantStdErr) | |||
| { | |||
| return launchWorkerProcess (executableToLaunch, commandLineUniqueID, timeoutMs, streamFlags); | |||
| } | |||
| /** Sends a kill message to the slave, and disconnects from it. | |||
| /** Sends a kill message to the worker, and disconnects from it. | |||
| Note that this won't wait for it to terminate. | |||
| */ | |||
| void killSlaveProcess(); | |||
| void killWorkerProcess(); | |||
| /** This will be called to deliver a message from the slave process. | |||
| [[deprecated ("Replaced by killWorkerProcess.")]] | |||
| void killSlaveProcess() { killWorkerProcess(); } | |||
| /** This will be called to deliver a message from the worker process. | |||
| The call will probably be made on a background thread, so be careful with your thread-safety! | |||
| */ | |||
| virtual void handleMessageFromSlave (const MemoryBlock&) = 0; | |||
| virtual void handleMessageFromWorker (const MemoryBlock&); | |||
| [[deprecated ("Replaced by handleMessageFromWorker")]] | |||
| virtual void handleMessageFromSlave (const MemoryBlock&) {} | |||
| /** This will be called when the slave process dies or is somehow disconnected. | |||
| /** This will be called when the worker process dies or is somehow disconnected. | |||
| The call will probably be made on a background thread, so be careful with your thread-safety! | |||
| */ | |||
| virtual void handleConnectionLost(); | |||
| /** Attempts to send a message to the slave process. | |||
| /** Attempts to send a message to the worker process. | |||
| This returns true if the message was dispatched, but doesn't check that it actually | |||
| gets delivered at the other end. If successful, the data will emerge in a call to | |||
| your ChildProcessSlave::handleMessageFromMaster(). | |||
| your ChildProcessWorker::handleMessageFromCoordinator(). | |||
| */ | |||
| bool sendMessageToSlave (const MemoryBlock&); | |||
| bool sendMessageToWorker (const MemoryBlock&); | |||
| [[deprecated ("Replaced by sendMessageToWorker.")]] | |||
| bool sendMessageToSlave (const MemoryBlock& mb) { return sendMessageToWorker (mb); } | |||
| private: | |||
| std::unique_ptr<ChildProcess> childProcess; | |||
| @@ -194,7 +220,9 @@ private: | |||
| struct Connection; | |||
| std::unique_ptr<Connection> connection; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessMaster) | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessCoordinator) | |||
| }; | |||
| using ChildProcessMaster [[deprecated ("Replaced by ChildProcessCoordinator.")]] = ChildProcessCoordinator; | |||
| } // namespace juce | |||