On Mon, 21 Feb 2022 07:57:32 GMT, Emmanuel Bourg <d...@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 five > additional commits since the last revision: > > - Test case for the window icon update on DPI change (other changes) > - Test case for the window icon update on DPI change (@compile not needed) > - Test case for the window icon update on DPI change (center the frame) > - Test case for the window icon update on DPI change (specific message for > timeouts) > - Test case for the window icon update on DPI change (icon with a white > background and centered text) Changes requested by aivanov (Reviewer). test/jdk/java/awt/Window/WindowIconUpdateOnDPIChanging/WindowIconUpdateOnDPIChangingTest.java line 79: > 77: > SwingUtilities.invokeLater(WindowIconUpdateOnDPIChangingTest::createUI); > 78: if (!countDownLatch.await(15, TimeUnit.MINUTES)) { > 79: frame.dispose(); It must be called on EDT. Suggestion: SwingUtilities.invokeAndWait(() -> frame.dispose()); test/jdk/java/awt/Window/WindowIconUpdateOnDPIChanging/WindowIconUpdateOnDPIChangingTest.java line 98: > 96: frame.getContentPane().add(createInstrumentsPane(), > BorderLayout.CENTER); > 97: frame.getContentPane().add(createControlPanel(), > BorderLayout.SOUTH); > 98: frame.setIconImages(IntStream.rangeClosed(16, 32).mapToObj(size > -> createIcon(size)).toList()); In fact, I liked the version with method reference better even though the line is longer. But I still suggest wrapping the line at each dot to make it clearer what operations are performed on the stream. Suggestion: frame.setIconImages(IntStream.rangeClosed(16, 32) .mapToObj(size -> createIcon(size)) .toList()); It fits into 80 column limit. If it's replaced with method reference as it was before, it doesn't fit but I don't see it as big problem. Alternatively, you can wrap the start of the stream too: Suggestion: frame.setIconImages( IntStream.rangeClosed(16, 32) .mapToObj(WindowIconUpdateOnDPIChangingTest::createIcon) .toList()); The line with method reference takes 82 columns, I'm sure it's acceptable. ------------- PR: https://git.openjdk.java.net/jdk/pull/6180