Draw Shapes on the Screen directly without a proper window

I recently revisited an old piece of code I wrote as a answer on this forum to allow an overlay onto another program. However this code didn’t use the graphics commands that processing provides. I fixed this problem and wrote easy to use code that allows using standard processing commands.

Main.pde

Code
OverlayHandler overlayHandler;
void setup() {
  //creates the handler
  overlayHandler=OverlayHandler.create(this);
}
void draw() {
  //Wipes the screen
  overlayHandler.wipe();
  stroke(0);
  strokeWeight(3);
  fill(255);
  ellipse(300, 300, 20, 20);
  noFill();
  stroke(255,0,0);
  ellipse(mouseX,mouseY,50,50);

}
void mousePressed(){
  println("Mouse was Pressed at",mouseX,mouseY);
}
void keyPressed(){
  if(key==ESC) exit();
}

OverlayHandler.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import processing.awt.*;
import java.lang.reflect.*;
import processing.core.*;

public class OverlayHandler {
  public Canvas canv=new ResultOutput();
  public JFrame drawingFrame=new JFrame("OverlayWindow");
  public BufferedImage graphics_internal;
  public PGraphicsJava2D overridenPGraphics;
  public PApplet sketch;
  public final Color transparent=new Color(0, 0, 0, 0);
  public Point mousePos=MouseInfo.getPointerInfo().getLocation();
  
  //Creates an OverlayHandler
  public OverlayHandler() {
  }
  public static OverlayHandler create(PApplet pa) {
    OverlayHandler ret=new OverlayHandler();
    ret.setupOverlay(pa);
    return ret;
  }
  
  //Sets up the Overlay. This should be called in setup before any painting takes place.
  public void setupOverlay(PApplet pa) {
    sketch=pa;
    //creates the BufferedImage
    graphics_internal=new BufferedImage(pa.displayWidth, pa.displayHeight, BufferedImage.TYPE_INT_ARGB);
    //creates an empty window
    drawingFrame.setUndecorated(true);
    drawingFrame.setBackground(transparent);
    //Adds the canvas (it will later only show a BufferedImage)
    drawingFrame.add(canv);
    canv.setBackground(transparent);
    drawingFrame.setSize(pa.displayWidth, pa.displayHeight);
    drawingFrame.setAlwaysOnTop(true);

    //Puts the window on the screen
    drawingFrame.setVisible(true);
    //The window can't be moved
    drawingFrame.getRootPane().putClientProperty("apply.awt.draggableWindowBackground", false);
    drawingFrame.pack();
    //hides the Processing window
    pa.getSurface().setVisible(false);
    //Creates a PGraphicsJava2D object that used the image given here as its output
    overridenPGraphics=new PGraphicsJava2D() {
      @Override public Graphics2D checkImage() {
        return (Graphics2D) graphics_internal.getGraphics();
      }
    };
    //Sets up the PGraphics object
    overridenPGraphics.setParent(pa);
    overridenPGraphics.setSize(pa.displayWidth, pa.displayHeight);
    overridenPGraphics.image=graphics_internal;
    overridenPGraphics.g2=overridenPGraphics.checkImage();
    //All graphics commands from processing now run through this object
    pa.g=overridenPGraphics;
    pa.registerMethod("draw", overlayInstance);
    pa.registerMethod("pre", overlayInstance);
    pa.registerMethod("mouseEvent", overlayInstance);
    addListeners();
  }
  //One needs to be careful when shapes block the cursor as these may take away the ability to click on the window below.
  //Having this on makes the mouse only be able to interact with the window below.
  public boolean alwaysAllow=false;
  public void alwaysAllowClicking(boolean b) {
    alwaysAllow=b;
  }
  //Clears the screen
  public void wipe() {
    wipe(0, 0, sketch.displayWidth, sketch.displayHeight);
  }
  //Prevents the sketch from continuing while the canvas is painting.
  public volatile boolean paintLock=false;
  //Clears a part of the screen
  public void wipe(int x1, int y1, int x2, int y2) {
    //Wipes the BufferedImage
    AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
    overridenPGraphics.g2.setComposite(composite);
    overridenPGraphics.g2.setColor(transparent);
    overridenPGraphics.g2.fillRect(x1, y1, x2, y2);

    //Allows things to be properly drawn again
    overridenPGraphics.g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
  }
  //creates interactions with the sketch.
  public OverlayUpkeep overlayInstance=new OverlayUpkeep();
  public class OverlayUpkeep {
    //Updates the mouse positions
    public void pre() {
      sketch.pmouseX=mousePos.x;
      sketch.pmouseY=mousePos.y;
      mousePos=MouseInfo.getPointerInfo().getLocation();
      sketch.mouseX=mousePos.x;
      sketch.mouseY=mousePos.y;
    }
    public void mouseEvent(processing.event.MouseEvent e) {
      pre();
    }
    //Updates the canvas after each draw
    public void draw() {
      paintLock=true;
      //refresh the canvas
      SwingUtilities.updateComponentTreeUI(drawingFrame);
      //Stopps the sketch until the canvas is done painting
      while(paintLock);
    }
  }
  //Canvas used for the window
  public class ResultOutput extends Canvas {
    public void paint(Graphics g) {
      //The use of BufferStrategy was ditched because it wasn't compatible with transparent pixels.
      //This is the reason the already existing SmoothCanvas wasn't used.
      g.drawImage(graphics_internal, 0, 0, sketch.displayWidth, sketch.displayHeight, null);
      //This allows you to always click
      paintLock=false;
      if (alwaysAllow) g.clearRect(mousePos.x, mousePos.y, 1, 1);
    }
  }
  //Uses already existing code to add functionality like registering key and mouse presses to the canvas
  public void addListeners() {
    PSurfaceAWT currentSurface=(PSurfaceAWT)sketch.getSurface();
    try {
      Field canvasField=PSurfaceAWT.class.getDeclaredField("canvas");
      Method addListenersMethod=PSurfaceAWT.class.getDeclaredMethod("addListeners");
      addListenersMethod.setAccessible(true);
      canvasField.setAccessible(true);
      Object currCanvas=canvasField.get(currentSurface);
      canvasField.set(currentSurface, canv);
      addListenersMethod.invoke(currentSurface);
      canvasField.set(currentSurface, currCanvas);
    }
    catch(Exception e) {
      throw new RuntimeException(e);
    }
  }
}

