I came up with another solution that uses another weakpoint specificy for when using JOGL.
processing/PSurfaceJOGL.java at master · processing/processing · GitHub
At this point a new Thread is dispatched and by checking all active threads you can find out that it has the name “Thread-3” from there you can get the Runnable
Thread.target. This is a inner class of PSurfaceJOGL so you can use this$0 to get it. And PSurfaceJOGL has a field called sketch. This can be combined with the solution for JAVA2D to cover all possibilities.
This solution probably will work with processing 4 with a few adjustments as processing 4 also dispatches the same thread with the one difference that lambdas are used.
processing4/PSurfaceJOGL.java at master · processing/processing · GitHub
Here is the code that worked in the end:
import processing.awt.*;
import processing.opengl.*;
import processing.core.*;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.lang.reflect.*;
/**This class finds the active PApplet (Processing program)*/
public class PAppletFinder {
/**This class takes the contents of the window and pieces together the PApplet
* @return PApplet of the current sketch.
* @param c contents of the Processing window (must be a SmoothCanvas)*/
public static PApplet get(Component c) {
PSurfaceAWT.SmoothCanvas sc=(PSurfaceAWT.SmoothCanvas) c;
try {
PSurfaceAWT psa=(PSurfaceAWT) get(sc, "this$0", sc.getClass());
PApplet prg=(PApplet) get((PSurfaceNone)psa, "sketch", PSurfaceNone.class);
return prg;
}
catch(Exception e) {
e.printStackTrace();
}
return null;
}
public static PApplet foundPapplet=null;
/**The main method to be used when using the PAppletFinder*/
public static PApplet find() {
if (foundPapplet==null) foundPapplet=findFromWindow();
if (foundPapplet==null) foundPapplet=fromThreads();
return foundPapplet;
}
/**This looks out for windows and gives the contents of the right one to the get method
* @return PApplet of the current sketch.*/
public static PApplet findFromWindow() {
JFrame mainWindow=null;
java.awt.Window win[]=java.awt.Window.getWindows();
for (int i=0; i<win.length&&mainWindow==null; i++) if (win[i] instanceof JFrame) {
mainWindow=(JFrame) win[i];
Component c=mainWindow.getContentPane().getComponents()[0];
return get(c);
}
return null;
}
/**This is used to get the value of fields
* @return Object value of a field
* @param j the Object from which the value is taken
* @param target name of the field*/
public static Object get(Object j, String target, Class<?> ref) {
try {
Field f=ref.getDeclaredField(target);
f.setAccessible(true);
return f.get(j);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**When using P2D or P3D everything is built differently however there is a weakness to be found in PSurfaceJOGL as it dispatches a Thread using an annonymous inner class as Runnable*/
public static PApplet fromThreads() {
Set<Thread> threadSet=Thread.getAllStackTraces().keySet();
//println(Thread.currentThread().getThreadGroup());
for (Thread th : threadSet) if (th.getName().matches("Thread-3")) {
//println(" ");
//println("Thread: Class:"+th.getClass()+" Name:"+th.getName()+" Daemon:"+th.isDaemon());
{
try {
//for (Field f : th.getClass().getDeclaredFields()) println(f);
Field f=th.getClass().getDeclaredField("target");
f.setAccessible(true);
Object currinstance=null;
currinstance=f.get(th);
currinstance=getEnclosingInstance(currinstance);
f=PSurfaceJOGL.class.getDeclaredField("sketch");
f.setAccessible(true);
return (PApplet) (currinstance=f.get(currinstance));
}
catch(Exception e) {
System.err.println("An error occurred");
}
}
//innerClassesLoaded(th);
}
return null;
}
public static Object getEnclosingInstance(Object o) {
try {
Class<?> classused=o.getClass();
Field this0=classused.getDeclaredField("this$0");
this0.setAccessible(true);
return this0.get(o);
}
catch(Exception e) {
return null;
}
}
}
An example-sketch using this would be:
void setup() {
size(300,300,JAVA2D);
println(this,PAppletFinder.find());
}
void draw() {
}