RFR: 8276849: Refresh the window icon on graphics configuration changes [v2]

Alexey Ivanov aivanov at openjdk.java.net
Sat Feb 19 16:13:54 UTC 2022


On Wed, 16 Feb 2022 14:11:51 GMT, Emmanuel Bourg <duke at openjdk.java.net> wrote:

>> When a list of icons is set on a window, the most appropiate icon is selected depending on the graphics configuration. But if the graphics configuration changes (because the window is moved to a different screen, or because the DPI settings of the screen is changed), the frame icon isn't updated.
>> 
>> Here is an example illustrating the issue:
>> 
>>     public static void main(String[] args) throws Exception {
>>         SwingUtilities.invokeLater(() -> {
>>             JFrame frame = new JFrame("Window Icon Test");
>>             frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
>>             frame.setSize(400, 300);
>>             frame.setVisible(true);
>> 
>>             List<Image> images = new ArrayList<>();
>>             for (int size = 16; size <= 32; size++) {
>>                 // create an image displaying the size used
>>                 BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
>>                 Graphics2D g = image.createGraphics();
>>                 g.setFont(new Font("dialog", Font.BOLD, 12));
>>                 g.setColor(Color.BLACK);
>>                 g.drawString(String.valueOf(size), 0, size - (size - g.getFont().getSize()) / 2);
>>                 images.add(image);
>>             }
>> 
>>             frame.setIconImages(images);
>>         });
>>     }
>> 
>> On Windows if the screen scaling is set to 100% the 16x16 icon is picked from the list. If the scaling of the screen is set to 150% while the application is running, the 16x16 icon is upscaled and looks blurry.
>> 
>> A way to work around this issue is to listen for graphics configuration changes with:
>> 
>>     frame.addPropertyChangeListener("graphicsConfiguration", event -> frame.setIconImages(frame.getIconImages()));
>> 
>> 
>> Ideally this should be done automatically by the JDK. Maybe the `WindowPeer` could call `updateIconImages()` when `updateGraphicsData()` or `displayChanged()` is invoked?
>
> Emmanuel Bourg has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Test case for the window icon update on DPI change

Changes requested by aivanov (Reviewer).

test/jdk/java/awt/Window/WindowIconUpdateOnDPIChanging/WindowIconUpdateOnDPIChangingTest.java line 47:

> 45:  * @bug 8276849
> 46:  * @summary Update the window icon on DPI scale factor changes
> 47:  * @compile WindowIconUpdateOnDPIChangingTest.java

The `@compile` is assumed; when the test consists of one file only, it's not necessary.

test/jdk/java/awt/Window/WindowIconUpdateOnDPIChanging/WindowIconUpdateOnDPIChangingTest.java line 53:

> 51: 
> 52:     private static volatile boolean testResult = false;
> 53:     private static volatile CountDownLatch countDownLatch;

Suggestion:

    private static final CountDownLatch countDownLatch = new CountDownLatch(1);

test/jdk/java/awt/Window/WindowIconUpdateOnDPIChanging/WindowIconUpdateOnDPIChangingTest.java line 78:

> 76:         countDownLatch = new CountDownLatch(1);
> 77:         SwingUtilities.invokeLater(WindowIconUpdateOnDPIChangingTest::createUI);
> 78:         countDownLatch.await(15, TimeUnit.MINUTES);

If `await` times out, `throw new RuntimeException("Timed out!");`

test/jdk/java/awt/Window/WindowIconUpdateOnDPIChanging/WindowIconUpdateOnDPIChangingTest.java line 96:

> 94:         frame.getContentPane().add(createInstrumentsPane(), BorderLayout.CENTER);
> 95:         frame.getContentPane().add(createControlPanel(), BorderLayout.SOUTH);
> 96:         frame.setIconImages(IntStream.rangeClosed(16, 32).mapToObj(WindowIconUpdateOnDPIChangingTest::createIcon).toList());

Suggestion:

        frame.setIconImages(IntStream.rangeClosed(16, 32)
                                     .mapToObj(WindowIconUpdateOnDPIChangingTest::createIcon)
                                     .toList());

This way, it's easier to see what is done in the stream and the line fits into 80 columns.

test/jdk/java/awt/Window/WindowIconUpdateOnDPIChanging/WindowIconUpdateOnDPIChangingTest.java line 97:

> 95:         frame.getContentPane().add(createControlPanel(), BorderLayout.SOUTH);
> 96:         frame.setIconImages(IntStream.rangeClosed(16, 32).mapToObj(WindowIconUpdateOnDPIChangingTest::createIcon).toList());
> 97:         frame.setVisible(true);

Could you also add?

        frame.setLocationRelativeTo(null);

This will place the window in the center of the screen.

test/jdk/java/awt/Window/WindowIconUpdateOnDPIChanging/WindowIconUpdateOnDPIChangingTest.java line 134:

> 132:         g.setFont(new Font("dialog", Font.BOLD, 12));
> 133:         g.setColor(Color.BLACK);
> 134:         g.drawString(String.valueOf(size), 0, size - (size - g.getFont().getSize()) / 2);

Before drawing black text, I suggest filling the background with white. I will guarantee the icon can always been seen. On the Windows taskbar which is black, it's very hard to see the black text. In the dark theme, where the window title bar is black, it'll be impossible to see the difference.

-------------

PR: https://git.openjdk.java.net/jdk/pull/6180



More information about the client-libs-dev mailing list