Code

This creates an PGraphicsJava2D object to replace the standard PGraphics object used by the sketch.
I couldn’t use the standard SmoothCanvas because the way it paints the graphics onto the screen (found in PGraphicsAWT.SmoothCanvas.render()) isn’t compatible with transparent pixels (using BufferStrategy) has this problem.

One can observe some kind of “flickering” when this runs. I suspect that this is because using SwingUtilities.updateComponentTreeUI(drawingFrame); may not be the best way for merely refreshing a image. If anyone has a suggestion on how to improve this feel free to post it here.

Edit: I think I fixed by replacing the canvas with a JPanel here’s the updated code:

Code
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import processing.awt.*;
import processing.core.*;

public class OverlayHandler {
  public JPanel canv=new ResultOutput();
  public JFrame drawingFrame=new JFrame("OverlayWindow");
  public BufferedImage graphics_internal;
  public PGraphicsJava2D overridenPGraphics;
  public PApplet sketch;
  public final Color transparent=new Color(0, 0, 0, 0);
  public AlphaComposite clear_composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
  public Point mousePos=MouseInfo.getPointerInfo().getLocation();

  //Creates an OverlayHandler
  public OverlayHandler() {
  }
  public static OverlayHandler create(PApplet pa) {
    OverlayHandler ret=new OverlayHandler();
    ret.setupOverlay(pa);
    return ret;
  }

