/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* Part of the Processing project - http://processing.org Copyright (c) 2012-14 The Processing Foundation Copyright (c) 2011-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package processing.app; import java.awt.EventQueue; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import processing.core.PApplet; /** * Class that handles a small server that prevents multiple instances of * Processing from running simultaneously. If there's already an instance * running, it'll handle opening a new empty sketch, or any files that had * been passed in on the command line. */ public class SingleInstance { static final String SERVER_PORT = "instance_server.port"; static final String SERVER_KEY = "instance_server.key"; /** * Returns true if there's an instance of Processing already running. * Will not return true unless this code was able to successfully * contact the already running instance to have it launch sketches. * @param filename Path to the PDE file that was opened, null if double-clicked * @return true if successfully launched on the other instance */ static boolean alreadyRunning(String[] args) { return Preferences.get(SERVER_PORT) != null && sendArguments(args); } static void startServer(final Base base) { try { Messages.log("Opening SingleInstance socket"); final ServerSocket ss = new ServerSocket(0, 0, InetAddress.getLoopbackAddress()); Preferences.set(SERVER_PORT, "" + ss.getLocalPort()); final String key = "" + Math.random(); Preferences.set(SERVER_KEY, key); Preferences.save(); Messages.log("Starting SingleInstance thread"); new Thread(new Runnable() { public void run() { while (true) { try { Socket s = ss.accept(); // blocks (sleeps) until connection final BufferedReader reader = PApplet.createReader(s.getInputStream()); String receivedKey = reader.readLine(); Messages.log(this, "key is " + key + ", received is " + receivedKey); if (key.equals(receivedKey)) { EventQueue.invokeLater(new Runnable() { public void run() { try { Messages.log(this, "about to read line"); String path = reader.readLine(); if (path == null) { // Because an attempt was made to launch the PDE again, // throw the user a bone by at least opening a new // Untitled window for them. Messages.log(this, "opening new empty sketch"); // platform.base.handleNew(); base.handleNew(); } else { // loop through the sketches that were passed in do { Messages.log(this, "calling open with " + path); // platform.base.handleOpen(filename); base.handleOpen(path); path = reader.readLine(); } while (path != null); } } catch (IOException e) { e.printStackTrace(); } } }); } else { Messages.log(this, "keys do not match"); } // } } catch (IOException e) { Messages.loge("SingleInstance error while listening", e); } } } }, "SingleInstance Server").start(); } catch (IOException e) { Messages.loge("Could not create single instance server.", e); } } static boolean sendArguments(String[] args) { //, long timeout) { try { Messages.log("Checking to see if Processing is already running"); int port = Preferences.getInteger(SERVER_PORT); String key = Preferences.get(SERVER_KEY); Socket socket = null; try { socket = new Socket(InetAddress.getLoopbackAddress(), port); } catch (Exception ignored) { } if (socket != null) { Messages.log("Processing is already running, sending command line"); PrintWriter writer = PApplet.createWriter(socket.getOutputStream()); writer.println(key); for (String arg : args) { writer.println(arg); } writer.flush(); writer.close(); return true; } } catch (IOException e) { Messages.loge("Error sending commands to other instance", e); } Messages.log("Processing is not already running (or could not connect)"); return false; } }