Skip to content

Commit 19342f5

Browse files
committed
FX: Add exception handler which reports exceptions form user code
Fixes processing#4339
1 parent 5c219a3 commit 19342f5

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

core/src/processing/javafx/PSurfaceFX.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.HashMap;
3131
import java.util.List;
3232
import java.util.Map;
33+
import java.util.concurrent.SynchronousQueue;
3334

3435
import javafx.animation.Animation;
3536
import javafx.animation.KeyFrame;
@@ -71,6 +72,8 @@ public class PSurfaceFX implements PSurface {
7172
final Animation animation;
7273
float frameRate = 60;
7374

75+
private SynchronousQueue<Throwable> drawExceptionQueue = new SynchronousQueue<>();
76+
7477
public PSurfaceFX(PGraphicsFX2D graphics) {
7578
fx = graphics;
7679
canvas = new ResizableCanvas();
@@ -80,7 +83,16 @@ public PSurfaceFX(PGraphicsFX2D graphics) {
8083
new EventHandler<ActionEvent>() {
8184
public void handle(ActionEvent event) {
8285
long startNanoTime = System.nanoTime();
83-
sketch.handleDraw();
86+
try {
87+
sketch.handleDraw();
88+
} catch (Throwable e) {
89+
// Let exception handler thread crash with our exception
90+
drawExceptionQueue.offer(e);
91+
// Stop animating right now so nothing runs afterwards
92+
// and crash frame can be for example traced by println()
93+
animation.stop();
94+
return;
95+
}
8496
long drawNanos = System.nanoTime() - startNanoTime;
8597

8698
if (sketch.exitCalled()) {
@@ -366,10 +378,40 @@ public void run() {
366378
} catch (InterruptedException e) { }
367379
}
368380

381+
startExceptionHandlerThread();
382+
369383
setProcessingIcon(stage);
370384
}
371385

372386

387+
private void startExceptionHandlerThread() {
388+
Thread exceptionHandlerThread = new Thread(() -> {
389+
Throwable drawException;
390+
try {
391+
drawException = drawExceptionQueue.take();
392+
} catch (InterruptedException e) {
393+
return;
394+
}
395+
// Adapted from PSurfaceJOGL
396+
if (drawException != null) {
397+
if (drawException instanceof ThreadDeath) {
398+
// System.out.println("caught ThreadDeath");
399+
// throw (ThreadDeath)cause;
400+
} else if (drawException instanceof RuntimeException) {
401+
throw (RuntimeException) drawException;
402+
} else if (drawException instanceof UnsatisfiedLinkError) {
403+
throw new UnsatisfiedLinkError(drawException.getMessage());
404+
} else {
405+
throw new RuntimeException(drawException);
406+
}
407+
}
408+
});
409+
exceptionHandlerThread.setDaemon(true);
410+
exceptionHandlerThread.setName("Processing-FX-ExceptionHandler");
411+
exceptionHandlerThread.start();
412+
}
413+
414+
373415
/** Set the window (and dock, or whatever necessary) title. */
374416
public void setTitle(String title) {
375417
// PApplicationFX.title = title; // store this in case the stage still null

0 commit comments

Comments
 (0)