  //Sets up the Overlay. This should be called in setup before any painting takes place.
  public void setupOverlay(PApplet pa) {
    //hides the Processing window
    pa.getSurface().setVisible(false);
    sketch=pa;
    //creates the BufferedImage
    graphics_internal=new BufferedImage(pa.displayWidth, pa.displayHeight, BufferedImage.TYPE_INT_ARGB);
    //creates an empty window
    drawingFrame.setUndecorated(true);
    drawingFrame.setBackground(transparent);
    //Adds the canvas (it will later only show a BufferedImage)
    canv.setFocusable(true);
    canv.setFocusTraversalKeysEnabled(false);
    canv.setBackground(transparent);
    drawingFrame.setLayout(null);
    drawingFrame.setSize(pa.displayWidth, pa.displayHeight);
    canv.setPreferredSize(new Dimension(pa.displayWidth, pa.displayHeight));
    //canv.setSize(pa.displayWidth, pa.displayHeight);
    drawingFrame.setLayout(null);
    drawingFrame.setContentPane(canv);
    drawingFrame.setAlwaysOnTop(true);
    //Puts the window on the screen
    drawingFrame.setVisible(true);
    //The window can't be moved
    drawingFrame.getRootPane().putClientProperty("apply.awt.draggableWindowBackground", false);
    drawingFrame.pack();
    //Creates a PGraphicsJava2D object that used the image given here as its output
    overridenPGraphics=new PGraphicsJava2D() {
      @Override public Graphics2D checkImage() {
        return (Graphics2D) graphics_internal.getGraphics();
      }
    };
    //Sets up the PGraphics object
    overridenPGraphics.setParent(pa);
    overridenPGraphics.setSize(pa.displayWidth, pa.displayHeight);
    overridenPGraphics.image=graphics_internal;
    overridenPGraphics.g2=overridenPGraphics.checkImage();
    //All graphics commands from processing now run through this object
    pa.g=overridenPGraphics;
    pa.registerMethod("draw", overlayInstance);
    pa.registerMethod("pre", overlayInstance);
    pa.registerMethod("mouseEvent", overlayInstance);
    addListeners();
  }
  //One needs to be careful when shapes block the cursor as these may take away the ability to click on the window below.
  //Having this on makes the mouse only be able to interact with the window below.
  public boolean alwaysAllow=false;
  public void alwaysAllowClicking(boolean b) {
    alwaysAllow=b;
  }
  //Clears the screen
  public void wipe() {
    wipe(0, 0, sketch.displayWidth, sketch.displayHeight);
  }
  //Prevents the sketch from continuing while the canvas is painting.
  public volatile boolean paintLock=false;
  //Clears a part of the screen
  public void wipe(int x, int y, int dx, int dy) {
    wipe(x, y, dx, dy, overridenPGraphics.g2);
  }
  //Clears a part of the screen
  public void wipe(int x, int y, int dx, int dy, Graphics2D g2) {
    //Wipes the BufferedImage
    g2.setComposite(clear_composite);
    g2.setColor(transparent);
    g2.fillRect(x, y, dx, dy);
    //Allows things to be properly drawn again
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
  }
  //creates interactions with the sketch.
  public OverlayUpkeep overlayInstance=new OverlayUpkeep();
  public class OverlayUpkeep {
    //Updates the mouse positions
    public void pre() {
      sketch.pmouseX=mousePos.x;
      sketch.pmouseY=mousePos.y;
      mousePos=MouseInfo.getPointerInfo().getLocation();
      sketch.mouseX=mousePos.x;
      sketch.mouseY=mousePos.y;
    }
    public void mouseEvent(processing.event.MouseEvent e) {
      pre();
    }
    //Updates the canvas after each draw
    public void draw() {
      paintLock=true;
      //refresh the canvas
      canv.repaint();
      //Stopps the sketch until the canvas is done painting
      while (paintLock);
    }
  }
  //Canvas used for the window
  public class ResultOutput extends JPanel {
    public void paintComponent(Graphics g) {
      //Wipes the screen before putting the current image there
      Graphics2D g2=(Graphics2D)g;
      wipe(0, 0, getWidth(), getHeight(), g2);
      //The use of BufferStrategy was ditched because it wasn't compatible with transparent pixels.
      //This is the reason the already existing SmoothCanvas wasn't used.
      g.drawImage(graphics_internal, 0, 0, sketch.displayWidth, sketch.displayHeight, null);
      paintLock=false;
      //This allows you to always click onto the window below
      if (alwaysAllow) {
        //Wipes the pixel under the cursor
        mousePos=MouseInfo.getPointerInfo().getLocation();
        wipe(mousePos.x, mousePos.y, 1, 1, g2);
      }
    }
  }
  //Uses already existing listeners from the canvas of the standard processing windows and puts them onto the new panel
  public void addListeners() {
    Canvas scanv=(Canvas)((PSurfaceAWT)sketch.getSurface()).getNative();
    for (MouseListener ml : scanv.getMouseListeners()) canv.addMouseListener(ml);
    for (MouseMotionListener ml : scanv.getMouseMotionListeners()) canv.addMouseMotionListener(ml);
    for (MouseWheelListener ml : scanv.getMouseWheelListeners()) canv.addMouseWheelListener(ml);
    for (KeyListener kl : scanv.getKeyListeners()) canv.addKeyListener(kl);
    for (FocusListener kl : scanv.getFocusListeners()) canv.addFocusListener(kl);
  }
}
4 Likes

