System.setProperty("prism.allowhidpi", "false") does not work?

1.2k views Asked by At

I'm trying to disable Windows display scaling (and in other OS) in my JavaFX application. Setting -Dprism.allowhidpi="false" in IntelliJ run configuration VM options works but setting the system property in code does not. I would like to set it in code so it works in any JVM setup like GraalVM / Gluon Substrate.

Is this a bug in JavaFX or how is it used in code? The following example does not work, the stage is scaled if scaling is set in Windows:

public class Main extends Application {

    public static void main(String[] args) {
        System.setProperty("prism.allowhidpi", "false");
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        stage.setWidth(1280);
        stage.setHeight(720);
        Scene scene = new Scene(new Label("SCALE TEST"));
        stage.setScene(scene);
        stage.show();
    }
}

EDIT: As noted in the comments, creating a seperate launcher class which sets the property and then calls the Application class works. However, it does not seem to work with Gluon Substrate. Here are relevant parts of my project. I also added two other prism properties to make sure the new main class is loaded properly in Substrate and the two other properties do indeed work. If I run mvn javafx:run the scaling is turned off, if I run mvn client:build and mvn client:run the scaling is on but everything else is the same.

public class Main {
    public static void main(String[] args) {
        System.setProperty("prism.allowhidpi", "false"); // doesn't work with Substrate
        System.setProperty("prism.lcdtext", "false"); // works
        System.setProperty("prism.subpixeltext", "false"); // works
        MainFXML.run(args);
    }
}

App

public class MainFXML extends Application {
    
    @Override
    public void start(Stage stage) throws Exception {
        String fxmlFile = "/fxml/FXMLDocument.fxml";
        FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlFile));
        Parent root = loader.load();
        root.getStylesheets().add(getClass().getResource("/styles/Style.css").toString());
        FXMLDocumentController gui = (FXMLDocumentController) loader.getController();

        Scene scene = new Scene(root);
        stage.setScene(scene); 
        stage.show();
        stage.setResizable(false);

        // create logic class etc
    }

    public static void run(String[] args) {
        launch(args);
    }
}

Pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>ank</groupId>
    <artifactId>PROJ</artifactId>
    <name>PROJ</name>

    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <finalName>PROJ</finalName>
        <plugins>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.3</version>
                <configuration>
                    <mainClass>ank.fxml.Main</mainClass>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.0.2</version>
                <configuration>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.gluonhq</groupId>
                <artifactId>client-maven-plugin</artifactId>
                <version>0.1.38</version>
                <configuration>
                    <mainClass>ank.fxml.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>15</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>15</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.11</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.6.2</version>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.9.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>
    </dependencies>

</project>

I also tried setting properties in the pom-file as nativeImageArgs, but none of them worked.

    <plugin>
        <groupId>com.gluonhq</groupId>
        <artifactId>client-maven-plugin</artifactId>
        <version>0.1.38</version>
        <configuration>
            <mainClass>ank.fxml.Main</mainClass>
            <nativeImageArgs>
                <arg>-Dprism.allowhidpi=false</arg>
                <arg>-Dprism.lcdtext=false</arg>
                <arg>-Dprism.subpixeltext=false</arg>
            </nativeImageArgs>
        </configuration>
    </plugin>
2

There are 2 answers

1
aDonut On BEST ANSWER

After much searching I managed to get this to work, at least on Windows. Instead of using the prism.allowhidpi flag, setting glass.win.uiScale to 100% did the trick to ignore Windows scaling. This worked setting it in code and passing it as an argument.

public class Main {
    public static void main(String[] args) {
        System.setProperty("glass.win.uiScale", "100%"); // instead of allowhidpi
        MainFXML.run(args);
    }
}

Be warned that setting prism.allowhidpi to false will negate the scaling override from what I tested.

0
neohope On

It seems that you want to set system environment for your app before GUI start, several ways to do that:

1.use script to start your app

#sh or cmd
#set system environment
#java -jar your_app_jar

2.use a native loader

loader[set system environment]->your app

3.use a java loader with ProcessBuilder to start you app

ProcessBuilder pb = new ProcessBuilder("your app command"); 
Map<String, String> envMap = pb.environment();
envMap.put("propName", "propValue");
pb.start();

4.use JNI or native command plus java agent in you app

//in premain
JNI[set system environment]
or 
invoke native command[set system environment]

5.use "java.lang.ProcessEnvironment" plus java agent to do the trick

//in premain
Class<?> pe = Class.forName("java.lang.ProcessEnvironment");
Method getenv = pe.getDeclaredMethod("getenv", String.class);
getenv.setAccessible(true);
Field props = pe.getDeclaredField("theCaseInsensitiveEnvironment");
props.setAccessible(true);
Map<String, String> env = (Map<String, String>) props.get(null);
env.put("propName", "propValue");