Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JPackage'd app has font issue #580

Closed
remcopoelstra opened this issue Aug 22, 2022 · 11 comments
Closed

JPackage'd app has font issue #580

remcopoelstra opened this issue Aug 22, 2022 · 11 comments

Comments

@remcopoelstra
Copy link

I want to switch to JPackage for distributing my apps, everything seemed ok until my laptop had been sleeping for a while, after waking it up all texts are twice as large (can be reproduced).

I only see this happening when using FlatLaf (tested default laf and nimbus).
Before sleeping:
before

After sleeping:
after

I created a small program for testing this

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import com.formdev.flatlaf.FlatIntelliJLaf;

public class JPackageTest {

	// cd C:\project\temp
	// "C:\tools\OpenJDK17U-jdk_x64_windows_hotspot_17.0.4_8\jdk-17.0.4+8\bin\jpackage" --type app-image --name JPackageTest --input "C:\project\temp\JPackageTestInput" --main-class JPackageTest --main-jar JPackageTest.jar --dest "C:\project\temp\JPackageTestOutput"

	public JPackageTest() {

		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setTitle("JPackageTest");
		frame.setSize(400, 250);

		frame.getContentPane().setLayout(new BorderLayout());

		JLabel label = new JLabel();
		label.setHorizontalAlignment(JLabel.CENTER);
		frame.getContentPane().add(label, BorderLayout.CENTER);

		new Timer(1000, new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				label.setText("Font size: " + label.getFont().getSize());
			}
		}).start();

		frame.setLocationRelativeTo(null);
		frame.setVisible(true);

	}

	public static void main(String[] args) {

		SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run() {

				try {
					UIManager.setLookAndFeel(new FlatIntelliJLaf());
				} catch (UnsupportedLookAndFeelException e) {
					e.printStackTrace();
				}

				new JPackageTest();

			}
		});

	}

}

The jar was built with maven and I used the following JPackage command to create the app-image:

"C:\tools\OpenJDK17U-jdk_x64_windows_hotspot_17.0.4_8\jdk-17.0.4+8\bin\jpackage" --type app-image --name JPackageTest --input "C:\project\temp\JPackageTestInput" --main-class JPackageTest --main-jar JPackageTest.jar --dest "C:\project\temp\JPackageTestOutput"

I am running windows 10 on a surface book 3, hidpi scaled 200%, and tested with FlatLaf 2.4, OpenJDK 17.0.4

@remcopoelstra
Copy link
Author

I looked into this a little deeper, the base font on which the default font is created seems to have a wrong size in this situation, FlatLaf.java line 581:

Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.messagebox.font" );

This starts returning a font with size 24.

I don't know why the look and feel is initialized again here.

I also just did a test with OpenJDK-19+36-RC1-beta and I haven't been able to reproduce the problem yet, so maybe it already got fixed.

@DevCharly
Copy link
Collaborator

... laptop had been sleeping for a while ...

How long is it necessary to let the laptop sleep?
Tried several minutes, but it does not occur here (Windows 10, 200% scale, Adoptium OpenJDK 17.0.4+8)

@remcopoelstra
Copy link
Author

On my system I was able to reproduce it almost every time by pressing the power button and waking it up again by pressing the space bar after 5 - 10 seconds.

@remcopoelstra
Copy link
Author

I also just tested on a Windows 11 system with 150% scale (Surface Go 2), here the OpenJDK-17 JPackage'd app also shows a larger text after sleeping (text size 18), the OpenJDK-19 version still seems ok. If you want I can upload a zip and mail you a link.

@DevCharly
Copy link
Collaborator

If you want I can upload a zip and mail you a link.

Yes, that would be great. Send link to support at formdev dot com

What OpenJDK distro do you use? Adoptium, Zulu, etc?

@remcopoelstra
Copy link
Author

I just sent you a mail with a download link.

I am also using the Adoptium distro (I downloaded the .zip from adoptium.net)