I get this error when trying to run the source code on macos (not sure how to fix):
err1

File “OverlayHandler.java” should have extension “.java”.
If you prefer it to keep it as “.pde”, declare class OverlayHandler as static then.

3 Likes

If you prefer it to keep it as “.pde”, declare class OverlayHandler as static then.
Fixed it; thanks.

This is fantastic!

Is there a way that mouse clicks and other mouse events could be propagated so that you can continue to use other programs through the overlay?

Edit: I just noticed the following code in OverlayHandler.java but it doesn’t seem to work for me on macOS 13.4 and Processing 4.4.1.

//One needs to be careful when shapes block the cursor as these may take away the ability to click on the window below.
  //Having this on makes the mouse only be able to interact with the window below.
  public boolean alwaysAllow=false;
  public void alwaysAllowClicking(boolean b) {
    alwaysAllow=b;
  }

Another thing I noticed is that mouseY is reporting the wrong position because it doesn’t account for the taskbar height.

I have never used macos before.
The sketch is supposed to already do that if you click on an area where noting is drawn.
Have you tried both variants of the OverlayHandler in the post?

If it still doesn’t work, could you check if the following code does? This is supposed to just create an invisible window one should be able to use the windows under it.
If this works setting the variable show to true should create a little overlay. One should also be able to use the window below there. Note that this code will exit the program after 10s.

Testing Code
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
Canvas canv=new ResultOutput();
JFrame drawingFrame=new JFrame("CustomWindow");

boolean show=false;

void setup() {
  size(50, 50);
  //creates an empty window
  drawingFrame.setUndecorated(true);
  drawingFrame.setBackground(new Color(0, 0, 0, 0));
  drawingFrame.add(canv);
  drawingFrame.setLocation(0,0);
  canv.setBackground(new Color(0, 0, 0, 0));
  drawingFrame.setSize(displayWidth, displayHeight);
  drawingFrame.setAlwaysOnTop(true);

  drawingFrame.setVisible(true);
  drawingFrame.getRootPane().putClientProperty("apply.awt.draggableWindowBackground", false);
  drawingFrame.pack();
  //hides the Processing window
  getSurface().setVisible(false);
}
Point p=MouseInfo.getPointerInfo().getLocation();
void draw() {
  //get the mousePosition
  p=MouseInfo.getPointerInfo().getLocation();
  canv.revalidate();
  //refresh the canvas
  SwingUtilities.updateComponentTreeUI(drawingFrame);
  if (millis()>10000) exit();
}
void mousePressed() {
}
public class ResultOutput extends Canvas {
  public void paint(Graphics g) {
    if (show) {
      int strokeWidth=5;
      Graphics2D g2=(Graphics2D) g;
      //here you can paint the screen
      g2.setColor(Color.BLACK);
      g2.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
      g2.drawLine(displayWidth/2, displayHeight/2, p.x, p.y);
      //g2.drawOval(p.x,p.y,strokeWidth/2,strokeWidth/2);

      //This allows you to always click
      g2.clearRect(p.x, p.y, 1, 1);
    }
  }
}

