3030import java .util .HashMap ;
3131import java .util .List ;
3232import java .util .Map ;
33+ import java .util .concurrent .SynchronousQueue ;
3334
3435import javafx .animation .Animation ;
3536import 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