diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index a23a361bc..d15598008 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -733,7 +733,7 @@ public class PApplet implements PConstants { */ static public final String ARGS_SKETCH_FOLDER = "--sketch-path"; - static public final String ARGS_DENSITY = "--density"; + static public final String ARGS_UI_SCALE = "--ui-scale"; /** * When run externally to a PdeEditor, @@ -785,11 +785,9 @@ public class PApplet implements PConstants { boolean fullScreen; int display = -1; // use default -// GraphicsDevice[] displayDevices; // Unlike the others above, needs to be public to support // the pixelWidth and pixelHeight fields. public int pixelDensity = 1; - int suggestedDensity = -1; boolean present; @@ -10181,19 +10179,6 @@ public class PApplet implements PConstants { uncaughtThrowable = e; }); - /* - if (platform == WINDOWS) { - // Set DPI scaling to either 1 or 2, but avoid fractional versions like - // 125% and 250% that make things look gross, or even 300% since that - // is not even a thing. - int dpi = java.awt.Toolkit.getDefaultToolkit().getScreenResolution(); // no longer possible to set prop after this line - System.out.println("dpi came back " + dpi); - int scaleFactor = constrain(dpi / 96, 1, 2); - System.out.println("setting scale factor to " + scaleFactor); - System.setProperty("sun.java2d.uiscale", String.valueOf(scaleFactor)); - } - */ - // This doesn't work, need to mess with Info.plist instead /* // In an exported application, add the Contents/Java folder to the @@ -10234,10 +10219,8 @@ public class PApplet implements PConstants { boolean hideStop = false; int displayNum = -1; // use default -// boolean fullScreen = false; boolean present = false; -// boolean spanDisplays = false; - int density = -1; + float uiScale = 0; String param, value; String folder = calcSketchPath(); @@ -10286,13 +10269,10 @@ public class PApplet implements PConstants { } else if (param.equals(ARGS_LOCATION)) { location = parseInt(split(value, ',')); - } else if (param.equals(ARGS_DENSITY)) { - density = parseInt(value, -1); - if (density == -1) { - System.err.println("Could not parse " + value + " for " + ARGS_DENSITY); - } else if (density != 1 && density != 2) { - density = -1; - System.err.println(ARGS_DENSITY + " should be 1 or 2"); + } else if (param.equals(ARGS_UI_SCALE)) { + uiScale = parseFloat(value, 0); + if (uiScale == 0) { + System.err.println("Could not parse " + value + " for " + ARGS_UI_SCALE); } } @@ -10300,9 +10280,6 @@ public class PApplet implements PConstants { if (args[argIndex].equals(ARGS_PRESENT)) { present = true; -// } else if (args[argIndex].equals(ARGS_SPAN_DISPLAYS)) { -// spanDisplays = true; - } else if (args[argIndex].equals(ARGS_HIDE_STOP)) { hideStop = true; @@ -10317,6 +10294,29 @@ public class PApplet implements PConstants { argIndex++; } + if (platform == WINDOWS) { + // Set DPI scaling to either 1 or 2, but avoid fractional + // settings such as 125% and 250% that make things look gross. + // Also applies to 300% since that is not even a thing. + + // no longer possible to set prop after this line initializes AWT + //int dpi = java.awt.Toolkit.getDefaultToolkit().getScreenResolution(); + + // Attempt to get the resolution using a helper app. This code is + // fairly conservative: if there is trouble, we go with the default. + if (uiScale == 0) { + int dpi = getWindowsDPI(); + if (dpi != 0) { + uiScale = constrain(dpi / 96, 1, 2); + } + } + if (uiScale != 0) { + System.setProperty("sun.java2d.uiScale", String.valueOf(uiScale)); + } else { + System.err.println("Could not identify Windows DPI, not setting sun.java2d.uiScale"); + } + } + if (!disableAWT) { ShimAWT.initRun(); } @@ -10357,10 +10357,6 @@ public class PApplet implements PConstants { // (and most likely, from the PDE's preference setting). sketch.display = displayNum; - // Set the suggested density that is coming from command line - // (most likely set from the PDE based on a system DPI scaling) - sketch.suggestedDensity = density; - sketch.present = present; // For 3.0.1, moved this above handleSettings() so that loadImage() can be @@ -10526,6 +10522,46 @@ public class PApplet implements PConstants { } + /** + * Find the location of fenster.exe by walking through java.library.path. + * (It will be on the path because it's part of core/library/windows-amd64) + */ + static private String findFenster() { + String libraryPath = System.getProperty("java.library.path"); + // Should not be null, but cannot assume + if (libraryPath != null) { + String[] folders = split(libraryPath, ';'); + // Usually, the most relevant paths will be at the front of the list, + // so hopefully this will not walk several entries. + for (String folder : folders) { + File file = new File(folder, "fenster.exe"); + if (file.exists()) { + return file.getAbsolutePath(); + } + } + } + return null; + } + + + /** + * Get the display scaling for Windows by calling out to a helper app. + * https://github.com/processing/processing4/tree/master/build/windows/fenster + */ + static private int getWindowsDPI() { + String fensterPath = findFenster(); + if (fensterPath != null) { + StringList stdout = new StringList(); + StringList stderr = new StringList(); + int result = exec(stdout, stderr, fensterPath); + if (result == 0) { + return parseInt(stdout.join(""), 0); + } + } + return 0; + } + + /** * Convenience method for Python Mode to run an already-constructed sketch. * This makes it makes it easy to launch a sketch in Jython: diff --git a/java/src/processing/mode/java/runner/Runner.java b/java/src/processing/mode/java/runner/Runner.java index ee424b4d9..7871a5dcd 100644 --- a/java/src/processing/mode/java/runner/Runner.java +++ b/java/src/processing/mode/java/runner/Runner.java @@ -24,7 +24,6 @@ package processing.mode.java.runner; import processing.app.*; import processing.app.exec.StreamRedirectThread; -import processing.app.ui.Toolkit; import processing.core.*; import processing.data.StringList; import processing.mode.java.JavaBuild; @@ -33,6 +32,7 @@ import processing.mode.java.JavaEditor; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Point; +import java.awt.Toolkit; import java.io.*; import java.net.ConnectException; import java.net.InetAddress; @@ -490,9 +490,17 @@ public class Runner implements MessageConsumer { // removed for 3.0a6 because it would break the args passed to sketches. params.append(PApplet.ARGS_SKETCH_FOLDER + "=" + build.getSketchPath()); + /* if (Toolkit.zoom(100) >= 200) { // Use 100 to bypass possible rounding in zoom() params.append(PApplet.ARGS_DENSITY + "=2"); } + */ + if (Platform.isWindows()) { + // Pass the DPI setting to the app to avoid using the helper app. + int dpi = Toolkit.getDefaultToolkit().getScreenResolution(); + int uiScale = PApplet.constrain(dpi / 96, 1, 2); + params.append(PApplet.ARGS_UI_SCALE + "=" + uiScale); + } params.append(build.getSketchClassName()); }