Thanks for your response :smiley:

I’ve tried both. In the first version the circle doesn’t follow the mouse. In the second one it does. In both cases clicks are not going through.

I tried it and I’m also unable to interact with the windows below.

Happy to run any other sketches to test this out.

If this can work reliably across platforms, it would make a great Processing library.

I tried to look up the issue and found solutions using very similar code to mine to
i.e. ( cocoa - How to create an overlay window in Java? - Stack Overflow)

This would be a minimal example for processing and java that should create an invisible window and a circle in the top left area of the window.

Processing example
import javax.swing.*;
import java.awt.*;
void setup() {
  JWindow jw=new JWindow();
  JPanel jp=new JPanel() {
    @Override
      public void paint(Graphics g) {
      Graphics2D g2=(Graphics2D)g;
      g2.fillOval(40, 40, 20, 20);
    }
  };
  jw.setBackground(new Color(0, 0, 0, 0));
  jp.setBackground(new Color(0, 0, 0, 0));
  jw.setAlwaysOnTop(true);
  jw.setLocation(0, 0);
  jp.setOpaque(false);
  jp.setPreferredSize(Toolkit.getDefaultToolkit().getScreenSize());
  jw.setContentPane(jp);
  jw.getRootPane().putClientProperty("apply.awt.draggableWindowBackground", false);
  jw.pack();
  new java.util.Timer().schedule(new java.util.TimerTask(){public void run(){System.exit(0);}},10000);
  jw.setVisible(true);
}
Java example
package overlayTest;
import javax.swing.*;
import java.awt.*;
public class OverlayWindowJava {
	public static void main(String[] args) {JWindow jw=new JWindow();
	  JPanel jp=new JPanel() {
		    @Override
		      public void paint(Graphics g) {
		      Graphics2D g2=(Graphics2D)g;
		      g2.fillOval(40, 40, 20, 20);
		    }
		  };
		  jw.setBackground(new Color(0, 0, 0, 0));
		  jp.setBackground(new Color(0, 0, 0, 0));
		  jw.setAlwaysOnTop(true);
		  jw.setLocation(0, 0);
		  jp.setOpaque(false);
		  jp.setPreferredSize(Toolkit.getDefaultToolkit().getScreenSize());
		  jw.setContentPane(jp);
		  jw.getRootPane().putClientProperty("apply.awt.draggableWindowBackground", false);
		  jw.pack();
		  new java.util.Timer().schedule(new java.util.TimerTask(){public void run(){System.exit(0);}},10000);
		  jw.setVisible(true);
	}
}

I tried the Processing version and it runs but there is still a visible sketch window and clicks still don’t work :face_with_diagonal_mouth:

In the processing example I didn’t dispose of the default window, so it showing up isn’t suprising.
But the window transparency not completly working is weird… Can you try the java example?
If this does work I need to look into how Processing works internally a little more.
If not I need to look into the java part a little more.

The following source code will produce a transparent, draggable window on macos, but it will not allow click through.

import javax.swing.*;

void buildWnd() {
  JFrame frame = new JFrame();
  frame.setUndecorated(true);
  frame.setBounds(100, 100, 300, 300);
  frame.setAlwaysOnTop(true);
  frame.getRootPane().putClientProperty("apple.awt.draggableWindowBackground", true);
  frame.setLayout(null);
  frame.setOpacity(0.55);
  frame.setVisible(true);
}

void setup() {
  surface.setVisible(false);
  javax.swing.SwingUtilities.invokeLater(()-> {
    buildWnd(); // Builds components on EventDispatchThread
  }
  );
}

Output:

Svan, do you have the same problem with not being able to click through the overlay? You mentioned that you are on MacOS. Does the window become “click through”, when you set opacity to 0 rather than 0.55?

