From efa4897a91d0d0ec40548d3fce24d370b8e19fe4 Mon Sep 17 00:00:00 2001
From: Jonathan Wilkes <jon.w.wilkes@gmail.com>
Date: Sun, 22 Nov 2015 18:11:15 -0500
Subject: [PATCH] first attempt at starting Pd from the GUI

---
 pd/nw/index.js | 27 +++++++++++++-------------
 pd/nw/pdgui.js | 52 ++++++++++++++++++++++++++++++++++----------------
 pd/nw/todo.txt |  1 +
 3 files changed, 51 insertions(+), 29 deletions(-)

diff --git a/pd/nw/index.js b/pd/nw/index.js
index 42e6f1f4c..8ef53a3fe 100644
--- a/pd/nw/index.js
+++ b/pd/nw/index.js
@@ -16,8 +16,13 @@ set_vars(this);
 add_events();
 nw_create_pd_window_menus();
 gui.Window.get().setMinimumSize(350,250);
-// This part depends on whether the GUI is starting Pd, or whether it's
-// the other way around.
+// Now we create a connection from the GUI to Pd, in one of two ways:
+// 1) If the GUI was started by Pd, then we create a tcp client and
+//    connect on the port Pd fed us in our command line arguments.
+// 2) If Pd hasn't started yet, then the GUI creates a tcp server and spawns
+//    Pd using the "-guiport" flag with the port the GUI is listening on.
+// Pd always starts the GUI with a certain set of command line arguments. If
+// those arguments aren't present then we assume we need to start Pd.
 connect();
 
 function have_args() {
@@ -103,19 +108,15 @@ function add_events() {
 }
 
 function connect() {
-    // When the GUI is started by core Pd, it gives it some command
-    // line args. In that case we just need to create a client and
-    // connect to Pd on the port it gave us as an arg.
-    // If we have no command line args, it means we need to create a
-    // server, and also create the Pd process with the command line
-    // arg -guiport and providing the port we are listening on.
-    if (have_args()) {
-        pdgui.create_client();
+    if (have_args()) { 
+        // Pd started the GUI, so connect to it on port provided in our args
+        pdgui.post("Pd has started the GUI");
+        pdgui.connect_as_client();
     } else {
-        pdgui.post("creating server");
-        pdgui.create_server();
+        // create a tcp server, then spawn Pd with "-guiport" flag and port
+        pdgui.post("GUI is starting Pd...");
+        pdgui.connect_as_server();
     }
-    pdgui.init_socket_events();
 }
 
 function console_find_check_default(e) {
diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index 03def5906..f1e9b58d7 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -1,7 +1,5 @@
 "use strict";
 
-// Modules
-
 var pwd;
 var gui_dir;
 
@@ -29,8 +27,11 @@ exports.get_pd_opendir = function() {
     }
 }
 
+// Modules
+
 var fs = require("fs");     // for fs.existsSync
 var path = require("path"); // for path.dirname path.extname path.join
+var cp = require("child_process"); // for starting core Pd from GUI in OSX
 
 // local strings
 var lang = require("./pdlang.js");
@@ -691,6 +692,7 @@ function gui_check_unique (unique) {
 function gui_startup(version, fontname_from_pd, fontweight_from_pd,
     apilist, midiapilist) {
     console.log("Starting up...");
+    console.log("gui_startup from GUI...");
     // # tb: user defined typefaces
     // set some global variables
     pd_myversion = version;
@@ -926,18 +928,32 @@ function gui_canvas_erase_all_gobjs(cid) {
 
 exports.canvas_map = canvas_map;
 
+// Start Pd
+
+// If the GUI is started first (as in a Mac OSX Bundle) we use this
+// function to actually start the core
+function spawn_pd() {
+    var pd_binary = "/home/user/pd-nw/packages/linux_make/build/usr/bin/pd-l2ork";
+    var child = cp.spawn(pd_binary, ["-guiport", PORT, "-nrt"], {
+        stdio: "inherit",
+        detached: true
+    });
+    child.unref();
+    post("Pd started.");
+}
+
 // net stuff
 var net = require("net");
 
 var HOST = "127.0.0.1";
 var PORT;
-var socket;
+var connection; // the GUI's socket connection to Pd
 
 exports.set_port = function (port_no) {
     PORT = port_no;
 }
 
-function create_client() {
+function connect_as_client() {
     var client = new net.Socket();
     client.setNoDelay(true);
     // uncomment the next line to use fast_parser (then set its callback below)
@@ -945,21 +961,25 @@ function create_client() {
     client.connect(PORT, HOST, function() {
         console.log("CONNECTED TO: " + HOST + ":" + PORT);
     });
-    socket = client;
+    connection = client;
+    init_socket_events();
 }
 
-exports.create_client = create_client;
+exports.connect_as_client = connect_as_client;
 
-function create_server() {
+function connect_as_server() {
     var server = net.createServer(function(c) {
-        console.log("server connected");
+        post("incoming connection to GUI");
+        connection = c;
+        init_socket_events();
+    });
+    server.listen(PORT, HOST, function() {
+        post("GUI listening on port " + PORT + " on host " + HOST);
+        spawn_pd();
     });
-    server.listen(PORT, HOST);
-    console.log("listening on port " + PORT + " on host " + HOST);
-    socket = server;
 }
 
-exports.create_server= create_server;
+exports.connect_as_server = connect_as_server;
 
 // Add a 'data' event handler for the client socket
 // data parameter is what the server sent to this socket
@@ -1031,12 +1051,12 @@ function init_socket_events () {
         }
     };
 
-    socket.on("data", perfect_parser);
+    connection.on("data", perfect_parser);
 
     // Add a "close" event handler for the socket
-    socket.on("close", function() {
+    connection.on("close", function() {
         //console.log("Connection closed");
-        //socket.destroy();
+        //connection.destroy();
         nw_app_quit(); // set a timeout here if you need to debug
     });
 }
@@ -1049,7 +1069,7 @@ function pdsend() {
     // some reason.  But it doesn't look like it makes that much
     // of a difference
     var string = Array.prototype.join.call(arguments, " ");
-    socket.write(string + ";");
+    connection.write(string + ";");
     // reprint the outgoing string to the pdwindow
     //post(string + ";", "red");
 }
diff --git a/pd/nw/todo.txt b/pd/nw/todo.txt
index b10a98783..69cfa5fa3 100644
--- a/pd/nw/todo.txt
+++ b/pd/nw/todo.txt
@@ -335,6 +335,7 @@ Everything else: (A [x] means we've fixed it)
     does _not_ send a key to Pd. Since <ctrl-v> is bound to "paste" and
     <ctrl-h> isn't bound to anything, that may somehow be causing an
     inconsistency.
+[ ] make GUI server try again if the port is already in use
 
 Crashers
 --------
-- 
GitLab