From 8ee1f4551a5edafe6e3a5e8e7491f0c228871587 Mon Sep 17 00:00:00 2001 From: Patrick Vares Date: Mon, 19 Jan 2015 20:00:10 -0500 Subject: [PATCH 1/2] Ensured that all GUI operations happen on the EDT via invokeLater or invokeAndWait Ensured that the sketch directory still exists before checking for changes --- app/src/processing/app/ChangeDetector.java | 110 ++++++++++++++++----- 1 file changed, 86 insertions(+), 24 deletions(-) diff --git a/app/src/processing/app/ChangeDetector.java b/app/src/processing/app/ChangeDetector.java index 3dc8fd1a5..5ef797d34 100644 --- a/app/src/processing/app/ChangeDetector.java +++ b/app/src/processing/app/ChangeDetector.java @@ -1,10 +1,13 @@ package processing.app; +import java.awt.EventQueue; +import java.awt.Frame; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; public class ChangeDetector implements WindowFocusListener { private Sketch sketch; @@ -45,12 +48,76 @@ public class ChangeDetector implements WindowFocusListener { th.start(); } + private void showErrorAsync(final String title, final String message, + final Exception e) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + Base.showError(title, message, e); + } + }); + } + + private void showWarningAsync(final String title, final String message) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + Base.showWarning(title, message); + } + }); + } + + private void showWarningTieredAsync(final String title, + final String message1, + final String message2, final Exception e) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + Base.showWarningTiered(title, message1, message2, e); + } + }); + } + + private int showYesNoQuestionAsync(final Frame editor, final String title, + final String message1, + final String message2) { + final int[] res = { -1 }; + try { + //have to wait for a response on this one + EventQueue.invokeAndWait(new Runnable() { + @Override + public void run() { + res[0] = Base.showYesNoQuestion(editor, title, message1, message2); + } + }); + } catch (InvocationTargetException e) { + //occurs if Base.showYesNoQuestion throws an error, so, shouldn't happen + e.printStackTrace(); + } catch (InterruptedException e) { + //occurs if the EDT is interrupted, so, shouldn't happen + e.printStackTrace(); + } + return res[0]; + } + + private void rebuildHeaderAsync() { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + editor.header.rebuild(); + } + }); + } + private void checkFileChange() { //check that the content of each of the files in sketch matches what is in memory if (sketch == null) { return; } + //make sure the sketch folder exists at all. if it does not, it will be re-saved, and no changes will be detected + // + sketch.ensureExistence(); //check file count first File sketchFolder = sketch.getFolder(); int fileCount = sketchFolder.list(new FilenameFilter() { @@ -58,7 +125,7 @@ public class ChangeDetector implements WindowFocusListener { @Override public boolean accept(File dir, String name) { for (String s : editor.getMode().getExtensions()) { - if (name.endsWith(s)) { + if (name.toLowerCase().endsWith(s.toLowerCase())) { return true; } } @@ -67,14 +134,14 @@ public class ChangeDetector implements WindowFocusListener { }).length; if (fileCount != sketch.getCodeCount()) { - reloadSketch(null); - if (fileCount < 1) { + //if they chose to reload and there aren't any files left + if (reloadSketch(null) && fileCount < 1) { try { //make a blank file sketch.getMainFile().createNewFile(); } catch (Exception e1) { //if that didn't work, tell them it's un-recoverable - Base.showError("Reload failed", "The sketch contains no code files.", + showErrorAsync("Reload failed", "The sketch contains no code files.", e1); //don't try to reload again after the double fail //this editor is probably trashed by this point, but a save-as might be possible @@ -83,11 +150,9 @@ public class ChangeDetector implements WindowFocusListener { } //it's okay to do this without confirmation, because they already confirmed to deleting the unsaved changes above sketch.reload(); - editor.header.rebuild(); - Base - .showWarning("Modified Reload", - "You cannot delete the last code file in a sketch.\n" - + "A new blank sketch file has been generated for you."); + showWarningAsync("Modified Reload", + "You cannot delete the last code file in a sketch.\n" + + "A new blank sketch file has been generated for you."); } return; @@ -107,10 +172,9 @@ public class ChangeDetector implements WindowFocusListener { try { onDisk = Base.loadFile(sketchFile); } catch (IOException e1) { - Base - .showWarningTiered("File Change Detection Failed", - "Checking for changed files for this sketch has failed.", - "The file change detector will be disabled.", e1); + showWarningTieredAsync("File Change Detection Failed", + "Checking for changed files for this sketch has failed.", + "The file change detector will be disabled.", e1); enabled = false; return; } @@ -129,18 +193,17 @@ public class ChangeDetector implements WindowFocusListener { } //returns true if the files in the sketch have been reloaded - private void reloadSketch(SketchCode changed) { - int response = Base - .showYesNoQuestion(editor, - "File Modified", - "Your sketch has been modified externally.
Would you like to reload the sketch?", - "If you reload the sketch, any unsaved changes will be lost!"); + private boolean reloadSketch(SketchCode changed) { + int response = showYesNoQuestionAsync(editor, + "File Modified", + "Your sketch has been modified externally.
Would you like to reload the sketch?", + "If you reload the sketch, any unsaved changes will be lost!"); if (response == 0) { //reload the sketch sketch.reload(); - editor.header.rebuild(); - + rebuildHeaderAsync(); + return true; } else { //they said no, make it possible for them to stop the errors by saving if (changed != null) { @@ -156,11 +219,10 @@ public class ChangeDetector implements WindowFocusListener { } //if files were simply added, then nothing needs done } - editor.header.rebuild(); + rebuildHeaderAsync(); skip = true; - return; + return false; } - return; } @Override From 402810e2e10144bc63bad6babc7225df79cd429c Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 20 Jan 2015 00:54:18 -0500 Subject: [PATCH 2/2] handle lack of predefined cursors in LWJGL --- .../src/processing/lwjgl/PSurfaceLWJGL.java | 69 ++++++++++++++----- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PSurfaceLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PSurfaceLWJGL.java index 80367c96e..014c3ddad 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PSurfaceLWJGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PSurfaceLWJGL.java @@ -6,13 +6,9 @@ import java.awt.Frame; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; -import java.awt.Image; -import java.awt.Point; import java.awt.Rectangle; -import java.awt.Toolkit; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; -import java.awt.image.MemoryImageSource; import java.nio.IntBuffer; import org.lwjgl.BufferUtils; @@ -52,6 +48,7 @@ public class PSurfaceLWJGL implements PSurface { int cursorType = PConstants.ARROW; // cursor type boolean cursorVisible = true; // cursor visibility flag Cursor invisibleCursor; + Cursor currentCursor; // ........................................................ @@ -199,8 +196,15 @@ public class PSurfaceLWJGL implements PSurface { @Override public void placeWindow(int[] location) { - Display.setLocation(location[0], location[1]); - + if (location != null) { + // a specific location was received from the Runner + // (applet has been run more than once, user placed window) + Display.setLocation(location[0], location[1]); + } else { // just center on screen + // Can't use frame.setLocationRelativeTo(null) because it sends the + // frame to the main display, which undermines the --display setting. + setFrameCentered(); + } } @Override @@ -208,6 +212,13 @@ public class PSurfaceLWJGL implements PSurface { // TODO Auto-generated method stub } + + private void setFrameCentered() { + // Can't use frame.setLocationRelativeTo(null) because it sends the + // frame to the main display, which undermines the --display setting. + Display.setLocation(screenRect.x + (screenRect.width - sketchWidth) / 2, + screenRect.y + (screenRect.height - sketchHeight) / 2); + } @Override public void placePresent(Color stopColor) { @@ -319,11 +330,13 @@ public class PSurfaceLWJGL implements PSurface { @Override public void setCursor(int kind) { + System.err.println("Sorry, cursor types not supported in OpenGL, provide your cursor image"); // TODO Auto-generated method stub - if (PApplet.platform == PConstants.MACOSX && kind == PConstants.MOVE) { - kind = PConstants.HAND; - } - java.awt.Cursor cursor0 = java.awt.Cursor.getPredefinedCursor(kind); +// if (PApplet.platform == PConstants.MACOSX && kind == PConstants.MOVE) { +// kind = PConstants.HAND; +// } +// +// java.awt.Cursor cursor0 = java.awt.Cursor.getPredefinedCursor(kind); // Cursor cursor1 = Cursor(cursor0., @@ -336,9 +349,8 @@ public class PSurfaceLWJGL implements PSurface { // Mouse.setNativeCursor(cursor1); - cursorVisible = true; - this.cursorType = kind; - +// cursorVisible = true; +// this.cursorType = kind; } @Override @@ -347,9 +359,9 @@ public class PSurfaceLWJGL implements PSurface { IntBuffer buf = IntBuffer.wrap(jimg.getRGB(0, 0, jimg.getWidth(), jimg.getHeight(), null, 0, jimg.getWidth())); try { - Cursor cursor = new Cursor(jimg.getWidth(), jimg.getHeight(), + currentCursor = new Cursor(jimg.getWidth(), jimg.getHeight(), hotspotX, hotspotY, 1, buf, null); - Mouse.setNativeCursor(cursor); + Mouse.setNativeCursor(currentCursor); cursorVisible = true; } catch (LWJGLException e) { // TODO Auto-generated catch block @@ -359,10 +371,18 @@ public class PSurfaceLWJGL implements PSurface { @Override public void showCursor() { -// if (!cursorVisible) { + if (!cursorVisible) { +// setCursor(cursorType); // cursorVisible = true; // Mouse.setCursor(Cursor.getPredefinedCursor(cursorType)); -// } + try { + Mouse.setNativeCursor(currentCursor); + cursorVisible = true; + } catch (LWJGLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } } @Override @@ -426,6 +446,8 @@ public class PSurfaceLWJGL implements PSurface { mousePoller = new MousePoller(sketch); mousePoller.start(); + System.err.println(Mouse.getNativeCursor()); + long beforeTime = System.nanoTime(); long overSleepTime = 0L; @@ -551,6 +573,12 @@ public class PSurfaceLWJGL implements PSurface { KeyPoller(PApplet parent) { this.parent = parent; stopRequested = false; + try { + Keyboard.create(); + } catch (LWJGLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } @Override @@ -642,6 +670,13 @@ public class PSurfaceLWJGL implements PSurface { MousePoller(PApplet parent) { this.parent = parent; stopRequested = false; + try { + Mouse.create(); +// Mouse.setNativeCursor(null); + } catch (LWJGLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } @Override