Write Processing sketches in Python
-
-
-
+
+
+
+
+
+
+
-
-
+
+
@@ -62,7 +66,7 @@
-
+
@@ -72,10 +76,10 @@
file="runtime/src/jycessing/build.properties"
comment="Python mode build number">
-
+
-
-
+
+
@@ -90,7 +94,7 @@
-
+
@@ -104,7 +108,7 @@
-
+
-
-
+
+
-
+
-
+
@@ -149,14 +153,14 @@
-
-
+
+
@@ -164,9 +168,9 @@
+ file="${processing.dir}/core/library/gluegen-rt-natives-${natives.platform}.jar"/>
+ file="${processing.dir}/core/library/jogl-all-natives-${natives.platform}.jar"/>
@@ -177,7 +181,7 @@
-
+
@@ -193,40 +197,40 @@
-
+
-
+
-
+
-
+
-
+ targetfile="${processing-video.dir}/library/video.jar">
+
+ depends="check-video-needs-build"
+ unless="video-is-uptodate">
-
-
+
+
@@ -234,7 +238,7 @@
-
+
@@ -244,7 +248,7 @@
-
+
-
@@ -420,9 +417,9 @@
-
-
@@ -435,10 +432,10 @@
-
+
-
@@ -486,7 +483,7 @@
@@ -502,14 +499,14 @@
@@ -534,21 +531,21 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mode/mode.properties b/mode/mode.properties
index 87e5ee02..9274ee27 100644
--- a/mode/mode.properties
+++ b/mode/mode.properties
@@ -1,11 +1,11 @@
-name = Python Mode for Processing 3
+name = Python Mode for Processing 4
authorList = [Jonathan Feinberg](http://MrFeinberg.com/)
url = https://github.com/jdf/processing.py
-sentence = Write Processing sketches in Python.
+sentence = Write Processing 4 sketches in Python.
paragraph =
version = @@version@@
prettyVersion = @@pretty-version@@
-# 3.0
-minRevision = 246
-# <3.2
+# 4.1.4 or 4.2 (additional changes made to support Python Mode)
+minRevision = 1292
+# works with any later release
maxRevision = 0
diff --git a/processing-py-test-suite.launch b/processing-py-test-suite.launch
index 7d5ac6b7..b5c2dad2 100644
--- a/processing-py-test-suite.launch
+++ b/processing-py-test-suite.launch
@@ -1,44 +1,38 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/runtime/src/jycessing/PAppletJythonDriver.java b/runtime/src/jycessing/PAppletJythonDriver.java
index b310a352..e5a4cbf7 100755
--- a/runtime/src/jycessing/PAppletJythonDriver.java
+++ b/runtime/src/jycessing/PAppletJythonDriver.java
@@ -15,21 +15,17 @@
import java.awt.Component;
import java.awt.Frame;
+import java.awt.GraphicsDevice;
import java.awt.Point;
-import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.File;
-import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -51,7 +47,6 @@
import org.python.core.PyFunction;
import org.python.core.PyIndentationError;
import org.python.core.PyInteger;
-import org.python.core.PyJavaType;
import org.python.core.PyObject;
import org.python.core.PyObjectDerived;
import org.python.core.PySet;
@@ -63,27 +58,24 @@
import org.python.core.PyUnicode;
import org.python.util.InteractiveConsole;
-import com.google.common.base.Charsets;
-import com.google.common.io.Files;
import com.jogamp.newt.opengl.GLWindow;
import jycessing.IOUtil.ResourceReader;
-import jycessing.jni.OSX;
import jycessing.mode.run.WrappedPrintStream;
import jycessing.mode.run.WrappedPrintStream.PushedOut;
+
import processing.awt.PSurfaceAWT;
import processing.core.PApplet;
import processing.core.PConstants;
import processing.core.PImage;
import processing.core.PSurface;
+import processing.core.ThinkDifferent;
import processing.event.KeyEvent;
import processing.event.MouseEvent;
-import processing.javafx.PSurfaceFX;
import processing.opengl.PGraphicsOpenGL;
import processing.opengl.PShader;
import processing.opengl.PSurfaceJOGL;
-@SuppressWarnings("serial")
public class PAppletJythonDriver extends PApplet {
public static final String C_LIKE_LOGICAL_AND_ERROR_MESSAGE =
@@ -106,6 +98,14 @@ public class PAppletJythonDriver extends PApplet {
private Field frameField;
+ static private Class> fxSurfaceClass;
+ static {
+ try {
+ // Get class object for use in dynamic instanceof calls for PSurfaceFX
+ fxSurfaceClass = Class.forName("processing.javafx.PSurfaceFX");
+ } catch (ClassNotFoundException ignored) { }
+ }
+
private PythonSketchError terminalException = null;
protected final PyStringMap builtins;
@@ -258,16 +258,13 @@ private static PythonSketchError toSketchException(Throwable t) {
if (t instanceof PythonSketchError) {
return (PythonSketchError) t;
}
- if (t instanceof PySyntaxError) {
- final PySyntaxError e = (PySyntaxError) t;
+ if (t instanceof final PySyntaxError e) {
return extractSketchErrorFromPyExceptionValue((PyTuple) e.value);
}
- if (t instanceof PyIndentationError) {
- final PyIndentationError e = (PyIndentationError) t;
+ if (t instanceof final PyIndentationError e) {
return extractSketchErrorFromPyExceptionValue((PyTuple) e.value);
}
- if (t instanceof PyException) {
- final PyException e = (PyException) t;
+ if (t instanceof final PyException e) {
final Pattern tbParse =
Pattern.compile("^\\s*File \"([^\"]+)\", line (\\d+)", Pattern.MULTILINE);
final Matcher m = tbParse.matcher(e.toString());
@@ -305,8 +302,8 @@ private static PythonSketchError extractSketchErrorFromPyExceptionValue(final Py
final PyTuple context = (PyTuple) tup.get(1);
final File file = new File((String) context.get(0));
final String fileName = file.getName();
- final int lineNumber = ((Integer) context.get(1)).intValue() - 1;
- final int column = ((Integer) context.get(2)).intValue();
+ final int lineNumber = (Integer) context.get(1) - 1;
+ final int column = (Integer) context.get(2);
if (pyMessage.startsWith("no viable alternative")) {
return noViableAlternative(file, lineNumber, column, pyMessage);
}
@@ -324,11 +321,6 @@ private static PythonSketchError extractSketchErrorFromPyExceptionValue(final Py
*
* This function takes a stab at finding such a thing, and reporting it. Otherwise, it throws a
* slightly less cryptic error message.
- *
- * @param file
- * @param line
- * @param column
- * @return
*/
private static PythonSketchError noViableAlternative(
final File file, final int lineNo, final int column, final String message) {
@@ -345,29 +337,29 @@ private static PythonSketchError noViableAlternative(
file.getName(),
lineNo,
column);
- try {
- int lineIndex = 0;
- for (final String line : Files.readLines(file, Charsets.UTF_8)) {
+ int lineIndex = 0;
+ String[] lines = PApplet.loadStrings(file);
+ if (lines != null) {
+ for (final String line : lines) {
final Matcher m = NAKED_COLOR.matcher(line);
if (m.find()) {
final String color = m.group(1);
return new PythonSketchError(
- "Did you try to name a color here? "
- + "Colors in Python mode are either strings, like '#"
- + color
- + "', or "
- + "large hex integers, like 0xFF"
- + color.toUpperCase()
- + ".",
- file.getName(),
- lineIndex,
- m.start(1));
+ "Did you try to name a color here? "
+ + "Colors in Python mode are either strings, like '#"
+ + color
+ + "', or "
+ + "large hex integers, like 0xFF"
+ + color.toUpperCase()
+ + ".",
+ file.getName(),
+ lineIndex,
+ m.start(1));
}
lineIndex++;
}
- } catch (final IOException e) {
- System.err.println("While trying to read " + file + ": " + e.getMessage());
- return defaultException;
+ } else {
+ System.err.println("Could not read " + file);
}
return defaultException;
}
@@ -422,25 +414,17 @@ public void doPrint(final String s) {
detectedPixelDensity = interp.get("__pixelDensity__").asInt();
detectedSmooth = interp.get("__smooth__").asInt() != 0;
detectedNoSmooth = interp.get("__noSmooth__").asInt() != 0;
+ detectedFullScreen = interp.get("__fullScreen__").asInt() != 0; // TODO does not work [fry 230221]
final String r = interp.get("__renderer__").asString();
- if (r.equals("JAVA2D")) {
- detectedRenderer = JAVA2D;
- } else if (r.equals("P2D")) {
- detectedRenderer = P2D;
- } else if (r.equals("P3D")) {
- detectedRenderer = P3D;
- } else if (r.equals("OPENGL")) {
- detectedRenderer = P3D;
- } else if (r.equals("FX2D")) {
- detectedRenderer = FX2D;
- } else if (r.equals("PDF")) {
- detectedRenderer = PDF;
- } else if (r.equals("SVG")) {
- detectedRenderer = SVG;
- } else if (r.equals("DXF")) {
- detectedRenderer = DXF;
- } else {
- detectedRenderer = r;
+ switch (r) {
+ case "JAVA2D" -> detectedRenderer = JAVA2D;
+ case "P2D" -> detectedRenderer = P2D;
+ case "P3D", "OPENGL" -> detectedRenderer = P3D;
+ case "FX2D" -> detectedRenderer = FX2D;
+ case "PDF" -> detectedRenderer = PDF;
+ case "SVG" -> detectedRenderer = SVG;
+ case "DXF" -> detectedRenderer = DXF;
+ default -> detectedRenderer = r;
}
processedStaticSketch = interp.get("__cleaned_sketch__");
}
@@ -482,8 +466,7 @@ protected PSurface initSurface() {
}
s.setTitle(pySketchPath.getFileName().toString().replaceAll("\\..*$", ""));
- if (s instanceof PSurfaceAWT) {
- final PSurfaceAWT surf = (PSurfaceAWT) s;
+ if (s instanceof final PSurfaceAWT surf) {
final Component c = (Component) surf.getNative();
c.addComponentListener(
new ComponentAdapter() {
@@ -492,8 +475,7 @@ public void componentHidden(final ComponentEvent e) {
finishedLatch.countDown();
}
});
- } else if (s instanceof PSurfaceJOGL) {
- final PSurfaceJOGL surf = (PSurfaceJOGL) s;
+ } else if (s instanceof final PSurfaceJOGL surf) {
final GLWindow win = (GLWindow) surf.getNative();
win.addWindowListener(
new com.jogamp.newt.event.WindowAdapter() {
@@ -502,12 +484,12 @@ public void windowDestroyed(final com.jogamp.newt.event.WindowEvent arg0) {
finishedLatch.countDown();
}
});
- } else if (s instanceof PSurfaceFX) {
+ } else if (fxSurfaceClass != null && fxSurfaceClass.isInstance(s)) {
System.err.println("I don't know how to watch FX2D windows for close.");
}
final PyObject pyG;
- if (g instanceof PGraphicsOpenGL) {
+ if (g instanceof final PGraphicsOpenGL glGraphics) {
/*
* The name "camera" in PGraphicsOpenGL can refer to either a PMatrix3D field
* or a couple of functions of that name. Unfortunately, Python only has one namespace,
@@ -528,7 +510,6 @@ public void windowDestroyed(final com.jogamp.newt.event.WindowEvent arg0) {
* # read back what we did
* print g.cameraMatrix.m02
*/
- final PGraphicsOpenGL glGraphics = (PGraphicsOpenGL) g;
final PyObject cameraMatrix = Py.java2py(glGraphics.camera);
final PyObject cameraInvMatrix = Py.java2py(glGraphics.cameraInv);
final PyObject modelviewMatrix = Py.java2py(glGraphics.modelview);
@@ -592,16 +573,12 @@ public void method(final String name) {
*
* @param obj either a {@link PyString} or a {@link PyFunction} to run in a thread.
*/
+ @SuppressWarnings("unused")
public void thread(final Object obj) {
if (obj instanceof String) {
super.thread((String) obj);
} else if (obj instanceof PyFunction) {
- new Thread() {
- @Override
- public void run() {
- ((PyFunction) obj).__call__();
- }
- }.start();
+ new Thread(() -> ((PyFunction) obj).__call__()).start();
}
}
@@ -627,63 +604,63 @@ public void findSketchMethods() throws PythonSketchError {
setupMeth = interp.get("setup");
mousePressedFunc =
- new EventFunction("mousePressed") {
- @Override
- protected void callSuper(final MouseEvent event) {
- PAppletJythonDriver.super.mousePressed(event);
- }
- };
+ new EventFunction<>("mousePressed") {
+ @Override
+ protected void callSuper(final MouseEvent event) {
+ PAppletJythonDriver.super.mousePressed(event);
+ }
+ };
mouseClickedFunc =
- new EventFunction("mouseClicked") {
- @Override
- protected void callSuper(final MouseEvent event) {
- PAppletJythonDriver.super.mouseClicked(event);
- }
- };
+ new EventFunction<>("mouseClicked") {
+ @Override
+ protected void callSuper(final MouseEvent event) {
+ PAppletJythonDriver.super.mouseClicked(event);
+ }
+ };
mouseMovedFunc =
- new EventFunction("mouseMoved") {
- @Override
- protected void callSuper(final MouseEvent event) {
- PAppletJythonDriver.super.mouseMoved(event);
- }
- };
+ new EventFunction<>("mouseMoved") {
+ @Override
+ protected void callSuper(final MouseEvent event) {
+ PAppletJythonDriver.super.mouseMoved(event);
+ }
+ };
mouseReleasedFunc =
- new EventFunction("mouseReleased") {
- @Override
- protected void callSuper(final MouseEvent event) {
- PAppletJythonDriver.super.mouseReleased(event);
- }
- };
+ new EventFunction<>("mouseReleased") {
+ @Override
+ protected void callSuper(final MouseEvent event) {
+ PAppletJythonDriver.super.mouseReleased(event);
+ }
+ };
mouseDraggedFunc =
- new EventFunction("mouseDragged") {
- @Override
- protected void callSuper(final MouseEvent event) {
- PAppletJythonDriver.super.mouseDragged(event);
- }
- };
+ new EventFunction<>("mouseDragged") {
+ @Override
+ protected void callSuper(final MouseEvent event) {
+ PAppletJythonDriver.super.mouseDragged(event);
+ }
+ };
// keyPressed is renamed to __keyPressed__ by the preprocessor.
keyPressedFunc =
- new EventFunction("__keyPressed__") {
- @Override
- protected void callSuper(final KeyEvent event) {
- PAppletJythonDriver.super.keyPressed(event);
- }
- };
+ new EventFunction<>("__keyPressed__") {
+ @Override
+ protected void callSuper(final KeyEvent event) {
+ PAppletJythonDriver.super.keyPressed(event);
+ }
+ };
keyReleasedFunc =
- new EventFunction("keyReleased") {
- @Override
- protected void callSuper(final KeyEvent event) {
- PAppletJythonDriver.super.keyReleased(event);
- }
- };
+ new EventFunction<>("keyReleased") {
+ @Override
+ protected void callSuper(final KeyEvent event) {
+ PAppletJythonDriver.super.keyReleased(event);
+ }
+ };
keyTypedFunc =
- new EventFunction("keyTyped") {
- @Override
- protected void callSuper(final KeyEvent event) {
- PAppletJythonDriver.super.keyTyped(event);
- }
- };
+ new EventFunction<>("keyTyped") {
+ @Override
+ protected void callSuper(final KeyEvent event) {
+ PAppletJythonDriver.super.keyTyped(event);
+ }
+ };
settingsMeth = interp.get("settings");
stopMeth = interp.get("stop");
@@ -730,62 +707,44 @@ public PyObject __call__(final PyObject[] args, final String[] kws) {
PyObject meth;
if ((meth = interp.get("noteOn")) != null) {
switch (argCount(meth)) {
- default:
- throw new RuntimeException(
- "only noteOn(channel, pitch, velocity) or "
- + "noteOn(channel, pitch, velocity, timestamp, bus_name) "
- + "are supported by Python Mode");
- case 3:
- noteOn3Meth = meth;
- break;
- case 5:
- noteOn5Meth = meth;
+ default -> throw new RuntimeException(
+ "only noteOn(channel, pitch, velocity) or "
+ + "noteOn(channel, pitch, velocity, timestamp, bus_name) "
+ + "are supported by Python Mode");
+ case 3 -> noteOn3Meth = meth;
+ case 5 -> noteOn5Meth = meth;
}
}
if ((meth = interp.get("noteOff")) != null) {
switch (argCount(meth)) {
- case 1:
- throw new RuntimeException(
- "only noteOff(channel, pitch, velocity) or "
- + "noteOff(channel, pitch, velocity, timestamp, bus_name) "
- + "are supported by Python Mode");
- case 3:
- noteOff3Meth = meth;
- break;
- case 5:
- noteOff5Meth = meth;
+ case 1 -> throw new RuntimeException(
+ "only noteOff(channel, pitch, velocity) or "
+ + "noteOff(channel, pitch, velocity, timestamp, bus_name) "
+ + "are supported by Python Mode");
+ case 3 -> noteOff3Meth = meth;
+ case 5 -> noteOff5Meth = meth;
}
}
if ((meth = interp.get("controllerChange")) != null) {
switch (argCount(meth)) {
- case 1:
- throw new RuntimeException(
- "only controllerChange(channel, pitch, velocity) or "
- + "controllerChange(channel, pitch, velocity, timestamp, bus_name) "
- + "are supported by Python Mode");
- case 3:
- controllerChange3Meth = meth;
- break;
- case 5:
- controllerChange5Meth = meth;
+ case 1 -> throw new RuntimeException(
+ "only controllerChange(channel, pitch, velocity) or "
+ + "controllerChange(channel, pitch, velocity, timestamp, bus_name) "
+ + "are supported by Python Mode");
+ case 3 -> controllerChange3Meth = meth;
+ case 5 -> controllerChange5Meth = meth;
}
}
if ((meth = interp.get("rawMidi")) != null) {
switch (argCount(meth)) {
- case 1:
- rawMidi1Meth = meth;
- break;
- case 3:
- rawMidi3Meth = meth;
+ case 1 -> rawMidi1Meth = meth;
+ case 3 -> rawMidi3Meth = meth;
}
}
if ((meth = interp.get("midiMessage")) != null) {
switch (argCount(meth)) {
- case 1:
- midiMessage1Meth = meth;
- break;
- case 3:
- midiMessage3Meth = meth;
+ case 1 -> midiMessage1Meth = meth;
+ case 3 -> midiMessage3Meth = meth;
}
}
@@ -883,31 +842,34 @@ private void wrapMouseVariables() {
public void start() {
// I want to quit on runtime exceptions.
// Processing just sits there by default.
- Thread.setDefaultUncaughtExceptionHandler(
- new UncaughtExceptionHandler() {
- @Override
- public void uncaughtException(final Thread t, final Throwable e) {
- terminalException = toSketchException(e);
- try {
- handleMethods("dispose");
- } catch (final Exception noop) {
- // give up
- }
- finishedLatch.countDown();
- }
- });
+ Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
+ terminalException = toSketchException(e);
+ try {
+ handleMethods("dispose");
+ } catch (final Exception noop) {
+ // give up
+ }
+ finishedLatch.countDown();
+ });
super.start();
}
- private void bringToFront() {
- if (PApplet.platform == PConstants.MACOSX) {
- OSX.bringToFront();
- }
- }
public void runAndBlock(final String[] args) throws PythonSketchError {
PApplet.runSketch(args, this);
- bringToFront();
+
+ // bring the sketch to the front
+ if (PApplet.platform == PConstants.MACOS) {
+ ThinkDifferent.activateIgnoringOtherApps();
+ }
+
+ if (detectedFullScreen) {
+ if (surface instanceof PSurfaceAWT) {
+ Frame frame = ((PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
+ GraphicsDevice displayDevice = frame.getGraphicsConfiguration().getDevice();
+ displayDevice.setFullScreenWindow(frame);
+ }
+ }
try {
finishedLatch.await();
@@ -934,7 +896,9 @@ public void runAndBlock(final String[] args) throws PythonSketchError {
maybeShutdownSoundEngine();
Thread.setDefaultUncaughtExceptionHandler(null);
- if (PApplet.platform == PConstants.MACOSX && Arrays.asList(args).contains("fullScreen")) {
+
+ /*
+ if (PApplet.platform == PConstants.MACOS && Arrays.asList(args).contains("fullScreen")) {
// Frame should be OS-X fullscreen, and it won't stop being that unless the jvm
// exits or we explicitly tell it to minimize.
// (If it's disposed, it'll leave a gray blank window behind it.)
@@ -949,7 +913,8 @@ public void runAndBlock(final String[] args) throws PythonSketchError {
}
}
}
- if (surface instanceof PSurfaceFX) {
+ */
+ if (fxSurfaceClass != null && fxSurfaceClass.isInstance(surface)) {
// Sadly, JavaFX is an abomination, and there's no way to run an FX sketch more than once,
// so we must actually exit.
Runner.log("JavaFX requires SketchRunner to terminate. Farewell!");
@@ -987,24 +952,6 @@ private void maybeShutdownSoundEngine() {
}
}
- /**
- * Use reflection to call
- * com.apple.eawt.Application.getApplication().requestToggleFullScreen(window);
- */
- private static void macosxFullScreenToggle(final Window window) {
- try {
- final Class> appClass = Class.forName("com.apple.eawt.Application");
- final Method getAppMethod = appClass.getMethod("getApplication");
- final Object app = getAppMethod.invoke(null);
- final Method requestMethod = appClass.getMethod("requestToggleFullScreen", Window.class);
- requestMethod.invoke(app, window);
- } catch (final ClassNotFoundException cnfe) {
- // ignored
- } catch (final Exception e) {
- e.printStackTrace();
- }
- }
-
/**
* Permit the punning use of set() by mucking with the builtin "set" Type. If you call it with 3
* arguments, it acts like the Processing set(x, y, whatever) method. If you call it with 0 or 1
@@ -1017,7 +964,7 @@ private void setSet() {
new PyType(PyType.TYPE) {
{
builtin = true;
- init(PySet.class, new HashSet());
+ init(PySet.class, new HashSet<>());
invalidateMethodCache();
}
@@ -1135,14 +1082,17 @@ public int lerpColor(final int c1, final int c2, final float amt) {
* invoke the fill(float) method, unless we provide a long int
* version to catch it.
*/
+ @SuppressWarnings("unused")
public void fill(final long argb) {
fill((int) (argb & 0xFFFFFFFF));
}
+ @SuppressWarnings("unused")
public void stroke(final long argb) {
stroke((int) (argb & 0xFFFFFFFF));
}
+ @SuppressWarnings("unused")
public void background(final long argb) {
background((int) (argb & 0xFFFFFFFF));
}
@@ -1151,14 +1101,17 @@ public void background(final long argb) {
* Python can't parse web colors, so we let the user do '#RRGGBB'
* as a string.
*/
+ @SuppressWarnings("unused")
public void fill(final String argbSpec) {
fill(parseColorSpec(argbSpec));
}
+ @SuppressWarnings("unused")
public void stroke(final String argbSpec) {
stroke(parseColorSpec(argbSpec));
}
+ @SuppressWarnings("unused")
public void background(final String argbSpec) {
background(parseColorSpec(argbSpec));
}
diff --git a/runtime/src/jycessing/Runner.java b/runtime/src/jycessing/Runner.java
index 29d3b712..8fac8e0d 100755
--- a/runtime/src/jycessing/Runner.java
+++ b/runtime/src/jycessing/Runner.java
@@ -53,7 +53,7 @@ public class Runner {
static {
final int archBits = Integer.parseInt(System.getProperty("sun.arch.data.model"));
- if (PApplet.platform == PConstants.MACOSX) {
+ if (PApplet.platform == PConstants.MACOS) {
ARCH = "macosx" + archBits;
} else if (PApplet.platform == PConstants.WINDOWS) {
ARCH = "macosx" + archBits;
@@ -89,7 +89,7 @@ static void log(final Object... objs) {
return;
}
for (final Object o : objs) {
- System.err.print(String.valueOf(o));
+ System.err.print(o);
}
System.err.println();
}
@@ -337,7 +337,7 @@ public static synchronized void runSketchBlocking(
interp.exec("import sys\n");
- // Add all of the sketch's requested sys.path entries, and add all jar
+ // Add all the sketch's requested sys.path entries, and add all jar
// files found there, recursively.
final Set userLibs = new TreeSet<>();
for (final File entry : sketch.getPathEntries()) {
@@ -351,7 +351,7 @@ public static synchronized void runSketchBlocking(
new LibraryImporter(libDirs, interp);
if (sketch.getLibraryPolicy() == LibraryPolicy.PROMISCUOUS) {
- log("Promiscusouly adding all libraries in " + libDirs);
+ log("Promiscuously adding all libraries in " + libDirs);
// Recursively search the "libraries" directory for jar files and
// directories containing dynamic libraries.
final Set libs = new HashSet<>();
diff --git a/runtime/src/jycessing/build.properties b/runtime/src/jycessing/build.properties
index 1a22f6ed..acd55828 100644
--- a/runtime/src/jycessing/build.properties
+++ b/runtime/src/jycessing/build.properties
@@ -1,5 +1,5 @@
#Python mode build number
-#Tue, 19 May 2020 13:23:09 -0400
+#Sat, 22 Jan 2022 11:36:58 -0500
-build.date=2020/05/19 13\:23
-build.number=3063
+build.date=2022/01/22 11\:36
+build.number=4001
diff --git a/runtime/src/jycessing/jni/OSX.java b/runtime/src/jycessing/jni/OSX.java
deleted file mode 100644
index aeb2ebfb..00000000
--- a/runtime/src/jycessing/jni/OSX.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package jycessing.jni;
-
-import jycessing.mode.PythonMode;
-import processing.core.PApplet;
-import processing.core.PConstants;
-
-public class OSX {
- private static volatile boolean didLoad = false;
-
- public static void bringToFront() {
- if (!didLoad && (PApplet.platform == PConstants.MACOSX)) {
- try {
- System.loadLibrary("jniosx");
- didLoad = true;
- } catch (final UnsatisfiedLinkError err) {
- System.err.println("Hmm. Can't load native code to bring window to front.");
- }
- }
- if (didLoad) {
- activateIgnoringOtherApps();
- }
- }
-
- public static void bringToFront(PythonMode mode) {
- if (!didLoad && (PApplet.platform == PConstants.MACOSX)) {
- String path = null;
- try {
- path = mode.getContentFile("mode").getAbsolutePath() + "/libjniosx.dylib";
- System.load(path);
- didLoad = true;
- } catch (final UnsatisfiedLinkError err) {
- System.err.println("Hmm. Can't load native code to bring window to front using the absolute path: " + path + ".");
- }
- }
- bringToFront();
- }
-
- private static native void activateIgnoringOtherApps();
-}
diff --git a/runtime/src/jycessing/jni/jniosx/jniosx/jniosx.m b/runtime/src/jycessing/jni/jniosx/jniosx/jniosx.m
deleted file mode 100644
index dd58aae4..00000000
--- a/runtime/src/jycessing/jni/jniosx/jniosx/jniosx.m
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "jycessing_jni_OSX.h"
-
-#import "AppKit/AppKit.h"
-
-JNIEXPORT void JNICALL Java_jycessing_jni_OSX_activateIgnoringOtherApps
-(JNIEnv *env, jclass klass) {
- [NSApp activateIgnoringOtherApps:true];
-}
diff --git a/runtime/src/jycessing/jni/jycessing_jni_OSX.h b/runtime/src/jycessing/jni/jycessing_jni_OSX.h
deleted file mode 100644
index 79fa36f5..00000000
--- a/runtime/src/jycessing/jni/jycessing_jni_OSX.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include
-/* Header for class jycessing_jni_OSX */
-
-#ifndef _Included_jycessing_jni_OSX
-#define _Included_jycessing_jni_OSX
-#ifdef __cplusplus
-extern "C" {
-#endif
-/*
- * Class: jycessing_jni_OSX
- * Method: activateIgnoringOtherApps
- * Signature: ()V
- */
-JNIEXPORT void JNICALL Java_jycessing_jni_OSX_activateIgnoringOtherApps
- (JNIEnv *, jclass);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/runtime/src/jycessing/mode/PyEditor.java b/runtime/src/jycessing/mode/PyEditor.java
index 7bd824b8..cfdfb99a 100644
--- a/runtime/src/jycessing/mode/PyEditor.java
+++ b/runtime/src/jycessing/mode/PyEditor.java
@@ -2,13 +2,13 @@
import java.awt.Point;
import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.UUID;
@@ -21,8 +21,7 @@
import jycessing.DisplayType;
import jycessing.IOUtil;
-import jycessing.jni.OSX;
-import jycessing.mode.export.ExportDialog;
+import jycessing.mode.export.Exporter;
import jycessing.mode.run.PdeSketch;
import jycessing.mode.run.PdeSketch.LocationType;
import jycessing.mode.run.SketchService;
@@ -45,11 +44,12 @@
import processing.app.ui.EditorException;
import processing.app.ui.EditorState;
import processing.app.ui.EditorToolbar;
+import processing.app.ui.ExportPrompt;
import processing.app.ui.Toolkit;
import processing.core.PApplet;
import processing.core.PConstants;
+import processing.core.ThinkDifferent;
-@SuppressWarnings("serial")
public class PyEditor extends Editor {
@SuppressWarnings("unused")
@@ -108,7 +108,7 @@ public void windowClosing(final WindowEvent e) {
@Override
protected JEditTextArea createTextArea() {
- return new PdeTextArea(new PdeTextAreaDefaults(mode), new PyInputHandler(this), this);
+ return new PdeTextArea(new PdeTextAreaDefaults(), new PyInputHandler(this), this);
}
public String getId() {
@@ -116,14 +116,11 @@ public String getId() {
}
private MouseWheelListener createHorizontalScrollListener() {
- return new MouseWheelListener() {
- @Override
- public void mouseWheelMoved(final MouseWheelEvent e) {
- if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL && e.isShiftDown()) {
- final int current = textarea.getHorizontalScrollPosition();
- final int delta = e.getUnitsToScroll() * 6;
- textarea.setHorizontalScrollPosition(current + delta);
- }
+ return e -> {
+ if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL && e.isShiftDown()) {
+ final int current = textarea.getHorizontalScrollPosition();
+ final int delta = e.getUnitsToScroll() * 6;
+ textarea.setHorizontalScrollPosition(current + delta);
}
};
}
@@ -153,7 +150,7 @@ private void cleanupTempSketch() {
log("Deleted " + tempSketch);
assert (!tempSketch.toFile().exists());
} catch (final IOException e) {
- System.err.println(e);
+ e.printStackTrace();
}
}
tempSketch = null;
@@ -166,12 +163,7 @@ public JMenu buildFileMenu() {
final String appTitle = Language.text("Export Application");
final JMenuItem exportApplication = Toolkit.newJMenuItem(appTitle, 'E');
exportApplication.addActionListener(
- new ActionListener() {
- @Override
- public void actionPerformed(final ActionEvent e) {
- handleExportApplication();
- }
- });
+ e -> handleExportApplication());
return buildFileMenu(new JMenuItem[] {exportApplication});
}
@@ -227,31 +219,13 @@ public void actionPerformed(final ActionEvent e) {
@Override
public JMenu buildSketchMenu() {
final JMenuItem runItem = Toolkit.newJMenuItem(Language.text("toolbar.run"), 'R');
- runItem.addActionListener(
- new ActionListener() {
- @Override
- public void actionPerformed(final ActionEvent e) {
- handleRun();
- }
- });
+ runItem.addActionListener(e -> handleRun());
final JMenuItem presentItem = Toolkit.newJMenuItemShift(Language.text("toolbar.present"), 'R');
- presentItem.addActionListener(
- new ActionListener() {
- @Override
- public void actionPerformed(final ActionEvent e) {
- handlePresent();
- }
- });
+ presentItem.addActionListener(e -> handlePresent());
final JMenuItem stopItem = new JMenuItem(Language.text("toolbar.stop"));
- stopItem.addActionListener(
- new ActionListener() {
- @Override
- public void actionPerformed(final ActionEvent e) {
- handleStop();
- }
- });
+ stopItem.addActionListener(e -> handleStop());
return buildSketchMenu(new JMenuItem[] {runItem, presentItem, stopItem});
}
@@ -288,7 +262,8 @@ public void handleExportApplication() {
}
}
- new ExportDialog(this, sketch).go();
+ //new ExportDialog(this, sketch).go();
+ new ExportPrompt(this, () -> new Exporter(PyEditor.this).export());
}
public File getModeContentFile(final String filename) {
@@ -304,12 +279,11 @@ public File getSplashFile() {
*
* @return a new directory containing a saved version of the current (presumably modified) sketch
* code.
- * @throws IOException
*/
private Path createTempSketch() throws IOException {
final Path tmp = Files.createTempDirectory(sketch.getName());
for (final SketchCode code : sketch.getCode()) {
- Files.write(tmp.resolve(code.getFileName()), code.getProgram().getBytes("utf-8"));
+ Files.write(tmp.resolve(code.getFileName()), code.getProgram().getBytes(StandardCharsets.UTF_8));
}
return tmp;
}
@@ -353,8 +327,8 @@ private void runSketch(final DisplayType displayType) {
}
private void bringToFront() {
- if (PApplet.platform == PConstants.MACOSX) {
- OSX.bringToFront(pyMode);
+ if (PApplet.platform == PConstants.MACOS) {
+ ThinkDifferent.activateIgnoringOtherApps();
}
}
diff --git a/runtime/src/jycessing/mode/export/Arch.java b/runtime/src/jycessing/mode/export/Arch.java
deleted file mode 100644
index 122cf781..00000000
--- a/runtime/src/jycessing/mode/export/Arch.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package jycessing.mode.export;
-
-/**
- * The architecture of the platform we're exporting to. (The "bits" field is necessary because the
- * processing Library API uses magic integers for architecture.)
- */
-public enum Arch {
- X86(32),
- AMD64(64);
-
- public final int bits;
-
- Arch(final int bits) {
- this.bits = bits;
- }
-}
diff --git a/runtime/src/jycessing/mode/export/ExportDialog.java b/runtime/src/jycessing/mode/export/ExportDialog.java
deleted file mode 100644
index c92ec1aa..00000000
--- a/runtime/src/jycessing/mode/export/ExportDialog.java
+++ /dev/null
@@ -1,389 +0,0 @@
-package jycessing.mode.export;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Rectangle;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.io.File;
-
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.JCheckBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.SwingConstants;
-import javax.swing.border.BevelBorder;
-import javax.swing.border.EmptyBorder;
-import javax.swing.border.TitledBorder;
-
-import jycessing.mode.PyEditor;
-import jycessing.mode.PythonMode;
-import processing.app.Platform;
-import processing.app.Preferences;
-import processing.app.Sketch;
-import processing.app.ui.ColorChooser;
-
-/**
- * This is the export window that pops up when the user clicks [=>]. It tries to look as much as
- * possible like java mode's exporter. Rather than passing the options they select directly to
- * Exporter, it sets them in their user preferences, which Exporter and the various Export classes
- * reference later.
- */
-@SuppressWarnings("serial")
-public class ExportDialog extends JDialog {
-
- @SuppressWarnings("unused")
- private static void log(final String msg) {
- if (PythonMode.VERBOSE) {
- System.err.println(ExportDialog.class.getSimpleName() + ": " + msg);
- }
- }
-
- private final Sketch sketch;
- private final PyEditor editor;
- private final JOptionPane optionPane;
-
- public ExportDialog(final PyEditor editor, final Sketch sketch) {
- super(editor, "Export Application", true);
-
- this.editor = editor;
- this.sketch = sketch;
-
- log("Setting up export dialog");
-
- final JPanel center = createCenterPanel();
-
- final JPanel platforms = createPlatformsPanel();
- center.add(platforms);
-
- final JPanel present = createPresentPanel();
- center.add(present);
-
- final JPanel embed = createEmbedJavaPanel(platforms.getPreferredSize().width);
- center.add(embed);
-
- // I haven't tested this on a Mac yet
- if (Platform.isMacOS()) {
- final JPanel signingProblems = createMacSigningWarning(platforms.getPreferredSize().width);
- center.add(signingProblems);
- }
-
- final String[] options = {"Export", "Cancel"};
- optionPane =
- new JOptionPane(
- center,
- JOptionPane.PLAIN_MESSAGE,
- JOptionPane.YES_NO_OPTION,
- null,
- options,
- options[0]);
-
- this.setContentPane(optionPane);
- optionPane.addPropertyChangeListener(
- new PropertyChangeListener() {
- @Override
- public void propertyChange(final PropertyChangeEvent e) {
- final String prop = e.getPropertyName();
-
- if (isVisible()
- && (e.getSource() == optionPane)
- && (prop.equals(JOptionPane.VALUE_PROPERTY))) {
- setVisible(false);
- }
- }
- });
- this.pack();
- this.setResizable(false);
-
- final Rectangle bounds = editor.getBounds();
- final Dimension size = this.getSize();
- this.setLocation(
- bounds.x + (bounds.width - size.width) / 2, bounds.y + (bounds.height - size.height) / 2);
- }
-
- public void go() {
- log("Launching export dialog");
-
- this.setVisible(true);
-
- // Wait until they click "Export" or "Cancel"
- final Object value = optionPane.getValue();
-
- if (value.equals("Export")) {
- new Exporter(editor, sketch).export();
- } else {
- editor.statusNotice("Export to Application Cancelled");
- }
- }
-
- private JPanel createCenterPanel() {
- final JPanel panel = new JPanel();
- panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
- panel.add(Box.createVerticalStrut(6));
- final String line1 = "Export to Application creates double-clickable,";
- final String line2 = "standalone applications for the selected plaforms.";
- final JLabel label1 = new JLabel(line1, SwingConstants.CENTER);
- final JLabel label2 = new JLabel(line2, SwingConstants.CENTER);
- label1.setAlignmentX(Component.LEFT_ALIGNMENT);
- label2.setAlignmentX(Component.LEFT_ALIGNMENT);
- panel.add(label1);
- panel.add(label2);
- panel.add(Box.createVerticalStrut(12));
- return panel;
- }
-
- private JPanel createPlatformsPanel() {
- final JCheckBox windowsButton = new JCheckBox("Windows");
- windowsButton.setSelected(Preferences.getBoolean("export.application.platform.windows"));
- windowsButton.addItemListener(
- new ItemListener() {
- @Override
- public void itemStateChanged(final ItemEvent e) {
- Preferences.setBoolean(
- "export.application.platform.windows", windowsButton.isSelected());
- }
- });
-
- final JCheckBox macosxButton = new JCheckBox("Mac OS X");
- macosxButton.setSelected(Preferences.getBoolean("export.application.platform.macosx"));
- macosxButton.addItemListener(
- new ItemListener() {
- @Override
- public void itemStateChanged(final ItemEvent e) {
- Preferences.setBoolean("export.application.platform.macosx", macosxButton.isSelected());
- }
- });
-
- final JCheckBox linuxButton = new JCheckBox("Linux");
- linuxButton.setSelected(Preferences.getBoolean("export.application.platform.linux"));
- linuxButton.addItemListener(
- new ItemListener() {
- @Override
- public void itemStateChanged(final ItemEvent e) {
- Preferences.setBoolean("export.application.platform.linux", linuxButton.isSelected());
- }
- });
-
- final JPanel platformPanel = new JPanel();
- platformPanel.add(windowsButton);
- platformPanel.add(Box.createHorizontalStrut(6));
- platformPanel.add(macosxButton);
- platformPanel.add(Box.createHorizontalStrut(6));
- platformPanel.add(linuxButton);
- platformPanel.setBorder(new TitledBorder("Platforms"));
- platformPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
- return platformPanel;
- }
-
- private JPanel createPresentPanel() {
- final JPanel presentPanel = new JPanel();
- presentPanel.setLayout(new BoxLayout(presentPanel, BoxLayout.Y_AXIS));
-
- final JCheckBox showStopButton = new JCheckBox("Show a Stop button");
- showStopButton.setSelected(Preferences.getBoolean("export.application.stop"));
- showStopButton.addItemListener(
- new ItemListener() {
- @Override
- public void itemStateChanged(final ItemEvent e) {
- Preferences.setBoolean("export.application.stop", showStopButton.isSelected());
- }
- });
- showStopButton.setEnabled(Preferences.getBoolean("export.application.fullscreen"));
- showStopButton.setBorder(new EmptyBorder(3, 13, 6, 13));
-
- final JCheckBox fullScreenButton = new JCheckBox("Full Screen (Present mode)");
- fullScreenButton.setSelected(Preferences.getBoolean("export.application.fullscreen"));
- fullScreenButton.addItemListener(
- new ItemListener() {
- @Override
- public void itemStateChanged(final ItemEvent e) {
- final boolean selected = fullScreenButton.isSelected();
- Preferences.setBoolean("export.application.fullscreen", selected);
- showStopButton.setEnabled(selected);
- }
- });
- fullScreenButton.setBorder(new EmptyBorder(3, 13, 3, 13));
-
- final Box fullScreenBox = Box.createHorizontalBox();
- fullScreenBox.add(fullScreenButton);
- fullScreenBox.add(new ColorPreference("run.present.bgcolor", editor));
- fullScreenBox.add(Box.createHorizontalStrut(10));
- fullScreenBox.add(Box.createHorizontalGlue());
- presentPanel.add(fullScreenBox);
-
- final Box showStopBox = Box.createHorizontalBox();
- showStopBox.add(showStopButton);
- showStopBox.add(new ColorPreference("run.present.stop.color", editor));
- showStopBox.add(Box.createHorizontalStrut(10));
- showStopBox.add(Box.createHorizontalGlue());
- presentPanel.add(showStopBox);
-
- presentPanel.setBorder(new TitledBorder("Full Screen"));
- presentPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
-
- return presentPanel;
- }
-
- private JPanel createEmbedJavaPanel(final int divWidth) {
- final JPanel embedPanel = new JPanel();
- embedPanel.setLayout(new BoxLayout(embedPanel, BoxLayout.Y_AXIS));
-
- String platformName = null;
- if (Platform.isMacOS()) {
- platformName = "Mac OS X";
- } else if (Platform.isWindows()) {
- platformName = "Windows (" + Platform.getNativeBits() + "-bit)";
- } else if (Platform.isLinux()) {
- platformName = "Linux (" + Platform.getNativeBits() + "-bit)";
- }
-
- final boolean embed = Preferences.getBoolean("export.application.embed_java");
- final String embedWarning =
- ""
- + "Embedding Java will make the "
- + platformName
- + " application "
- + "larger, but it will be far more likely to work. "
- + "Users on other platforms will need to install Java 7.";
- final String nopeWarning =
- ""
- + "Users on all platforms will have to install the latest "
- + "version of Java 7 from http://java.com/download. "
- + "
";
- // "from java.com/download.";
- final JLabel warningLabel = new JLabel(embed ? embedWarning : nopeWarning);
- warningLabel.addMouseListener(
- new MouseAdapter() {
- @Override
- public void mousePressed(final MouseEvent event) {
- Platform.openURL("http://java.com/download");
- }
- });
- warningLabel.setBorder(new EmptyBorder(3, 13, 3, 13));
-
- final JCheckBox embedJavaButton = new JCheckBox("Embed Java for " + platformName);
- embedJavaButton.setSelected(embed);
- embedJavaButton.addItemListener(
- new ItemListener() {
- @Override
- public void itemStateChanged(final ItemEvent e) {
- final boolean selected = embedJavaButton.isSelected();
- Preferences.setBoolean("export.application.embed_java", selected);
- if (selected) {
- warningLabel.setText(embedWarning);
- } else {
- warningLabel.setText(nopeWarning);
- }
- }
- });
- embedJavaButton.setBorder(new EmptyBorder(3, 13, 3, 13));
-
- embedPanel.add(embedJavaButton);
- embedPanel.add(warningLabel);
- embedPanel.setBorder(new TitledBorder("Embed Java"));
-
- return embedPanel;
- }
-
- private JPanel createMacSigningWarning(final int divWidth) {
- final JPanel signPanel = new JPanel();
- signPanel.setLayout(new BoxLayout(signPanel, BoxLayout.Y_AXIS));
- signPanel.setBorder(new TitledBorder("Code Signing"));
-
- final StringBuilder thePain =
- new StringBuilder(
- "In recent versions of OS X, Apple has introduced the \u201CGatekeeper\u201D system, "
- + "which makes it more difficult to run applications like those exported from Processing. ");
-
- if (new File("/usr/bin/codesign_allocate").exists()) {
- thePain.append(
- "This application will be \u201Cself-signed\u201D which means that Finder may report that the "
- + "application is from an \u201Cunidentified developer\u201D. If the application will not "
- + "run, try right-clicking the app and selecting Open from the pop-up menu. Or you can visit "
- + "System Preferences \u2192 Security & Privacy and select Allow apps downloaded from: anywhere. ");
- } else {
- thePain.append(
- "Gatekeeper requires applications to be \u201Csigned\u201D, or they will be reported as damaged. "
- + "To prevent this message, install Xcode (and the Command Line Tools) from the App Store, or visit "
- + "System Preferences \u2192 Security & Privacy and select Allow apps downloaded from: anywhere. ");
- }
- thePain.append(
- "To avoid the messages entirely, manually code sign your app. "
- + "For more information: https://developer.apple.com/developer-id/");
-
- final JLabel area =
- new JLabel(
- ""
- + thePain.toString()
- + "
");
-
- area.setBorder(new EmptyBorder(3, 13, 3, 13));
- signPanel.add(area);
- signPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
-
- area.addMouseListener(
- new MouseAdapter() {
- @Override
- public void mousePressed(final MouseEvent event) {
- Platform.openURL("https://developer.apple.com/developer-id/");
- }
- });
- return signPanel;
- }
-
- static class ColorPreference extends JPanel implements ActionListener {
- ColorChooser chooser;
- String prefName;
-
- public ColorPreference(final String pref, final PyEditor editor) {
- prefName = pref;
-
- setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
- setPreferredSize(new Dimension(30, 20));
- setMaximumSize(new Dimension(30, 20));
-
- addMouseListener(
- new MouseAdapter() {
- @Override
- public void mouseReleased(final MouseEvent e) {
- final Color color = Preferences.getColor(prefName);
- chooser = new ColorChooser(editor, true, color, "Select", ColorPreference.this);
- chooser.show();
- }
- });
- }
-
- @Override
- public void paintComponent(final Graphics g) {
- g.setColor(Preferences.getColor(prefName));
- final Dimension size = getSize();
- g.fillRect(0, 0, size.width, size.height);
- }
-
- @Override
- public void actionPerformed(final ActionEvent e) {
- final Color color = chooser.getColor();
- Preferences.setColor(prefName, color);
- repaint();
- chooser.hide();
- }
- }
-}
diff --git a/runtime/src/jycessing/mode/export/ExportedSketch.java b/runtime/src/jycessing/mode/export/ExportedSketch.java
index 5b3fc216..9b69387a 100644
--- a/runtime/src/jycessing/mode/export/ExportedSketch.java
+++ b/runtime/src/jycessing/mode/export/ExportedSketch.java
@@ -2,7 +2,7 @@
import java.io.File;
import java.io.FileNotFoundException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
@@ -46,7 +46,7 @@ public ExportedSketch(final String[] args) throws Exception {
}
final List codeLines =
- Files.readAllLines(sketchPath.toPath(), Charset.forName("UTF-8"));
+ Files.readAllLines(sketchPath.toPath(), StandardCharsets.UTF_8);
final StringBuilder code = new StringBuilder();
for (final String line : codeLines) {
diff --git a/runtime/src/jycessing/mode/export/Exporter.java b/runtime/src/jycessing/mode/export/Exporter.java
index b4386b36..fd86f41d 100644
--- a/runtime/src/jycessing/mode/export/Exporter.java
+++ b/runtime/src/jycessing/mode/export/Exporter.java
@@ -9,6 +9,7 @@
import processing.app.Platform;
import processing.app.Preferences;
import processing.app.Sketch;
+import processing.app.ui.ExportPrompt;
/**
* Class that handles doing the actual exporting. All this currently does is figure out libraries
@@ -23,70 +24,38 @@ private static void log(final String msg) {
}
}
- // Architecture of the currently running Processing JRE.
- // Used to determine what platform we can embed java in.
- public static final Arch processingArch;
-
- static {
- if (Platform.getNativeBits() == Arch.X86.bits) {
- processingArch = Arch.X86;
- } else {
- processingArch = Arch.AMD64;
- }
- }
-
private final Sketch sketch;
- private final PyEditor editor; // I don't really want to pass this around but there's some
- // functionality
+ private final PyEditor editor;
- // I need
-
- public Exporter(final PyEditor editor, final Sketch sketch) {
- this.sketch = sketch;
+ public Exporter(final PyEditor editor) {
this.editor = editor;
+ this.sketch = editor.getSketch();
}
public void export() {
// Work out the libraries the sketch exports - we only need to do this once.
final Set libraries = new ImportExtractor(sketch).getLibraries();
- // Now, do this for each platform:
- if (Preferences.getBoolean("export.application.platform.linux")) {
- try {
- new LinuxExport(Arch.X86, sketch, editor, libraries).export();
- } catch (final IOException e) {
- e.printStackTrace();
- editor.statusError("Export to linux32 failed!");
- }
- try {
- new LinuxExport(Arch.AMD64, sketch, editor, libraries).export();
- } catch (final IOException e) {
- e.printStackTrace();
- editor.statusError("Export to linux64 failed!");
- }
- }
- if (Preferences.getBoolean("export.application.platform.windows")) {
- try {
- new WindowsExport(Arch.X86, sketch, editor, libraries).export();
- } catch (final IOException e) {
- e.printStackTrace();
- editor.statusError("Export to windows32 failed!");
- }
- try {
- new WindowsExport(Arch.AMD64, sketch, editor, libraries).export();
- } catch (final IOException e) {
- e.printStackTrace();
- editor.statusError("Export to windows64 failed!");
- }
- }
- if (Preferences.getBoolean("export.application.platform.macosx")) {
+ final String hostVariant = Platform.getVariant();
+ for (String variant : Preferences.get(ExportPrompt.EXPORT_VARIANTS).split(",")) {
+ // Can only embed Java on the native platform
+ boolean embed = variant.equals(hostVariant) &&
+ Preferences.getBoolean("export.application.embed_java");
+
try {
- new MacExport(sketch, editor, libraries).export();
+ if (variant.startsWith("windows-")) {
+ new WindowsExport(variant, sketch, editor, libraries, embed).export();
+ } else if (variant.startsWith("macos-")) {
+ new MacExport(variant, sketch, editor, libraries, embed).export();
+ } else if (variant.startsWith("linux-")) {
+ new LinuxExport(variant, sketch, editor, libraries, embed).export();
+ }
} catch (final IOException e) {
e.printStackTrace();
- editor.statusError("Export to macosx failed!");
+ editor.statusError("Export to " + variant + " failed");
}
}
+
log("Opening result folder.");
Platform.openFolder(sketch.getFolder());
}
diff --git a/runtime/src/jycessing/mode/export/LinuxExport.java b/runtime/src/jycessing/mode/export/LinuxExport.java
index 0450f273..fb568540 100644
--- a/runtime/src/jycessing/mode/export/LinuxExport.java
+++ b/runtime/src/jycessing/mode/export/LinuxExport.java
@@ -18,7 +18,6 @@
import processing.app.Sketch;
import processing.app.Util;
import processing.core.PApplet;
-import processing.core.PConstants;
/**
* Performs an export to Linux (32/64). The linux export folder layout is as follows:
@@ -41,26 +40,18 @@ protected void log(final String msg) {
}
}
- public LinuxExport(
- final Arch arch, final Sketch sketch, final PyEditor editor, final Set libraries) {
- this.id = PConstants.LINUX;
- this.arch = arch;
- this.name = PConstants.platformNames[id] + arch.bits;
+ public LinuxExport(final String variant, final Sketch sketch, final PyEditor editor, final Set libraries, boolean embedJava) {
+ this.variant = variant;
this.sketch = sketch;
this.editor = editor;
this.libraries = libraries;
+ this.embedJava = embedJava;
}
@Override
public void export() throws IOException {
- // Work out user preferences and other possibilities we care about
- final boolean embedJava =
- (id == PApplet.platform)
- && Preferences.getBoolean("export.application.embed_java")
- && arch == Exporter.processingArch;
-
// Work out the folders we'll be (maybe) using
- final File destFolder = new File(sketch.getFolder(), "application." + name);
+ final File destFolder = new File(sketch.getFolder(), variant);
final File javaFolder = new File(destFolder, "java");
copyBasicStructure(destFolder);
diff --git a/runtime/src/jycessing/mode/export/MacExport.java b/runtime/src/jycessing/mode/export/MacExport.java
index 948370e0..0a7cf18a 100644
--- a/runtime/src/jycessing/mode/export/MacExport.java
+++ b/runtime/src/jycessing/mode/export/MacExport.java
@@ -23,7 +23,6 @@
import processing.app.Sketch;
import processing.app.Util;
import processing.core.PApplet;
-import processing.core.PConstants;
/**
* A Mac export.
@@ -50,23 +49,18 @@ protected void log(final String msg) {
}
}
- public MacExport(final Sketch sketch, final PyEditor editor, final Set libraries) {
- this.id = PConstants.MACOSX;
- this.name = PConstants.platformNames[id];
+ public MacExport(final String variant, final Sketch sketch, final PyEditor editor, final Set libraries, final boolean embedJava) {
+ this.variant = variant;
this.sketch = sketch;
this.editor = editor;
this.libraries = libraries;
- this.arch = Arch.AMD64;
+ this.embedJava = embedJava;
}
@Override
public void export() throws IOException {
- // Work out user preferences and other possibilities we care about
- final boolean embedJava =
- (id == PApplet.platform) && Preferences.getBoolean("export.application.embed_java");
-
// Work out the folders we'll be (maybe) using
- final File destFolder = new File(sketch.getFolder(), "application." + name);
+ final File destFolder = new File(sketch.getFolder(), variant);
final File appRootFolder = new File(destFolder, sketch.getName() + ".app");
final File contentsFolder = new File(appRootFolder, "Contents");
final File binFolder = new File(contentsFolder, "MacOS");
diff --git a/runtime/src/jycessing/mode/export/PlatformExport.java b/runtime/src/jycessing/mode/export/PlatformExport.java
index 036dd17b..c72f6317 100644
--- a/runtime/src/jycessing/mode/export/PlatformExport.java
+++ b/runtime/src/jycessing/mode/export/PlatformExport.java
@@ -14,12 +14,14 @@
/** Subclass this to add more platforms, if we ever want to add freebsd or haiku or something */
public abstract class PlatformExport {
- protected int id;
- protected String name;
+ //protected int id;
+ //protected Arch arch;
+ protected String variant; // replaces id and arch in Processing 4
+// protected String name;
protected PyEditor editor;
protected Sketch sketch;
protected Set libraries;
- protected Arch arch;
+ protected boolean embedJava;
/** Instance so that subclasses can override it. */
protected abstract void log(final String msg);
@@ -76,8 +78,7 @@ public void copyBasicStructure(final File destFolder) throws IOException {
final File libraryExportFolder =
new File(libFolder, library.getFolder().getName() + "/library/");
libraryExportFolder.mkdirs();
- for (final File exportFile :
- library.getApplicationExports(id, Integer.toString(arch.bits))) {
+ for (final File exportFile : library.getApplicationExports(variant)) {
log("Exporting: " + exportFile);
final String exportName = exportFile.getName();
if (!exportFile.exists()) {
@@ -104,7 +105,7 @@ public void copyBasicStructure(final File destFolder) throws IOException {
log("Copying core processing stuff to export");
for (final File exportFile :
new Library(Platform.getContentFile("core"))
- .getApplicationExports(id, Integer.toString(arch.bits))) {
+ .getApplicationExports(variant)) {
if (exportFile.isDirectory()) {
Util.copyDir(exportFile, new File(jycessingFolder, exportFile.getName()));
} else {
diff --git a/runtime/src/jycessing/mode/export/WindowsExport.java b/runtime/src/jycessing/mode/export/WindowsExport.java
index 5aa2fd96..a89f336d 100644
--- a/runtime/src/jycessing/mode/export/WindowsExport.java
+++ b/runtime/src/jycessing/mode/export/WindowsExport.java
@@ -47,24 +47,17 @@ protected void log(final String msg) {
}
}
- public WindowsExport(
- final Arch arch, final Sketch sketch, final PyEditor editor, final Set libraries) {
- this.id = PConstants.WINDOWS;
- this.arch = arch;
- this.name = PConstants.platformNames[id] + arch.bits;
+ public WindowsExport(final String variant, final Sketch sketch, final PyEditor editor, final Set libraries, boolean embedJava) {
+ this.variant = variant;
this.sketch = sketch;
this.editor = editor;
this.libraries = libraries;
+ this.embedJava = embedJava;
}
@Override
public void export() throws IOException {
- final boolean embedJava =
- (id == PApplet.platform)
- && Preferences.getBoolean("export.application.embed_java")
- && arch == Exporter.processingArch;
-
- final File destFolder = new File(sketch.getFolder(), "application." + name);
+ final File destFolder = new File(sketch.getFolder(), variant);
final File javaFolder = new File(destFolder, "java");
copyBasicStructure(destFolder);
@@ -109,7 +102,7 @@ private XML buildLaunch4jConfig(final File destFolder, final boolean embedJava)
config.addChild("errTitle").setContent("Sketchy Behavior");
config.addChild("icon").setContent(iconFile.getAbsolutePath());
config.addChild("chdir").setContent(".");
- config.addChild(buildJREOptions(embedJava, setMemory, arch));
+ config.addChild(buildJREOptions(embedJava, setMemory));
config.addChild(buildRunnerOptions(presentMode, stopButton));
config.addChild(buildClassPathOptions(jycessingFolder));
log("Configuration done: " + config.format(0));
@@ -188,7 +181,7 @@ private void runLaunch4j(final File configFile) throws IOException {
}
}
- private XML buildJREOptions(final boolean embedJava, final boolean setMemory, final Arch arch) {
+ private XML buildJREOptions(final boolean embedJava, final boolean setMemory) {
log("Building JRE options.");
final XML jre = new XML("jre");
if (embedJava) {
@@ -200,14 +193,7 @@ private XML buildJREOptions(final boolean embedJava, final boolean setMemory, fi
// We always add the minVersion tag, which means that the sketch will always try to look for
// Java on the system - by default when java isn't embedded, as a fallback when it is
jre.addChild("minVersion").setContent("1.7.0_40");
-
- switch (arch) {
- case AMD64:
- jre.addChild("runtimeBits").setContent("64");
- break;
- case X86:
- jre.addChild("runtimeBits").setContent("32");
- }
+ jre.addChild("runtimeBits").setContent("64");
if (setMemory) {
jre.addChild("initialHeapSize").setContent(Preferences.get("run.options.memory.initial"));
diff --git a/runtime/src/jycessing/mode/run/OSXAdapter.java b/runtime/src/jycessing/mode/run/OSXAdapter.java
deleted file mode 100644
index fd84d349..00000000
--- a/runtime/src/jycessing/mode/run/OSXAdapter.java
+++ /dev/null
@@ -1,233 +0,0 @@
-package jycessing.mode.run;
-
-/*
-
-File: OSXAdapter.java
-
-Abstract: Hooks existing preferences/about/quit functionality from an
- existing Java app into handlers for the Mac OS X application menu.
- Uses a Proxy object to dynamically implement the
- com.apple.eawt.ApplicationListener interface and register it with the
- com.apple.eawt.Application object. This allows the complete project
- to be both built and run on any platform without any stubs or
- placeholders. Useful for developers looking to implement Mac OS X
- features while supporting multiple platforms with minimal impact.
-
-Version: 2.0
-
-Disclaimer: IMPORTANT: This Apple software is supplied to you by
-Apple Inc. ("Apple") in consideration of your agreement to the
-following terms, and your use, installation, modification or
-redistribution of this Apple software constitutes acceptance of these
-terms. If you do not agree with these terms, please do not use,
-install, modify or redistribute this Apple software.
-
-In consideration of your agreement to abide by the following terms, and
-subject to these terms, Apple grants you a personal, non-exclusive
-license, under Apple's copyrights in this original Apple software (the
-"Apple Software"), to use, reproduce, modify and redistribute the Apple
-Software, with or without modifications, in source and/or binary forms;
-provided that if you redistribute the Apple Software in its entirety and
-without modifications, you must retain this notice and the following
-text and disclaimers in all such redistributions of the Apple Software.
-Neither the name, trademarks, service marks or logos of Apple Inc.
-may be used to endorse or promote products derived from the Apple
-Software without specific prior written permission from Apple. Except
-as expressly stated in this notice, no other rights or licenses, express
-or implied, are granted by Apple herein, including but not limited to
-any patent rights that may be infringed by your derivative works or by
-other works in which the Apple Software may be incorporated.
-
-The Apple Software is provided by Apple on an "AS IS" basis. APPLE
-MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
-THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
-OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
-
-IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
-OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
-MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
-AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
-STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-Copyright (C) 2003-2007 Apple, Inc., All Rights Reserved
-
-*/
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-public class OSXAdapter implements InvocationHandler {
-
- protected Object targetObject;
- protected Method targetMethod;
- protected String proxySignature;
-
- static Object macOSXApplication;
-
- // Pass this method an Object and Method equipped to perform application shutdown logic
- // The method passed should return a boolean stating whether or not the quit should occur
- public static void setQuitHandler(final Object target, final Method quitHandler) {
- setHandler(new OSXAdapter("handleQuit", target, quitHandler));
- }
-
- // Pass this method an Object and Method equipped to display application info
- // They will be called when the About menu item is selected from the application menu
- public static void setAboutHandler(final Object target, final Method aboutHandler) {
- final boolean enableAboutMenu = (target != null && aboutHandler != null);
- if (enableAboutMenu) {
- setHandler(new OSXAdapter("handleAbout", target, aboutHandler));
- }
- // If we're setting a handler, enable the About menu item by calling
- // com.apple.eawt.Application reflectively
- try {
- final Method enableAboutMethod =
- macOSXApplication
- .getClass()
- .getDeclaredMethod("setEnabledAboutMenu", new Class[] {boolean.class});
- enableAboutMethod.invoke(macOSXApplication, new Object[] {Boolean.valueOf(enableAboutMenu)});
- } catch (final Exception ex) {
- System.err.println("OSXAdapter could not access the About Menu");
- ex.printStackTrace();
- }
- }
-
- // Pass this method an Object and a Method equipped to display application options
- // They will be called when the Preferences menu item is selected from the application menu
- public static void setPreferencesHandler(final Object target, final Method prefsHandler) {
- final boolean enablePrefsMenu = (target != null && prefsHandler != null);
- if (enablePrefsMenu) {
- setHandler(new OSXAdapter("handlePreferences", target, prefsHandler));
- }
- // If we're setting a handler, enable the Preferences menu item by calling
- // com.apple.eawt.Application reflectively
- try {
- final Method enablePrefsMethod =
- macOSXApplication
- .getClass()
- .getDeclaredMethod("setEnabledPreferencesMenu", new Class[] {boolean.class});
- enablePrefsMethod.invoke(macOSXApplication, new Object[] {Boolean.valueOf(enablePrefsMenu)});
- } catch (final Exception ex) {
- System.err.println("OSXAdapter could not access the About Menu: " + ex);
- }
- }
-
- // Pass this method an Object and a Method equipped to handle document events from the Finder
- // Documents are registered with the Finder via the CFBundleDocumentTypes dictionary in the
- // application bundle's Info.plist
- public static void setFileHandler(final Object target, final Method fileHandler) {
- setHandler(
- new OSXAdapter("handleOpenFile", target, fileHandler) {
- // Override OSXAdapter.callTarget to send information on the
- // file to be opened
- @Override
- public boolean callTarget(final Object appleEvent) {
- if (appleEvent != null) {
- try {
- final Method getFilenameMethod =
- appleEvent.getClass().getDeclaredMethod("getFilename", (Class[]) null);
- final String filename =
- (String) getFilenameMethod.invoke(appleEvent, (Object[]) null);
- this.targetMethod.invoke(this.targetObject, new Object[] {filename});
- } catch (final Exception ex) {
-
- }
- }
- return true;
- }
- });
- }
-
- // setHandler creates a Proxy object from the passed OSXAdapter and adds it as an
- // ApplicationListener
- public static void setHandler(final OSXAdapter adapter) {
- try {
- final Class> applicationClass = Class.forName("com.apple.eawt.Application");
- if (macOSXApplication == null) {
- macOSXApplication =
- applicationClass.getConstructor((Class[]) null).newInstance((Object[]) null);
- }
- final Class> applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener");
- final Method addListenerMethod =
- applicationClass.getDeclaredMethod(
- "addApplicationListener", new Class[] {applicationListenerClass});
- // Create a proxy object around this handler that can be reflectively added as an Apple
- // ApplicationListener
- final Object osxAdapterProxy =
- Proxy.newProxyInstance(
- OSXAdapter.class.getClassLoader(), new Class[] {applicationListenerClass}, adapter);
- addListenerMethod.invoke(macOSXApplication, new Object[] {osxAdapterProxy});
- } catch (final ClassNotFoundException cnfe) {
- System.err.println(
- "This version of Mac OS X does not support the Apple EAWT. ApplicationEvent handling has been disabled ("
- + cnfe
- + ")");
- } catch (final Exception ex) { // Likely a NoSuchMethodException or an IllegalAccessException
- // loading/invoking eawt.Application methods
- System.err.println("Mac OS X Adapter could not talk to EAWT:" + ex);
- }
- }
-
- // Each OSXAdapter has the name of the EAWT method it intends to listen for (handleAbout, for
- // example),
- // the Object that will ultimately perform the task, and the Method to be called on that Object
- protected OSXAdapter(final String proxySignature, final Object target, final Method handler) {
- this.proxySignature = proxySignature;
- this.targetObject = target;
- this.targetMethod = handler;
- }
-
- // Override this method to perform any operations on the event
- // that comes with the various callbacks
- // See setFileHandler above for an example
- public boolean callTarget(final Object appleEvent)
- throws InvocationTargetException, IllegalAccessException {
- final Object result = targetMethod.invoke(targetObject, (Object[]) null);
- if (result == null) {
- return true;
- }
- return Boolean.valueOf(result.toString()).booleanValue();
- }
-
- // InvocationHandler implementation
- // This is the entry point for our proxy object; it is called every time an ApplicationListener
- // method is invoked
- @Override
- public Object invoke(final Object proxy, final Method method, final Object[] args)
- throws Throwable {
- if (isCorrectMethod(method, args)) {
- final boolean handled = callTarget(args[0]);
- setApplicationEventHandled(args[0], handled);
- }
- // All of the ApplicationListener methods are void; return null regardless of what happens
- return null;
- }
-
- // Compare the method that was called to the intended method when the OSXAdapter instance was
- // created
- // (e.g. handleAbout, handleQuit, handleOpenFile, etc.)
- protected boolean isCorrectMethod(final Method method, final Object[] args) {
- return (targetMethod != null && proxySignature.equals(method.getName()) && args.length == 1);
- }
-
- // It is important to mark the ApplicationEvent as handled and cancel the default behavior
- // This method checks for a boolean result from the proxy method and sets the event accordingly
- protected void setApplicationEventHandled(final Object event, final boolean handled) {
- if (event != null) {
- try {
- final Method setHandledMethod =
- event.getClass().getDeclaredMethod("setHandled", new Class[] {boolean.class});
- // If the target method returns a boolean, use that as a hint
- setHandledMethod.invoke(event, new Object[] {Boolean.valueOf(handled)});
- } catch (final Exception ex) {
- System.err.println("OSXAdapter was unable to handle an ApplicationEvent: " + event);
- ex.printStackTrace();
- }
- }
- }
-}
diff --git a/runtime/src/jycessing/mode/run/RMIUtils.java b/runtime/src/jycessing/mode/run/RMIUtils.java
index a096b6bf..5cfdf987 100644
--- a/runtime/src/jycessing/mode/run/RMIUtils.java
+++ b/runtime/src/jycessing/mode/run/RMIUtils.java
@@ -1,6 +1,5 @@
package jycessing.mode.run;
-import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
@@ -19,19 +18,10 @@ public class RMIUtils {
static final int RMI_PORT = 8220;
- private static final RMIClientSocketFactory clientFactory = new RMIClientSocketFactory() {
- @Override
- public Socket createSocket(final String host, final int port) throws IOException {
- return new Socket(host, port);
- }
- };
+ private static final RMIClientSocketFactory clientFactory = Socket::new;
- private static final RMIServerSocketFactory serverFactory = new RMIServerSocketFactory() {
- @Override
- public ServerSocket createServerSocket(final int port) throws IOException {
- return new ServerSocket(port, 50, InetAddress.getLoopbackAddress());
- }
- };
+ private static final RMIServerSocketFactory serverFactory =
+ port -> new ServerSocket(port, 50, InetAddress.getLoopbackAddress());
static {
System.setProperty("sun.rmi.transport.tcp.localHostNameTimeOut", "1000");
@@ -90,7 +80,7 @@ public static void bind(final Remote remote, final Class extends Remote> remot
try {
log("Unbinding " + registryKey + " from registry.");
registry().unbind(registryKey);
- } catch (final Exception e) {
+ } catch (final Exception ignored) {
}
}));
} catch (final Exception e) {
diff --git a/runtime/src/jycessing/mode/run/SketchRunner.java b/runtime/src/jycessing/mode/run/SketchRunner.java
index cb79df20..0a274d5f 100644
--- a/runtime/src/jycessing/mode/run/SketchRunner.java
+++ b/runtime/src/jycessing/mode/run/SketchRunner.java
@@ -1,16 +1,17 @@
package jycessing.mode.run;
+import java.awt.Desktop;
import java.rmi.RemoteException;
+import processing.app.Platform;
+import processing.app.SketchException;
+
import jycessing.Printer;
import jycessing.PythonSketchError;
import jycessing.Runner;
import jycessing.SketchPositionListener;
import jycessing.mode.PythonMode;
import jycessing.mode.run.RMIUtils.RMIProblem;
-import processing.app.SketchException;
-import processing.core.PApplet;
-import processing.core.PConstants;
public class SketchRunner implements SketchService {
@@ -28,14 +29,21 @@ private static void log(final String msg) {
public SketchRunner(final String id, final ModeService modeService) {
this.id = id;
this.modeService = modeService;
- if (PApplet.platform == PConstants.MACOSX) {
+ if (Platform.isMacOS()) {
+ //OSXAdapter.setQuitHandler(this, this.getClass().getMethod("preventUserQuit"));
try {
- OSXAdapter.setQuitHandler(this, this.getClass().getMethod("preventUserQuit"));
+ Desktop.getDesktop().setQuitHandler((event, quitResponse) -> {
+ if (preventUserQuit()) {
+ quitResponse.performQuit();
+ } else {
+ quitResponse.cancelQuit();
+ }
+ });
} catch (final Throwable e) {
System.err.println(e.getMessage());
}
}
- new Thread(() -> Runner.warmup(), "SketchRunner Warmup Thread").start();
+ new Thread(Runner::warmup, "SketchRunner Warmup Thread").start();
}
/**
@@ -57,7 +65,7 @@ public boolean preventUserQuit() {
return true;
}
log("Cancelling quit, but stopping sketch.");
- new Thread(() -> stopSketch()).start();
+ new Thread(this::stopSketch).start();
return false;
}
@@ -68,7 +76,7 @@ public void shutdown() {
System.exit(0);
}
- private abstract class RemotePrinter implements Printer {
+ private abstract static class RemotePrinter implements Printer {
abstract protected void doPrint(String s) throws RemoteException;
public void print(final Object o) {
diff --git a/runtime/src/jycessing/mode/run/SketchServiceProcess.java b/runtime/src/jycessing/mode/run/SketchServiceProcess.java
index b2e018fa..352aec62 100644
--- a/runtime/src/jycessing/mode/run/SketchServiceProcess.java
+++ b/runtime/src/jycessing/mode/run/SketchServiceProcess.java
@@ -155,6 +155,39 @@ private ProcessBuilder createServerCommand() {
// enable assertions
command.add("-ea");
+ // Give introspection permissions.
+ final String[] exports = {"java.base/sun.nio.ch", //
+ "java.base/java.nio", //
+ "java.base/java.lang", //
+ "java.base/java.lang.constant", //
+ "java.base/java.lang.reflect", //
+ "java.base/java.io", //
+ "jdk.unsupported/sun.misc", //
+ "java.base/java.nio.charset", //
+ "java.base/java.util", //
+ "java.base/java.net", //
+ "java.base/java.text", //
+ "java.base/java.util.concurrent", //
+ "java.sql/java.sql", //
+ "java.base/java.util.concurrent.locks", //
+ "java.base/sun.util.calendar", //
+ "java.base/java.nio.channels", //
+ "java.base/java.security", //
+ "java.base/java.util.concurrent.atomic", //
+ "java.base/java.security.cert", //
+ "java.base/javax.net.ssl", //
+ "java.naming/javax.naming.ldap", //
+ "java.base/java.security.spec", //
+ "java.base/javax.net.ssl", //
+ "java.base/javax.security.auth.x500", //
+ "java.security.jgss/org.ietf.jgss", //
+ "java.desktop/com.apple.eawt", //
+ };
+ for (final String s : exports) {
+ command.add(String.format("--add-exports=%s=ALL-UNNAMED", s));
+ command.add(String.format("--add-opens=%s=ALL-UNNAMED", s));
+ }
+
// Run the SketchRunner main.
command.add(SketchRunner.class.getName());
diff --git a/testmode.sh b/testmode.sh
index f7356c29..d318e0d1 100755
--- a/testmode.sh
+++ b/testmode.sh
@@ -2,12 +2,12 @@
export VERBOSE_PYTHON_MODE=true
PROCESSINGPY=$(pwd)
-PROCESSING=../processing
+PROCESSING=../processing4
MODES=~/Documents/Processing/modes;
if [[ $(uname) == 'Darwin' ]]; then
- RUNPROCESSING=$PROCESSING/build/macosx/work/Processing.app/Contents/MacOS/Processing
-else
+ RUNPROCESSING=$PROCESSING/build/macos/work/Processing.app/Contents/MacOS/Processing
+else
RUNPROCESSING="$PROCESSING/build/linux/work/processing"
MODES=~/sketchbook/modes;
fi