Intercept window closure in P2D renderer (Processing 3)

edited July 2016 in How To...

Hello, all. What I want to do is to display a popup message that blocks the window from closing for the P2D renderer. I could have exit()make a blocking call, but then the main window doesn't refresh. So what I'd like to do is stop exit() from being called at all until the popup is dismissed. I can prevent the sketch from closing for the ESC key by intercepting it in keyPressed(), but I don't know how to make it work when I try to close the window directly via ALT+F4 or the window X button. For the default renderer I could just add an AWT window listener to surface, but P2D uses GLWindow as the underlying implementation, and I haven't figured out how to intercept OpenGL window events. So, my question: is what I want possible with P2D, and if so how do I do it?

Answers

  • I would also love to learn how to do this. Running into serious issues trying to find the x,y coordinates of my Java GLWindow (relative to my screen).

  • Hey @kchoi,

    I think the content in this other thread may help you.

  • edited July 2016 Answer ✓

    Not sure about the popup window but this prevents an P2D/P3D sketch window from closing using the red cross. It doesn't prevent the ESC key but you already know how to do that. I have not tried using both together - if you do, think about how you are going to eventually close the window ;)

    void setup() {
      size(300, 300, P2D);
      keepOpen();
    }
    
    void draw() {
      background(200, 200, 240);
    }
    
    // Prevent window closing using red cross.
    void keepOpen() {
      // Get OpenGL window
      com.jogamp.newt.opengl.GLWindow newtCanvas = (com.jogamp.newt.opengl.GLWindow) surface.getNative();
      // Remove listeners added by Processing
      for (com.jogamp.newt.event.WindowListener l : newtCanvas.getWindowListeners())
        if (l.getClass().getName().startsWith("processing"))
          newtCanvas.removeWindowListener(l);
      // Set on close action to do nothing i.e. keep the window open
      newtCanvas.setDefaultCloseOperation(com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode.DO_NOTHING_ON_CLOSE);
    }
    
  • This is a slight modification so it will work with JAVA2D as well as P2D/P3D and is in the same style as I used in the link provided by @crussoma

    // Prevent a P2D/P3D sketch window from closing with the red X
    
    // Either JAVA2D (default), P2D or P3D
    final String renderer = P2D; 
    
    void setup() {
      size(300, 300, renderer);
      keepOpen(renderer);
    }
    
    void draw() {
      background(200, 200, 240);
    }
    
    // Prevent window closing using red cross.
    void keepOpen(String renderer) {
      if (renderer == P2D || renderer == P3D) {
        // Get OpenGL window
        com.jogamp.newt.opengl.GLWindow newtCanvas = (com.jogamp.newt.opengl.GLWindow) surface.getNative();
        // Remove listeners added by Processing
        for (com.jogamp.newt.event.WindowListener l : newtCanvas.getWindowListeners())
          if (l.getClass().getName().startsWith("processing"))
            newtCanvas.removeWindowListener(l);
        // Set on close action to do nothing i.e. keep the window open
        newtCanvas.setDefaultCloseOperation(com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode.DO_NOTHING_ON_CLOSE);
      } else if (renderer == JAVA2D) {
        javax.swing.JFrame awtCanvas = (javax.swing.JFrame)((processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
        println(awtCanvas.getClass().getSimpleName());
        for (java.awt.event.WindowListener l : awtCanvas.getWindowListeners())
          awtCanvas.removeWindowListener(l);
        awtCanvas.setDefaultCloseOperation(javax.swing.JFrame.DO_NOTHING_ON_CLOSE);
      }
    }
    
  • edited July 2016

    Tried to add FX2D renderer support but failed! :(

    W/o being able to import package javafx in Processing, it doesn't seem to have any hackish way to implement method handle() from interface EventHandler:
    http://docs.Oracle.com/javase/8/javafx/api/javafx/event/EventHandler.html

    Given that class Stage doesn't have any kinda setDefaultCloseOperation() like the others, we're obliged to use setOnCloseRequest() passing our own EventHandler as its parameter:
    http://docs.Oracle.com/javase/8/javafx/api/javafx/stage/Window.html#setOnCloseRequest-javafx.event.EventHandler-

    Regardless, gonna post my tweaks for the other PSurface types: :-\"

    /**
     * SetDefaultCloseEvent (v2.0)
     * by  Quark (2016-Jul-28)
     * mod GoToLoop
     *
     * forum.Processing.org/two/discussion/17310/
     * intercept-window-closure-in-p2d-renderer-processing-3#Item_5
     */
    
    // Either JAVA2D (default), FX2D, P2D or P3D:
    static final String RENDERER = P3D;
    
    void setup() {
      size(300, 200, RENDERER);
      noLoop();
      background((color) random(#000000));
      setDefaultClosePolicy(this, true);
    }
    
    void keyPressed() {
      final int k = keyCode;
      if (k == ESC)  key = 0;
    }
    
    static final void setDefaultClosePolicy(PApplet pa, boolean keepOpen) {
      final Object surf = pa.getSurface().getNative();
      final PGraphics canvas = pa.getGraphics();
    
      if (canvas.isGL()) {
        final com.jogamp.newt.Window w = (com.jogamp.newt.Window) surf;
    
        for (com.jogamp.newt.event.WindowListener wl : w.getWindowListeners())
          if (wl.toString().startsWith("processing.opengl.PSurfaceJOGL"))
            w.removeWindowListener(wl); 
    
        w.setDefaultCloseOperation(keepOpen?
          com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode
          .DO_NOTHING_ON_CLOSE :
          com.jogamp.nativewindow.WindowClosingProtocol.WindowClosingMode
          .DISPOSE_ON_CLOSE);
      } else if (canvas instanceof processing.awt.PGraphicsJava2D) {
        final javax.swing.JFrame f = (javax.swing.JFrame)
          ((processing.awt.PSurfaceAWT.SmoothCanvas) surf).getFrame(); 
    
        for (java.awt.event.WindowListener wl : f.getWindowListeners())
          if (wl.toString().startsWith("processing.awt.PSurfaceAWT"))
            f.removeWindowListener(wl);
    
        f.setDefaultCloseOperation(keepOpen?
          f.DO_NOTHING_ON_CLOSE : f.DISPOSE_ON_CLOSE);
      }
    }
    
  • Oh, I see. What I was failing to do was remove the existing listeners. Perfect, this is exactly what I needed. Thanks, @quark!

  • Hi. I am also trying to this. I tried using @quark 's code but I'm getting an error on surface.getNative();

    The error says: Cannot find anything named "surface"

  • Make sure you are using Processing 3. If you are then post your code.

Sign In or Register to comment.