The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

313 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "../jucedemo_headers.h"
  18. //==============================================================================
  19. class InterprocessCommsDemo : public Component,
  20. public ButtonListener,
  21. public ComboBoxListener
  22. {
  23. public:
  24. //==============================================================================
  25. InterprocessCommsDemo()
  26. : sendButton ("send", "Fires off the message"),
  27. modeLabel (String::empty, "Mode:"),
  28. pipeLabel (String::empty, "Pipe Name:"),
  29. numberLabel (String::empty, "Socket Port:"),
  30. hostLabel (String::empty, "Socket Host:")
  31. {
  32. setName ("Interprocess Communication");
  33. server = new DemoInterprocessConnectionServer (*this);
  34. // create all our UI bits and pieces..
  35. addAndMakeVisible (&modeSelector);
  36. modeSelector.setBounds (100, 25, 200, 24);
  37. modeLabel.attachToComponent (&modeSelector, true);
  38. modeSelector.addItem ("(Disconnected)", 8);
  39. modeSelector.addSeparator();
  40. modeSelector.addItem ("Named pipe (listening)", 1);
  41. modeSelector.addItem ("Named pipe (connect to existing pipe)", 5);
  42. modeSelector.addSeparator();
  43. modeSelector.addItem ("Socket (listening)", 2);
  44. modeSelector.addItem ("Socket (connect to existing socket)", 6);
  45. modeSelector.setSelectedId (8);
  46. modeSelector.addListener (this);
  47. addAndMakeVisible (&pipeName);
  48. pipeName.setBounds (100, 60, 130, 24);
  49. pipeName.setMultiLine (false);
  50. pipeName.setText ("juce demo pipe");
  51. pipeLabel.attachToComponent (&pipeName, true);
  52. addAndMakeVisible (&socketNumber);
  53. socketNumber.setBounds (350, 60, 80, 24);
  54. socketNumber.setMultiLine (false);
  55. socketNumber.setText ("12345");
  56. socketNumber.setInputRestrictions (5, "0123456789");
  57. numberLabel.attachToComponent (&socketNumber, true);
  58. addAndMakeVisible (&socketHost);
  59. socketHost.setBounds (530, 60, 130, 24);
  60. socketHost.setMultiLine (false);
  61. socketHost.setText ("localhost");
  62. socketNumber.setInputRestrictions (512);
  63. hostLabel.attachToComponent (&socketHost, true);
  64. addChildComponent (&sendText);
  65. sendText.setBounds (30, 120, 200, 24);
  66. sendText.setMultiLine (false);
  67. sendText.setReadOnly (false);
  68. sendText.setText ("testing 1234");
  69. addChildComponent (&sendButton);
  70. sendButton.setBounds (240, 120, 200, 24);
  71. sendButton.changeWidthToFitText();
  72. sendButton.addListener (this);
  73. addChildComponent (&incomingMessages);
  74. incomingMessages.setReadOnly (true);
  75. incomingMessages.setMultiLine (true);
  76. incomingMessages.setBounds (30, 150, 500, 250);
  77. // call this to set up everything's state correctly.
  78. comboBoxChanged (0);
  79. }
  80. ~InterprocessCommsDemo()
  81. {
  82. close();
  83. }
  84. void buttonClicked (Button* button)
  85. {
  86. if (button == &sendButton)
  87. {
  88. // The send button has been pressed, so write out the contents of the
  89. // text box to the socket or pipe, depending on which is active.
  90. const String text (sendText.getText());
  91. MemoryBlock messageData (text.toUTF8(), text.getNumBytesAsUTF8());
  92. for (int i = activeConnections.size(); --i >= 0;)
  93. {
  94. if (! activeConnections[i]->sendMessage (messageData))
  95. {
  96. // the write failed, so indicate that the connection has broken..
  97. appendMessage ("send message failed!");
  98. }
  99. }
  100. }
  101. }
  102. void comboBoxChanged (ComboBox*)
  103. {
  104. // This is called when the user picks a different mode from the drop-down list..
  105. const int modeId = modeSelector.getSelectedId();
  106. close();
  107. if (modeId < 8)
  108. {
  109. open ((modeId & 2) != 0,
  110. (modeId & 4) != 0);
  111. }
  112. }
  113. //==============================================================================
  114. // Just closes any connections that are currently open.
  115. void close()
  116. {
  117. server->stop();
  118. activeConnections.clear();
  119. // Reset the UI stuff to a disabled state.
  120. sendText.setVisible (false);
  121. sendButton.setVisible (false);
  122. incomingMessages.setText (String::empty, false);
  123. incomingMessages.setVisible (true);
  124. appendMessage (
  125. "To demonstrate named pipes, you'll need to run two instances of the JuceDemo application on this machine. On "
  126. "one of them, select \"named pipe (listening)\", and then on the other, select \"named pipe (connect to existing pipe)\". Then messages that you "
  127. "send from the 'sender' app should appear on the listener app. The \"pipe name\" field lets you choose a name for the pipe\n\n"
  128. "To demonstrate sockets, you can either run two instances of the app on the same machine, or on different "
  129. "machines on your network. In each one enter a socket number, then on one of the apps, select the "
  130. "\"Socket (listening)\" mode. On the other, enter the host address of the listening app, and select \"Socket (connect to existing socket)\". "
  131. "Messages should then be be sent between the apps in the same way as through the named pipes.");
  132. }
  133. void open (bool asSocket, bool asSender)
  134. {
  135. close();
  136. // Make the appropriate bits of UI visible..
  137. sendText.setVisible (true);
  138. sendButton.setVisible (true);
  139. incomingMessages.setText (String::empty, false);
  140. incomingMessages.setVisible (true);
  141. // and try to open the socket or pipe...
  142. bool openedOk = false;
  143. if (asSender)
  144. {
  145. // if we're connecting to an existing server, we can just create a connection object
  146. // directly.
  147. ScopedPointer<DemoInterprocessConnection> newConnection (new DemoInterprocessConnection (*this));
  148. if (asSocket)
  149. {
  150. openedOk = newConnection->connectToSocket (socketHost.getText(),
  151. socketNumber.getText().getIntValue(),
  152. 1000);
  153. }
  154. else
  155. {
  156. openedOk = newConnection->connectToPipe (pipeName.getText(), 5000);
  157. }
  158. if (openedOk)
  159. activeConnections.add (newConnection.release());
  160. }
  161. else
  162. {
  163. // if we're starting up a server, we need to tell the server to start waiting for
  164. // clients to connect. It'll then create connection objects for us when clients arrive.
  165. if (asSocket)
  166. {
  167. openedOk = server->beginWaitingForSocket (socketNumber.getText().getIntValue());
  168. if (openedOk)
  169. appendMessage ("Waiting for another app to connect to this socket..");
  170. }
  171. else
  172. {
  173. ScopedPointer<DemoInterprocessConnection> newConnection (new DemoInterprocessConnection (*this));
  174. openedOk = newConnection->createPipe (pipeName.getText(), 2000);
  175. if (openedOk)
  176. {
  177. appendMessage ("Waiting for another app to connect to this pipe..");
  178. activeConnections.add (newConnection.release());
  179. }
  180. }
  181. }
  182. if (! openedOk)
  183. {
  184. modeSelector.setSelectedId (8);
  185. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  186. "Interprocess Comms Demo",
  187. "Failed to open the socket or pipe...");
  188. }
  189. }
  190. void appendMessage (const String& message)
  191. {
  192. incomingMessages.setCaretPosition (INT_MAX);
  193. incomingMessages.insertTextAtCaret (message + "\n");
  194. incomingMessages.setCaretPosition (INT_MAX);
  195. }
  196. //==============================================================================
  197. class DemoInterprocessConnection : public InterprocessConnection
  198. {
  199. public:
  200. DemoInterprocessConnection (InterprocessCommsDemo& owner_)
  201. : InterprocessConnection (true),
  202. owner (owner_)
  203. {
  204. static int totalConnections = 0;
  205. ourNumber = ++totalConnections;
  206. }
  207. void connectionMade()
  208. {
  209. owner.appendMessage ("Connection #" + String (ourNumber) + " - connection started");
  210. }
  211. void connectionLost()
  212. {
  213. owner.appendMessage ("Connection #" + String (ourNumber) + " - connection lost");
  214. }
  215. void messageReceived (const MemoryBlock& message)
  216. {
  217. owner.appendMessage ("Connection #" + String (ourNumber) + " - message received: " + message.toString());
  218. }
  219. private:
  220. InterprocessCommsDemo& owner;
  221. int ourNumber;
  222. };
  223. //==============================================================================
  224. class DemoInterprocessConnectionServer : public InterprocessConnectionServer
  225. {
  226. public:
  227. DemoInterprocessConnectionServer (InterprocessCommsDemo& owner_)
  228. : owner (owner_)
  229. {
  230. }
  231. InterprocessConnection* createConnectionObject()
  232. {
  233. DemoInterprocessConnection* newConnection = new DemoInterprocessConnection (owner);
  234. owner.activeConnections.add (newConnection);
  235. return newConnection;
  236. }
  237. private:
  238. InterprocessCommsDemo& owner;
  239. };
  240. OwnedArray <DemoInterprocessConnection, CriticalSection> activeConnections;
  241. private:
  242. ComboBox modeSelector;
  243. TextButton sendButton;
  244. TextEditor sendText, incomingMessages, pipeName, socketNumber, socketHost;
  245. Label modeLabel, pipeLabel, numberLabel, hostLabel;
  246. ScopedPointer<DemoInterprocessConnectionServer> server;
  247. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InterprocessCommsDemo)
  248. };
  249. //==============================================================================
  250. Component* createInterprocessCommsDemo()
  251. {
  252. return new InterprocessCommsDemo();
  253. }