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.

329 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. {
  28. server = new DemoInterprocessConnectionServer (*this);
  29. setName (T("Interprocess Communication"));
  30. // create all our UI bits and pieces..
  31. addAndMakeVisible (modeSelector = new ComboBox (T("mode:")));
  32. modeSelector->setBounds (100, 25, 200, 24);
  33. (new Label (modeSelector->getName(), modeSelector->getName()))->attachToComponent (modeSelector, true);
  34. modeSelector->addItem (T("(Disconnected)"), 8);
  35. modeSelector->addSeparator();
  36. modeSelector->addItem (T("Named pipe (listening)"), 1);
  37. modeSelector->addItem (T("Named pipe (connect to existing pipe)"), 5);
  38. modeSelector->addSeparator();
  39. modeSelector->addItem (T("Socket (listening)"), 2);
  40. modeSelector->addItem (T("Socket (connect to existing socket)"), 6);
  41. modeSelector->setSelectedId (8);
  42. modeSelector->addListener (this);
  43. addAndMakeVisible (pipeName = new TextEditor (T("pipe name:")));
  44. pipeName->setBounds (100, 60, 130, 24);
  45. pipeName->setMultiLine (false);
  46. pipeName->setText (T("juce demo pipe"));
  47. (new Label (pipeName->getName(), pipeName->getName()))->attachToComponent (pipeName, true);
  48. addAndMakeVisible (socketNumber = new TextEditor (T("socket port:")));
  49. socketNumber->setBounds (350, 60, 80, 24);
  50. socketNumber->setMultiLine (false);
  51. socketNumber->setText (T("12345"));
  52. socketNumber->setInputRestrictions (5, T("0123456789"));
  53. (new Label (socketNumber->getName(), socketNumber->getName()))->attachToComponent (socketNumber, true);
  54. addAndMakeVisible (socketHost = new TextEditor (T("socket host:")));
  55. socketHost->setBounds (530, 60, 130, 24);
  56. socketHost->setMultiLine (false);
  57. socketHost->setText (T("localhost"));
  58. socketNumber->setInputRestrictions (512);
  59. (new Label (socketHost->getName(), socketHost->getName()))->attachToComponent (socketHost, true);
  60. addChildComponent (sendText = new TextEditor (T("sendtext")));
  61. sendText->setBounds (30, 120, 200, 24);
  62. sendText->setMultiLine (false);
  63. sendText->setReadOnly (false);
  64. sendText->setText (T("testing 1234"));
  65. addChildComponent (sendButton = new TextButton (T("send"), T("Fires off the message")));
  66. sendButton->setBounds (240, 120, 200, 24);
  67. sendButton->changeWidthToFitText();
  68. sendButton->addButtonListener (this);
  69. addChildComponent (incomingMessages = new TextEditor (T("messages")));
  70. incomingMessages->setReadOnly (true);
  71. incomingMessages->setMultiLine (true);
  72. incomingMessages->setBounds (30, 150, 500, 250);
  73. // call this to set up everything's state correctly.
  74. comboBoxChanged (0);
  75. }
  76. ~InterprocessCommsDemo()
  77. {
  78. close();
  79. delete server;
  80. deleteAllChildren();
  81. }
  82. void buttonClicked (Button* button)
  83. {
  84. if (button == sendButton)
  85. {
  86. // The send button has been pressed, so write out the contents of the
  87. // text box to the socket or pipe, depending on which is active.
  88. const String text (sendText->getText());
  89. MemoryBlock messageData (text.toUTF8(), text.getNumBytesAsUTF8());
  90. for (int i = activeConnections.size(); --i >= 0;)
  91. {
  92. if (! activeConnections[i]->sendMessage (messageData))
  93. {
  94. // the write failed, so indicate that the connection has broken..
  95. appendMessage (T("send message failed!"));
  96. }
  97. }
  98. }
  99. }
  100. void comboBoxChanged (ComboBox*)
  101. {
  102. // This is called when the user picks a different mode from the drop-down list..
  103. const int modeId = modeSelector->getSelectedId();
  104. close();
  105. if (modeId < 8)
  106. {
  107. open ((modeId & 2) != 0,
  108. (modeId & 4) != 0);
  109. }
  110. }
  111. //==============================================================================
  112. // Just closes any connections that are currently open.
  113. void close()
  114. {
  115. server->stop();
  116. activeConnections.clear();
  117. // Reset the UI stuff to a disabled state.
  118. sendText->setVisible (false);
  119. sendButton->setVisible (false);
  120. incomingMessages->setText (String::empty, false);
  121. incomingMessages->setVisible (true);
  122. appendMessage (
  123. "To demonstrate named pipes, you'll need to run two instances of the JuceDemo application on this machine. On "
  124. "one of them, select \"named pipe (listening)\", and then on the other, select \"named pipe (connect to existing pipe)\". Then messages that you "
  125. "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"
  126. "To demonstrate sockets, you can either run two instances of the app on the same machine, or on different "
  127. "machines on your network. In each one enter a socket number, then on one of the apps, select the "
  128. "\"Socket (listening)\" mode. On the other, enter the host address of the listening app, and select \"Socket (connect to existing socket)\". "
  129. "Messages should then be be sent between the apps in the same way as through the named pipes.");
  130. }
  131. void open (bool asSocket, bool asSender)
  132. {
  133. close();
  134. // Make the appropriate bits of UI visible..
  135. sendText->setVisible (true);
  136. sendButton->setVisible (true);
  137. incomingMessages->setText (String::empty, false);
  138. incomingMessages->setVisible (true);
  139. // and try to open the socket or pipe...
  140. bool openedOk = false;
  141. if (asSender)
  142. {
  143. // if we're connecting to an existing server, we can just create a connection object
  144. // directly.
  145. DemoInterprocessConnection* newConnection = new DemoInterprocessConnection (*this);
  146. if (asSocket)
  147. {
  148. openedOk = newConnection->connectToSocket (socketHost->getText(),
  149. socketNumber->getText().getIntValue(),
  150. 1000);
  151. }
  152. else
  153. {
  154. openedOk = newConnection->connectToPipe (pipeName->getText());
  155. }
  156. if (openedOk)
  157. activeConnections.add (newConnection);
  158. else
  159. delete newConnection;
  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 (T("Waiting for another app to connect to this socket.."));
  170. }
  171. else
  172. {
  173. DemoInterprocessConnection* newConnection = new DemoInterprocessConnection (*this);
  174. openedOk = newConnection->createPipe (pipeName->getText());
  175. if (openedOk)
  176. {
  177. appendMessage (T("Waiting for another app to connect to this pipe.."));
  178. activeConnections.add (newConnection);
  179. }
  180. else
  181. {
  182. delete newConnection;
  183. }
  184. }
  185. }
  186. if (! openedOk)
  187. {
  188. modeSelector->setSelectedId (8);
  189. AlertWindow::showMessageBox (AlertWindow::WarningIcon,
  190. T("Interprocess Comms Demo"),
  191. T("Failed to open the socket or pipe..."));
  192. }
  193. }
  194. void appendMessage (const String& message)
  195. {
  196. incomingMessages->setCaretPosition (INT_MAX);
  197. incomingMessages->insertTextAtCaret (message + T("\n"));
  198. incomingMessages->setCaretPosition (INT_MAX);
  199. }
  200. //==============================================================================
  201. class DemoInterprocessConnection : public InterprocessConnection
  202. {
  203. InterprocessCommsDemo& owner;
  204. int ourNumber;
  205. public:
  206. DemoInterprocessConnection (InterprocessCommsDemo& owner_)
  207. : InterprocessConnection (true),
  208. owner (owner_)
  209. {
  210. static int totalConnections = 0;
  211. ourNumber = ++totalConnections;
  212. }
  213. ~DemoInterprocessConnection()
  214. {
  215. }
  216. void connectionMade()
  217. {
  218. owner.appendMessage (T("Connection #") + String (ourNumber) + T(" - connection started"));
  219. }
  220. void connectionLost()
  221. {
  222. owner.appendMessage (T("Connection #") + String (ourNumber) + T(" - connection lost"));
  223. }
  224. void messageReceived (const MemoryBlock& message)
  225. {
  226. owner.appendMessage (T("Connection #") + String (ourNumber) + T(" - message received: ") + message.toString());
  227. }
  228. };
  229. //==============================================================================
  230. class DemoInterprocessConnectionServer : public InterprocessConnectionServer
  231. {
  232. InterprocessCommsDemo& owner;
  233. public:
  234. DemoInterprocessConnectionServer (InterprocessCommsDemo& owner_)
  235. : owner (owner_)
  236. {
  237. }
  238. ~DemoInterprocessConnectionServer()
  239. {
  240. }
  241. InterprocessConnection* createConnectionObject()
  242. {
  243. DemoInterprocessConnection* newConnection = new DemoInterprocessConnection (owner);
  244. owner.activeConnections.add (newConnection);
  245. return newConnection;
  246. }
  247. };
  248. OwnedArray <DemoInterprocessConnection, CriticalSection> activeConnections;
  249. //==============================================================================
  250. juce_UseDebuggingNewOperator
  251. private:
  252. ComboBox* modeSelector;
  253. TextEditor* sendText;
  254. TextButton* sendButton;
  255. TextEditor* incomingMessages;
  256. TextEditor* pipeName;
  257. TextEditor* socketNumber;
  258. TextEditor* socketHost;
  259. DemoInterprocessConnectionServer* server;
  260. };
  261. //==============================================================================
  262. Component* createInterprocessCommsDemo()
  263. {
  264. return new InterprocessCommsDemo();
  265. }