I can’t even see it a 0.0, but tested at 0.125 and couldn’t click through.

One can’t see it at 0.0 as it is completely transparent so you’ll need to try and click at the position where the now invisible window appears. I heard that with macos on can set opacity to something like 0.01 and you can click through but that may be dependent on the version of the macos.

Does the original code work for you? (Can you click through the window?)

The only place that click through works is in the menubar; this allows the user to ‘Quit’ the app. However, it does not work on icons on the Desktop. I’m using Sonoma 14.6.1 if that makes any difference.

This seems to be an issue with MacOS in general…
Have you tried the pure Java example frome this post?

If so does it work? If it doesn’t I’ll ask StackOverflow since this would be a Java related Problem rather than a processing-related one.

This is what I tested on MacOS; as a rule I don’t run ‘pure Java’:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import processing.awt.*;
import processing.core.*;

public static class OverlayHandler {
  public JPanel canv=new ResultOutput();
  public JFrame drawingFrame=new JFrame("OverlayWindow");
  public BufferedImage graphics_internal;
  public PGraphicsJava2D overridenPGraphics;
  public PApplet sketch;
  public final Color transparent=new Color(0, 0, 0, 0);
  public AlphaComposite clear_composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
  public Point mousePos=MouseInfo.getPointerInfo().getLocation();

  //Creates an OverlayHandler
  public OverlayHandler() {
  }
  public static OverlayHandler create(PApplet pa) {
    OverlayHandler ret=new OverlayHandler();
    ret.setupOverlay(pa);
    return ret;
  }

