Prevent one Processing window from closing others

I’m experimenting with launching multiple processing windows.

I find that when I set the renderer to be the same for all sketch instances, closing one immediately closes the other two instances.

When all renderers are different (as per the code example) the behavior changes: when the FX2D sketch is closed, the others remain open; when the JAVA2D sketch is closed, the other two freeze for a moment and then both close; when the P2D sketch is closed, the JAVA2D sketch closes immediately followed by the FX2D sketch very shortly afterwards.

This behavior seems to be independent of the order in which the sketches (the renderers) are launched using runSketch().

I want the program to behave such that closing any sketch (window) does not affect the others (they will not also close). Can this be done?


This is the code I’m playing with:

public static void main(String[] args) {

	Sketch sketch1 = new Sketch(PApplet.FX2D);
	Sketch sketch2 = new Sketch(PApplet.P2D);
	Sketch sketch3 = new Sketch(PApplet.JAVA2D);
	PApplet.runSketch(new String[] { "--location=760,0", "" }, sketch1);
	PApplet.runSketch(new String[] { "--location=760,80", "" }, sketch2);
	PApplet.runSketch(new String[] { "--location=760,160", "" }, sketch3);
}

The Sketch class has the following code (the renderer is set during initialization):

public final class Sketch extends PApplet {

	private final String renderer;

	public Sketch(String renderer) {
		this.renderer = renderer;
	}

	@Override
	public void settings() {
		size(800, 800, renderer);
	}
    .
    .
    .
1 Like
1 Like

This thread looks at how to prevent one from closing a window. I want to maintain that functionality – the problem I (/ the Processing library) have is closing one window is closing other windows (there is a coupling somewhere).

All three of your sketches are being launched by another Processing sketch (the enclosing class) so they are all coupled through that. Processing’s default action on window close is to exit the application which will close the other windows. In the link provided by @GoToLoop you see that you have remove the existing windows listeners and add your own.

2 Likes

I’ve done some digging – inspired by @GoToLoop and @quark – and have found a solution.

Closing sketches in P2D and JAVA2D renderer modes calls the PApplet instance’s exitActual() method, which contains the line System.exit(0) – a static method – which terminates the currently running Java virtual machine.

Overriding exitActual() with nothing (i.e. preventing the call to System.exit(0)) prevents sketches from closing others, fixing the issue, but introduces another problem in the case of P2D sketches: the window is not disposed properly when the cross is clicked.

Solution:

Override exitActual() to prevent the JVM (and all sketches) closing when one sketch is closed.

@Override
public void exitActual() {
}

Introduce the following code (suitable in setup()) such that P2D sketches are disposed properly:

if (getGraphics().isGL()) {
		final com.jogamp.newt.Window w = (com.jogamp.newt.Window) getSurface().getNative();
		w.setDefaultCloseOperation(WindowClosingMode.DISPOSE_ON_CLOSE);
}

However, in overriding (preventing) the call to System.exit(0), another issue is introduced: even after all sketches (windows) are closed, the JVM will continue to run in memory. Ideally System.exit(0) should be called but only when the last remaining window is disposed.

I propose a rudimentary fix below – a simple counter – but I wonder whether it is possible to inspect the JVM to see the number of live instances of JavaFX/NEWT/AWT windows, using those values instead?

@Override
public void exitActual() {
	if (Benchmark.n == 1) {
			System.exit(0);
	}
	Benchmark.n--;
}
public class Benchmark {

	public static int n = 3;

	public static void main(String[] args) {

		Sketch sketch1 = new Sketch(PApplet.FX2D);
		Sketch sketch2 = new Sketch(PApplet.P2D);
		Sketch sketch3 = new Sketch(PApplet.JAVA2D);
		PApplet.runSketch(new String[] { "--location=760,0", "" }, sketch1);
		PApplet.runSketch(new String[] { "--location=760,80", "" }, sketch2);
		PApplet.runSketch(new String[] { "--location=760,160", "" }, sketch3);
	}
}
4 Likes

Hi!

I am trying to avoid ThreadDeath when closing 2 P3D windows, I have inserted micycle’s code into the multiwindow example but I am getting “The variable “WindowClosingMode” does not exist” error. Can anyone tell me what I am doing wrong?

First Window

PWindow win;

@Override
  public void exitActual() {
}

public void settings() {
  size(320, 240, P3D);
}

void setup() { 
  win = new PWindow();
  
  if (getGraphics().isGL()) {
    final com.jogamp.newt.Window w = (com.jogamp.newt.Window) getSurface().getNative();
    w.setDefaultCloseOperation(WindowClosingMode.DISPOSE_ON_CLOSE);
  }
}

void draw() {
  background(255, 0, 0);
  fill(255);
  rect(10, 10, frameCount, 10);
} 

Second Window

class PWindow extends PApplet {
  PWindow() {
    super();
    PApplet.runSketch(new String[] {this.getClass().getSimpleName()}, this);
  }

  void settings() {
    size(500, 200, P3D);
  }

  void setup() {
    background(150);

    if (getGraphics().isGL()) {
      final com.jogamp.newt.Window w = (com.jogamp.newt.Window) getSurface().getNative();
      w.setDefaultCloseOperation(WindowClosingMode.DISPOSE_ON_CLOSE);
    }
  }

  void draw() {
    ellipse(random(width), random(height), random(50), random(50));
  }
}

Ta

You need to include it as an import statement, though I’m not sure of the exact class path.

Follow up: has anyone found the WindowClosingMode import statement and class path. I’m having a hard time with it.

import com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode;