Hello folks!
This is an exploration of native window access in P2D/P3D and JAVA2D.
In my Windows 10 environment, I was seeing offsets, and I was compelled to understand why.
And now I do!
This is an advanced topic and Chat GPT was used to support this research.
P2D Code
// Author: GLV
// Date: 2026-04-14
// ChatGPT supported.
// Description:
// This is an exploration of native window access in P2D/P3D,
// where the underlying GLWindow lets us read the window insets.
// This is displayed in console:
// The sketch has been resized from 1920x1200 to 1920x1181 by the operating system.
// This happened outside Processing, and may be a limitation of the OS or window manager.
import com.jogamp.newt.opengl.GLWindow;
void settings()
{
int w = displayWidth;
int h = displayHeight;
size(w, h, P2D); // or P3D
}
void setup()
{
GLWindow glw = (GLWindow) surface.getNative();
int left = glw.getInsets().getLeftWidth();
int right = glw.getInsets().getRightWidth();
int top = glw.getInsets().getTopHeight();
int bottom = glw.getInsets().getBottomHeight();
println("Insets L/T/R/B = " + left + " / " + top + " / " + right + " / " + bottom);
// Give these a try:
//surface.setVisible(true); // Show (true) or hide (false) the window
//surface.setLocation(0, 0); // Set desired window position (0, 0); frame insets will shift the sketch area.
//surface.setLocation(-in.left, 0); // Offsets the left frame border so the sketch area starts at the desired position.
//surface.setResizable(true); // Lets the window be resized or maximized
}
void draw()
{
fill(random(64, 128+64));
circle(random(width), random(height), 20);
}
JAVA2D Code
// Author: GLV
// Date: 2026-04-14
// ChatGPT support
// Description:
// This is an exploration of native window access in JAVA2D,
// where the underlying AWT Frame lets us read the window insets.
import processing.awt.PSurfaceAWT;
import java.awt.Insets;
void settings()
{
int w = displayWidth;
int h = displayHeight;
println(w, h);
size(w, h, JAVA2D);
}
void setup()
{
PSurfaceAWT.SmoothCanvas canvas = (PSurfaceAWT.SmoothCanvas) surface.getNative();
Insets in = canvas.getFrame().getInsets();
println("Insets L/T/R/B = " + in.left + " / " + in.top + " / " + in.right + " / " + in.bottom);
// Give these a try:
//surface.setVisible(true); // Show (true) or hide (false) the window
//surface.setLocation(0, 0); // Set desired window position (0, 0); frame insets will shift the sketch area.
//surface.setLocation(-in.left, 0); // Offsets the left frame border so the sketch area starts at the desired position.
//surface.setResizable(true); // Lets the window be resized or maximized
}
void draw()
{
fill(random(64, 128+64));
circle(random(width), random(height), 20);
}
Insets:
Insets L/T/R/B = 8 / 31 / 8 / 8
There is more going on here than just Java calling getInsets(). On my Windows system, the returned inset values also line up exactly with the Win32 metrics documented here:
A lot of details sit between those layers.
This was certainly an adventure.
I will post an update later… and now is later and I added to post below.
That was fun!
ChatGPT research:
Summary
For transparency:
ChatGPT supported my research, analysis, wording, and drafting of this test, while the direction, review, and interpretation were guided by me.
It is subject to scrutiny and I have not included the 800+ word research which includes references.
This was not a simple task and took a lot of iterations to get to this point.
This test compares
Frame.getInsets()insetup()and again in the firstdraw(), then compares both results to the corresponding Win32 metrics returned byGetSystemMetrics(). The goal is to check whether the inset values remain stable across both phases and whether they line up with the Windows frame, caption, and padded-border metrics. The output shows the actual Java/AWT inset values, the raw Windows metric values, the derived inset math, and whether the results match. It does not determine which internal AWT path produced the values, only whether the final values agree.
import processing.awt.PSurfaceAWT;
import java.awt.Insets;
import java.awt.Frame;
import com.sun.jna.platform.win32.User32;
Insets inSetup;
boolean reportedInDraw = false;
void settings()
{
size(600, 400, JAVA2D);
}
void setup()
{
Frame frame = getFrameRef();
inSetup = frame.getInsets();
printInsetReport("setup()", inSetup);
}
void draw()
{
background(240);
if(reportedInDraw) return;
Frame frame = getFrameRef();
Insets inDraw = frame.getInsets();
printInsetReport("first draw()", inDraw);
println();
println("setup() vs first draw() match = " +
(inSetup.left == inDraw.left &&
inSetup.top == inDraw.top &&
inSetup.right == inDraw.right &&
inSetup.bottom == inDraw.bottom));
reportedInDraw = true;
noLoop();
}
Frame getFrameRef()
{
PSurfaceAWT.SmoothCanvas canvas = (PSurfaceAWT.SmoothCanvas) surface.getNative();
return canvas.getFrame();
}
void printInsetReport(String label, Insets in)
{
int cxFrame = User32.INSTANCE.GetSystemMetrics(32); // SM_CXFRAME
int cyFrame = User32.INSTANCE.GetSystemMetrics(33); // SM_CYFRAME
int cyCaption = User32.INSTANCE.GetSystemMetrics(4); // SM_CYCAPTION
int cxPadded = User32.INSTANCE.GetSystemMetrics(92); // SM_CXPADDEDBORDER
int leftFromMetrics = cxFrame + cxPadded;
int topFromMetrics = cyFrame + cxPadded + cyCaption;
int rightFromMetrics = cxFrame + cxPadded;
int bottomFromMetrics = cyFrame + cxPadded;
println();
println("=== " + label + " ===");
println("Actual Insets L/T/R/B = " + in.left + " / " + in.top + " / " + in.right + " / " + in.bottom);
println();
println("Raw Windows metrics:");
println("SM_CXFRAME = " + cxFrame);
println("SM_CYFRAME = " + cyFrame);
println("SM_CYCAPTION = " + cyCaption);
println("SM_CXPADDEDBORDER = " + cxPadded);
println();
println("Derived inset math:");
println("left = SM_CXFRAME + SM_CXPADDEDBORDER = " + cxFrame + " + " + cxPadded + " = " + leftFromMetrics);
println("top = SM_CYFRAME + SM_CXPADDEDBORDER + SM_CYCAPTION = " + cyFrame + " + " + cxPadded + " + " + cyCaption + " = " + topFromMetrics);
println("right = SM_CXFRAME + SM_CXPADDEDBORDER = " + cxFrame + " + " + cxPadded + " = " + rightFromMetrics);
println("bottom = SM_CYFRAME + SM_CXPADDEDBORDER = " + cyFrame + " + " + cxPadded + " = " + bottomFromMetrics);
println();
println("Derived Insets L/T/R/B = " + leftFromMetrics + " / " + topFromMetrics + " / " + rightFromMetrics + " / " + bottomFromMetrics);
println("Metric match = " +
(in.left == leftFromMetrics &&
in.top == topFromMetrics &&
in.right == rightFromMetrics &&
in.bottom == bottomFromMetrics));
}
Console output on y W10 PC:
0 launchVirtualMachine()
Free port allocated: 52159
freePort: 52159
Sketch runner port: 52159=== setup() ===
Actual Insets L/T/R/B = 8 / 31 / 8 / 8Raw Windows metrics:
SM_CXFRAME = 4
SM_CYFRAME = 4
SM_CYCAPTION = 23
SM_CXPADDEDBORDER = 4Derived inset math:
left = SM_CXFRAME + SM_CXPADDEDBORDER = 4 + 4 = 8
top = SM_CYFRAME + SM_CXPADDEDBORDER + SM_CYCAPTION = 4 + 4 + 23 = 31
right = SM_CXFRAME + SM_CXPADDEDBORDER = 4 + 4 = 8
bottom = SM_CYFRAME + SM_CXPADDEDBORDER = 4 + 4 = 8Derived Insets L/T/R/B = 8 / 31 / 8 / 8
Metric match = true=== first draw() ===
Actual Insets L/T/R/B = 8 / 31 / 8 / 8Raw Windows metrics:
SM_CXFRAME = 4
SM_CYFRAME = 4
SM_CYCAPTION = 23
SM_CXPADDEDBORDER = 4Derived inset math:
left = SM_CXFRAME + SM_CXPADDEDBORDER = 4 + 4 = 8
top = SM_CYFRAME + SM_CXPADDEDBORDER + SM_CYCAPTION = 4 + 4 + 23 = 31
right = SM_CXFRAME + SM_CXPADDEDBORDER = 4 + 4 = 8
bottom = SM_CYFRAME + SM_CXPADDEDBORDER = 4 + 4 = 8Derived Insets L/T/R/B = 8 / 31 / 8 / 8
Metric match = truesetup() vs first draw() match = true
The first part was a modified Processing to assign a free port.
:)