DevCharly added a commit that referenced this issue Aug 24, 2022
…isabling automatic UI update when system font changes (issue #580)
@DevCharly
Copy link
Collaborator

Thanks for the app download.

Still don't see the effect on sleep-wakeup, but it also occurs when changing various UI related options in Windows Settings app. E.g. text size, accent color, cleartype on/off, always show scrollbars on/off, transparency effects on/off, etc.

Since Java updates its desktop properties when it receives WM_SETTINGCHANGE message, I assume that all those options send that message.

FlatLaf listens to changes of desktop property win.messagebox.font and updates the UI.
This property is changed when the user changes text size in Windows Settings app
(Windows 11: Accessibility > Text size; Windows 10: Ease of Access > Display > Make text bigger).
All native applications immediately change the text size and I thought that it would be a good idea that Java applications also work this way.

FlatLaf also listens to desktop property awt.font.desktophints, which is changed when ClearType is disabled/enabled.

There is no way to disable this in FlatLaf 2.4 and earlier.
For FlatLaf 2.5 I've added an option to disable this feature via system property:

-Dflatlaf.updateUIOnSystemFontChange=false

Or in Java code:

System.setProperty( "flatlaf.updateUIOnSystemFontChange", "false" );

However this is not a solution for this issue.
If the application has a feature to toggle between light/dark FlatLaf themes, this still can happen.

The strange thing is that this occurs only with JPackaged apps.

Since JDK 19rc the issue seems to be fixed. Looked at the history of changes in jpackage since Java 18, but did not find any related commit: https://github.com/openjdk/jdk/tree/master/src/jdk.jpackage
Also did not find anything in Java 19 release notes or in bugs.openjdk.java.net

@DevCharly
Copy link
Collaborator

BTW logging can be enabled to see what desktop properties are changed.

Create a log config file (e.g. platform-logger.properties):

handlers= java.util.logging.FileHandler
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.FileHandler.pattern = platform-log.txt
java.util.logging.SimpleFormatter.format=%5$s%6$s%n

sun.awt.windows.WDesktopProperties.level = FINE

And enable it with java option:

-Djava.util.logging.config.file=platform-logger.properties

When running JPackage'd app and compare log of startup with log after disabling ClearType, there are a lot of differences, which are all scaling related (BTW log produced with 150% scaling):

image

For comparison, app started with java.exe has only a single difference (ClearType disabled):

image

@remcopoelstra
Copy link
Author

Thanks, that's a lot of interesting information! I've also been looking around for commits/bugs that could explain why JDK19 is ok, but couldn't find anything either. All I can see is that the desktop properties from your screenshot are retrieved in AwtDesktopProperties::GetNonClientParameters() here:

https://github.com/openjdk/jdk/blob/master/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp

using the winapi function SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ... which is not dpi-aware, so they are scaled on the jvm side while setting the property. So my guess is that the scaling factor is 1.0 for some reason when our bug occurs. There was a recent change to this scaling code but I cannot see how this could have fixed the bug. I believe that the winapi function GetDeviceCaps(hDC, LOGPIXELSX) which is used for getting the scale can return different values depending on whether the application is registered as dpi aware or not, so maybe the JPackage'd app was not handling this correctly..

I agree that having FlatLaf update the UI when the font changes is a good idea, and the new option to turn it off so we can work around jpackage/jdk bugs is a very nice solution!

Thanks for all your great work!

@remcopoelstra
Copy link
Author

I was curious how java handles dpi-awareness on windows and had another look, as far as I can tell it is declared in manifest in the .exe, after un-7zipping the .exe's off the different JPackage'd apps I noticed the JDK19 version has a manifest but the JDK17 version does not.

I found the following bug report: "jpackage.exe" creates application launcher without Windows Application Manfiest
https://bugs.openjdk.org/browse/JDK-8284675

I still don't understand how this can cause the scale to be ok first and wrong later, but I think this might be the one we were looking for.

@remcopoelstra
Copy link
Author

Closed because this is not a FlatLaf issue, and fixed since JDK19.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants