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.

314 lines
12KB

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