JDK-8238734 : [HiDPI] Hotspot of the custom cursor is in wrong position
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 11,15
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_10
  • CPU: x86_64
  • Submitted: 2020-02-07
  • Updated: 2020-03-01
  • Resolved: 2020-03-01
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 15
15Resolved
Related Reports
Duplicate :  
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Windows 10

A DESCRIPTION OF THE PROBLEM :
The hotspot is in the wrong position, even in the latest available JDK version15 EA Build 6.

It is reproducible every time on a screen having scaling set to 200% (probably on all scaling levels >100%).

Constructing the cursor sized according to Toolkit.getBestCursorSize() fixes the problem.  However, the hotspot should also be set correctly when the image is smaller.

It is quite apparent from the JDK source code
https://github.com/openjdk/jdk/blob/6bab0f539fba8fb441697846347597b4a0ade428/src/java.desktop/share/classes/sun/awt/CustomCursor.java
that the cursor image is scaled in certain cases (line 71), but the hotspot is not scaled accordingly.

Fixing this should be quite trivial.  Please solve this problem after being open for 4 years.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute the attached test program and click into the opened window.



EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The rectangles drawn on click should appear at the very center of the haircross.
ACTUAL -
The drawn rectangles appear in the top left quadrant, off the center of the haircross.
(Too bad not screenshots can be submitted here.)

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;

public class CustomCursorHotspot {
    public static void main(String[] args)
    {
        Dimension bestCursorSize = Toolkit.getDefaultToolkit().getBestCursorSize(32, 32);
        assert bestCursorSize.width == bestCursorSize.height;

        final int cursorSize = 32; // this triggers the bug

        //final int cursorSize = bestCursorSize.width; // this is the workaround

        // construct framed haircross
        BufferedImage bufferedImage = new BufferedImage(cursorSize, cursorSize, BufferedImage.TYPE_INT_ARGB);
        Graphics2D bg = bufferedImage.createGraphics();
        bg.setBackground(new Color(1.0f, 1.0f, 1.0f, 0.0f));
        bg.clearRect(0, 0, cursorSize, cursorSize);
        bg.setColor(Color.BLACK);
        bg.drawRect(0, 0, cursorSize - 1, cursorSize - 1);
        bg.setStroke(new BasicStroke(2));
        bg.drawLine(cursorSize / 2, 0, cursorSize / 2, cursorSize);
        bg.drawLine(0, cursorSize / 2, cursorSize, cursorSize / 2);

        Frame frame = new Frame();
        frame.setCursor(Toolkit.getDefaultToolkit().createCustomCursor(
                bufferedImage, new Point(cursorSize / 2, cursorSize / 2), "haircross"));
        frame.setSize(new Dimension(500, 500));
        frame.setVisible(true);

        frame.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent e) {
                Graphics graphics = frame.getGraphics();
                graphics.setColor(Color.RED);
                graphics.drawRect(e.getX() - 1, e.getY() - 1, 3, 3);
            }

            @Override
            public void mousePressed(MouseEvent e) { }
            @Override
            public void mouseReleased(MouseEvent e) { }
            @Override
            public void mouseEntered(MouseEvent e) { }
            @Override
            public void mouseExited(MouseEvent e) { }
        });
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Provide the cursor image in a size matching Toolkit.getBestCursorSize().
To test this, uncomment the second line setting cursorSize, and comment out the first one.

FREQUENCY : always



Comments
Reported with JDK 15 ea b06 and HiDPI scaling to >100%, the hotspot of the custom cursor is at wring position. Issue is similar to JDK-8158776, however this contain detailed information including a test case. Checked this with attached test case and could confirm the issue as reported. This is a regression in JDK 9 and reproduced easily with versions above including JDK 15 ea build. Issue is not reproducible with JDK 8u. Result: ====== 8u241: OK 9: Fail 11: Fail 13.0.2: Fail 14 ea b34: Fail 15 ea b8: Fail To verify, run the attached test case with respective JDK versions. Attached screenshots as reference.
10-02-2020