  //Sets up the Overlay. This should be called in setup before any painting takes place.
  public void setupOverlay(PApplet pa) {
    //hides the Processing window
    pa.getSurface().setVisible(false);
    sketch=pa;
    //creates the BufferedImage
    graphics_internal=new BufferedImage(pa.displayWidth, pa.displayHeight, BufferedImage.TYPE_INT_ARGB);
    //creates an empty window
    drawingFrame.setUndecorated(true);
    drawingFrame.setBackground(transparent);
    //Adds the canvas (it will later only show a BufferedImage)
    canv.setFocusable(true);
    canv.setFocusTraversalKeysEnabled(false);
    canv.setBackground(transparent);
    drawingFrame.setLayout(null);
    drawingFrame.setSize(pa.displayWidth, pa.displayHeight);
    canv.setPreferredSize(new Dimension(pa.displayWidth, pa.displayHeight));
    //canv.setSize(pa.displayWidth, pa.displayHeight);
    drawingFrame.setLayout(null);
    drawingFrame.setContentPane(canv);
    drawingFrame.setAlwaysOnTop(true);
    //Puts the window on the screen
    drawingFrame.setVisible(true);
    //The window can't be moved
    drawingFrame.getRootPane().putClientProperty("apply.awt.draggableWindowBackground", false);
    drawingFrame.pack();
    //Creates a PGraphicsJava2D object that used the image given here as its output
    overridenPGraphics=new PGraphicsJava2D() {
      @Override public Graphics2D checkImage() {
        return (Graphics2D) graphics_internal.getGraphics();
      }
    };
    //Sets up the PGraphics object
    overridenPGraphics.setParent(pa);
    overridenPGraphics.setSize(pa.displayWidth, pa.displayHeight);
    overridenPGraphics.image=graphics_internal;
    overridenPGraphics.g2=overridenPGraphics.checkImage();
    //All graphics commands from processing now run through this object
    pa.g=overridenPGraphics;
    pa.registerMethod("draw", overlayInstance);
    pa.registerMethod("pre", overlayInstance);
    pa.registerMethod("mouseEvent", overlayInstance);
    addListeners();
  }
  //One needs to be careful when shapes block the cursor as these may take away the ability to click on the window below.
  //Having this on makes the mouse only be able to interact with the window below.
  public boolean alwaysAllow=false;
  public void alwaysAllowClicking(boolean b) {
    alwaysAllow=b;
  }
  //Clears the screen
  public void wipe() {
    wipe(0, 0, sketch.displayWidth, sketch.displayHeight);
  }
  //Prevents the sketch from continuing while the canvas is painting.
  public volatile boolean paintLock=false;
  //Clears a part of the screen
  public void wipe(int x, int y, int dx, int dy) {
    wipe(x, y, dx, dy, overridenPGraphics.g2);
  }
  //Clears a part of the screen
  public void wipe(int x, int y, int dx, int dy, Graphics2D g2) {
    //Wipes the BufferedImage
    g2.setComposite(clear_composite);
    g2.setColor(transparent);
    g2.fillRect(x, y, dx, dy);
    //Allows things to be properly drawn again
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
  }
  //creates interactions with the sketch.
  public OverlayUpkeep overlayInstance=new OverlayUpkeep();
  public class OverlayUpkeep {
    //Updates the mouse positions
    public void pre() {
      sketch.pmouseX=mousePos.x;
      sketch.pmouseY=mousePos.y;
      mousePos=MouseInfo.getPointerInfo().getLocation();
      sketch.mouseX=mousePos.x;
      sketch.mouseY=mousePos.y;
    }
    public void mouseEvent(processing.event.MouseEvent e) {
      pre();
    }
    //Updates the canvas after each draw
    public void draw() {
      paintLock=true;
      //refresh the canvas
      canv.repaint();
      //Stops the sketch until the canvas is done painting
      while (paintLock);
    }
  }
  //Canvas used for the window
  public class ResultOutput extends JPanel {
    public void paintComponent(Graphics g) {
      //Wipes the screen before putting the current image there
      Graphics2D g2=(Graphics2D)g;
      wipe(0, 0, getWidth(), getHeight(), g2);
      //The use of BufferStrategy was ditched because it wasn't compatible with transparent pixels.
      //This is the reason the already existing SmoothCanvas wasn't used.
      g.drawImage(graphics_internal, 0, 0, sketch.displayWidth, sketch.displayHeight, null);
      paintLock=false;
      //This allows you to always click onto the window below
      if (alwaysAllow) {
        //Wipes the pixel under the cursor
        mousePos=MouseInfo.getPointerInfo().getLocation();
        wipe(mousePos.x, mousePos.y, 1, 1, g2);
      }
    }
  }
  //Uses already existing listeners from the canvas of the standard processing windows and puts them onto the new panel
  public void addListeners() {
    Canvas scanv=(Canvas)((PSurfaceAWT)sketch.getSurface()).getNative();
    for (MouseListener ml : scanv.getMouseListeners()) canv.addMouseListener(ml);
    for (MouseMotionListener ml : scanv.getMouseMotionListeners()) canv.addMouseMotionListener(ml);
    for (MouseWheelListener ml : scanv.getMouseWheelListeners()) canv.addMouseWheelListener(ml);
    for (KeyListener kl : scanv.getKeyListeners()) canv.addKeyListener(kl);
    for (FocusListener kl : scanv.getFocusListeners()) canv.addFocusListener(kl);
  }
}

OverlayHandler overlayHandler;

void setup() {
  //creates the handler
  overlayHandler=OverlayHandler.create(this);
}
void draw() {
  //Wipes the screen
  overlayHandler.wipe();
  stroke(0);
  strokeWeight(3);
  fill(255);
  ellipse(300, 300, 20, 20);
  noFill();
  stroke(255,0,0);
  ellipse(mouseX,mouseY,150,150);

}
void mousePressed(){
 // println("Mouse was Pressed at",mouseX,mouseY);
}
void keyPressed(){
  if(key==ESC) exit();
}

I was able to run the java example and it still prevents clicks.

1 Like

Ok, then I’ll ask on StackOverflow if they know this issue and how to solve it!
Thanks for your help!

1 Like

If anyone wants to use the current version of this code there would be a link to a library based on this code. This works a little different than the code posted here although the backend is almost the same:

The source code and the library as well as a few examples are in the UsefulRenderers.zip file.

Edit: (Hopefully) fixed the link.