Skip to content
Permalink
Browse files
8211999: Window positioning bugs due to overlapping GraphicsDevice bo…
…unds (Windows/HiDPI)

Reviewed-by: serb
Backport-of: be63525
  • Loading branch information
TheRealMDoerr committed Oct 15, 2021
1 parent 99ff268 commit fcb396fe52ddd594050cfae470c35ac96547ecb9
Showing with 1,117 additions and 429 deletions.
  1. +15 −15 src/java.desktop/share/classes/java/awt/Robot.java
  2. +11 −1 src/java.desktop/share/classes/java/awt/peer/RobotPeer.java
  3. +98 −26 src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java
  4. +1 −1 src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java
  5. +12 −0 src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java
  6. +4 −2 src/java.desktop/windows/classes/sun/awt/windows/WDialogPeer.java
  7. +9 −8 src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java
  8. +7 −2 src/java.desktop/windows/classes/sun/awt/windows/WRobotPeer.java
  9. +12 −94 src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java
  10. +3 −3 src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp
  11. +52 −14 src/java.desktop/windows/native/libawt/windows/awt_Component.cpp
  12. +5 −0 src/java.desktop/windows/native/libawt/windows/awt_Component.h
  13. +3 −3 src/java.desktop/windows/native/libawt/windows/awt_Cursor.cpp
  14. +9 −9 src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp
  15. +7 −6 src/java.desktop/windows/native/libawt/windows/awt_FileDialog.cpp
  16. +2 −6 src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp
  17. +6 −3 src/java.desktop/windows/native/libawt/windows/awt_List.cpp
  18. +2 −6 src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsConfig.cpp
  19. +53 −6 src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp
  20. +8 −1 src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h
  21. +124 −178 src/java.desktop/windows/native/libawt/windows/awt_Window.cpp
  22. +4 −11 src/java.desktop/windows/native/libawt/windows/awt_Window.h
  23. +5 −1 src/java.desktop/windows/native/libawt/windows/awtmsg.h
  24. +120 −0 test/jdk/java/awt/Component/SetComponentsBounds/SetComponentsBounds.java
  25. +4 −2 test/jdk/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java
  26. +12 −3 test/jdk/java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenSmall.java
  27. +102 −0 test/jdk/java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java
  28. +152 −0 test/jdk/java/awt/List/ListMultipleSelectTest/ListMultipleSelectTest.java
  29. +1 −1 test/jdk/java/awt/Multiscreen/MouseEventTest/MouseEventTest.java
  30. +25 −10 test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java
  31. +5 −2 test/jdk/java/awt/Window/LocationAtScreenCorner/LocationAtScreenCorner.java
  32. +95 −0 test/jdk/java/awt/Window/SlowMotion/SlowMotion.java
  33. +113 −0 test/jdk/java/awt/Window/WindowSizeDifferentScreens/WindowSizeDifferentScreens.java
  34. +9 −6 test/jdk/java/awt/dnd/Button2DragTest/Button2DragTest.java
  35. +27 −9 test/jdk/javax/swing/JTextArea/8149849/DNDTextToScaledArea.java
@@ -43,6 +43,9 @@
import sun.awt.image.SunWritableRaster;
import sun.java2d.SunGraphicsEnvironment;

import static sun.java2d.SunGraphicsEnvironment.toDeviceSpace;
import static sun.java2d.SunGraphicsEnvironment.toDeviceSpaceAbs;

/**
* This class is used to generate native system input events
* for the purposes of test automation, self-running demos, and
@@ -377,13 +380,9 @@ private void checkKeycodeArgument(int keycode) {
*/
public synchronized Color getPixelColor(int x, int y) {
checkScreenCaptureAllowed();
AffineTransform tx = GraphicsEnvironment.
getLocalGraphicsEnvironment().getDefaultScreenDevice().
getDefaultConfiguration().getDefaultTransform();
x = (int) (x * tx.getScaleX());
y = (int) (y * tx.getScaleY());
Color color = new Color(peer.getRGBPixel(x, y));
return color;
Point point = peer.useAbsoluteCoordinates() ? toDeviceSpaceAbs(x, y)
: toDeviceSpace(x, y);
return new Color(peer.getRGBPixel(point.x, point.y));
}

/**
@@ -516,16 +515,17 @@ public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {

} else {

int sX = (int) Math.floor(screenRect.x * uiScaleX);
int sY = (int) Math.floor(screenRect.y * uiScaleY);
int sWidth = (int) Math.ceil(screenRect.width * uiScaleX);
int sHeight = (int) Math.ceil(screenRect.height * uiScaleY);
int temppixels[];
Rectangle scaledRect = new Rectangle(sX, sY, sWidth, sHeight);
temppixels = peer.getRGBPixels(scaledRect);
Rectangle scaledRect;
if (peer.useAbsoluteCoordinates()) {
scaledRect = toDeviceSpaceAbs(gc, screenRect.x,
screenRect.y, screenRect.width, screenRect.height);
} else {
scaledRect = toDeviceSpace(gc, screenRect.x,
screenRect.y, screenRect.width, screenRect.height);
}

// HighResolutionImage
pixels = temppixels;
pixels = peer.getRGBPixels(scaledRect);
buffer = new DataBufferInt(pixels, pixels.length);
raster = Raster.createPackedRaster(buffer, scaledRect.width,
scaledRect.height, scaledRect.width, bandmasks, null);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -117,4 +117,14 @@
* @see Robot#createScreenCapture(Rectangle)
*/
int[] getRGBPixels(Rectangle bounds);

/**
* Determines if absolute coordinates should be used by this peer.
*
* @return {@code true} if absolute coordinates should be used,
* {@code false} otherwise
*/
default boolean useAbsoluteCoordinates() {
return false;
}
}
@@ -27,6 +27,7 @@

import java.awt.AWTError;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
@@ -401,53 +402,124 @@ public static GraphicsConfiguration getGraphicsConfigurationAtPoint(
}

/**
* Converts coordinates from the user's space to the device space using
* appropriate device transformation.
* Returns the bounds of the graphics configuration in device space.
*
* @param config the graphics configuration which bounds are requested
* @return the bounds of the area covered by this
* {@code GraphicsConfiguration} in device space (pixels)
*/
public static Rectangle getGCDeviceBounds(GraphicsConfiguration config) {
AffineTransform tx = config.getDefaultTransform();
Rectangle bounds = config.getBounds();
bounds.width *= tx.getScaleX();
bounds.height *= tx.getScaleY();
return bounds;
}

/**
* Converts the size (w, h) from the device space to the user's space using
* passed graphics configuration.
*
* @param gc the graphics configuration to be used for transformation
* @param w the width in the device space
* @param h the height in the device space
* @return the size in the user's space
*/
public static Dimension toUserSpace(GraphicsConfiguration gc,
int w, int h) {
AffineTransform tx = gc.getDefaultTransform();
return new Dimension(
Region.clipRound(w / tx.getScaleX()),
Region.clipRound(h / tx.getScaleY())
);
}

/**
* Converts absolute coordinates from the user's space to the device space
* using appropriate device transformation.
*
* @param x coordinate in the user space
* @param y coordinate in the user space
* @return the point which uses device space(pixels)
* @param x absolute coordinate in the user's space
* @param y absolute coordinate in the user's space
* @return the point which uses device space (pixels)
*/
public static Point convertToDeviceSpace(double x, double y) {
public static Point toDeviceSpaceAbs(int x, int y) {
GraphicsConfiguration gc = getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration();
.getDefaultScreenDevice().getDefaultConfiguration();
gc = getGraphicsConfigurationAtPoint(gc, x, y);
return toDeviceSpaceAbs(gc, x, y, 0, 0).getLocation();
}

/**
* Converts the rectangle from the user's space to the device space using
* appropriate device transformation.
*
* @param rect the rectangle in the user's space
* @return the rectangle which uses device space (pixels)
*/
public static Rectangle toDeviceSpaceAbs(Rectangle rect) {
GraphicsConfiguration gc = getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration();
gc = getGraphicsConfigurationAtPoint(gc, rect.x, rect.y);
return toDeviceSpaceAbs(gc, rect.x, rect.y, rect.width, rect.height);
}

/**
* Converts absolute coordinates (x, y) and the size (w, h) from the user's
* space to the device space using passed graphics configuration.
*
* @param gc the graphics configuration to be used for transformation
* @param x absolute coordinate in the user's space
* @param y absolute coordinate in the user's space
* @param w the width in the user's space
* @param h the height in the user's space
* @return the rectangle which uses device space (pixels)
*/
public static Rectangle toDeviceSpaceAbs(GraphicsConfiguration gc,
int x, int y, int w, int h) {
AffineTransform tx = gc.getDefaultTransform();
x = Region.clipRound(x * tx.getScaleX());
y = Region.clipRound(y * tx.getScaleY());
return new Point((int) x, (int) y);
Rectangle screen = gc.getBounds();
return new Rectangle(
screen.x + Region.clipRound((x - screen.x) * tx.getScaleX()),
screen.y + Region.clipRound((y - screen.y) * tx.getScaleY()),
Region.clipRound(w * tx.getScaleX()),
Region.clipRound(h * tx.getScaleY())
);
}

/**
* Converts bounds from the user's space to the device space using
* Converts coordinates from the user's space to the device space using
* appropriate device transformation.
*
* @param bounds the rectangle in the user space
* @return the rectangle which uses device space(pixels)
* @param x coordinate in the user's space
* @param y coordinate in the user's space
* @return the point which uses device space (pixels)
*/
public static Rectangle convertToDeviceSpace(Rectangle bounds) {
public static Point toDeviceSpace(int x, int y) {
GraphicsConfiguration gc = getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration();
gc = getGraphicsConfigurationAtPoint(gc, bounds.x, bounds.y);
return convertToDeviceSpace(gc, bounds);
gc = getGraphicsConfigurationAtPoint(gc, x, y);
return toDeviceSpace(gc, x, y, 0, 0).getLocation();
}

/**
* Converts bounds from the user's space to the device space using
* appropriate device transformation of the passed graphics configuration.
* Converts coordinates (x, y) and the size (w, h) from the user's
* space to the device space using passed graphics configuration.
*
* @param bounds the rectangle in the user space
* @return the rectangle which uses device space(pixels)
* @param gc the graphics configuration to be used for transformation
* @param x coordinate in the user's space
* @param y coordinate in the user's space
* @param w the width in the user's space
* @param h the height in the user's space
* @return the rectangle which uses device space (pixels)
*/
public static Rectangle convertToDeviceSpace(GraphicsConfiguration gc,
Rectangle bounds) {
public static Rectangle toDeviceSpace(GraphicsConfiguration gc,
int x, int y, int w, int h) {
AffineTransform tx = gc.getDefaultTransform();
return new Rectangle(
Region.clipRound(bounds.x * tx.getScaleX()),
Region.clipRound(bounds.y * tx.getScaleY()),
Region.clipRound(bounds.width * tx.getScaleX()),
Region.clipRound(bounds.height * tx.getScaleY())
Region.clipRound(x * tx.getScaleX()),
Region.clipRound(y * tx.getScaleY()),
Region.clipRound(w * tx.getScaleX()),
Region.clipRound(h * tx.getScaleY())
);
}
}
@@ -463,7 +463,7 @@ public synchronized void setDisplayMode(DisplayMode dm) {
// display mode
Rectangle screenBounds = getDefaultConfiguration().getBounds();
w.setBounds(screenBounds.x, screenBounds.y,
dm.getWidth(), dm.getHeight());
screenBounds.width, screenBounds.height);
// Note: no call to replaceSurfaceData is required here since
// replacement will be caused by an upcoming display change event
} else {
@@ -520,7 +520,11 @@ public void run() {

@Override
public boolean updateGraphicsData(GraphicsConfiguration gc) {
var old = getGraphicsConfiguration().getDefaultTransform();
winGraphicsConfig = (Win32GraphicsConfig)gc;
if (gc != null && !old.equals(gc.getDefaultTransform())) {
syncBounds(); // the bounds of the peer depend on the DPI
}
try {
replaceSurfaceData();
} catch (InvalidPipeException e) {
@@ -529,6 +533,14 @@ public boolean updateGraphicsData(GraphicsConfiguration gc) {
return false;
}

/**
* Make sure that the native peer's coordinates are in sync with the target.
*/
void syncBounds() {
Rectangle r = ((Component) target).getBounds();
setBounds(r.x, r.y, r.width, r.height, SET_BOUNDS);
}

//This will return null for Components not yet added to a Container
@Override
public ColorModel getColorModel() {
@@ -36,6 +36,8 @@
import sun.awt.AWTAccessor;
import sun.awt.im.InputMethodManager;

import static sun.java2d.SunGraphicsEnvironment.toUserSpace;

final class WDialogPeer extends WWindowPeer implements DialogPeer {
// Toolkit & peer internals

@@ -117,8 +119,8 @@ public Dimension getMinimumSize() {
if (((Dialog)target).isUndecorated()) {
return super.getMinimumSize();
}
return new Dimension(scaleDownX(getSysMinWidth()),
scaleDownY(getSysMinHeight()));
return toUserSpace(getGraphicsConfiguration(),
getSysMinWidth(), getSysMinHeight());
}

@Override
@@ -38,7 +38,9 @@
import sun.awt.im.InputMethodManager;
import sun.security.action.GetPropertyAction;

import static sun.java2d.SunGraphicsEnvironment.convertToDeviceSpace;
import static sun.java2d.SunGraphicsEnvironment.getGCDeviceBounds;
import static sun.java2d.SunGraphicsEnvironment.toDeviceSpaceAbs;
import static sun.java2d.SunGraphicsEnvironment.toUserSpace;

class WFramePeer extends WWindowPeer implements FramePeer {

@@ -97,10 +99,9 @@ public final void setMaximizedBounds(Rectangle b) {
*/
private Rectangle adjustMaximizedBounds(Rectangle bounds) {
// All calculations should be done in the device space
bounds = convertToDeviceSpace(bounds);

bounds = toDeviceSpaceAbs(bounds);
GraphicsConfiguration gc = getGraphicsConfiguration();
Rectangle currentDevBounds = convertToDeviceSpace(gc, gc.getBounds());
Rectangle currentDevBounds = getGCDeviceBounds(gc);
// Prepare data for WM_GETMINMAXINFO message.
// ptMaxPosition should be in coordinate system of the current monitor,
// not the main monitor, or monitor on which we maximize the window.
@@ -148,13 +149,13 @@ public void reshape(int x, int y, int width, int height) {

@Override
public final Dimension getMinimumSize() {
GraphicsConfiguration gc = getGraphicsConfiguration();
Dimension d = new Dimension();
if (!((Frame)target).isUndecorated()) {
d.setSize(scaleDownX(getSysMinWidth()),
scaleDownY(getSysMinHeight()));
d.setSize(toUserSpace(gc, getSysMinWidth(), getSysMinHeight()));
}
if (((Frame)target).getMenuBar() != null) {
d.height += scaleDownY(getSysMenuHeight());
if (((Frame) target).getMenuBar() != null) {
d.height += toUserSpace(gc, 0, getSysMenuHeight()).height;
}
return d;
}
@@ -30,7 +30,7 @@
import java.awt.Rectangle;
import java.awt.peer.RobotPeer;

import sun.java2d.SunGraphicsEnvironment;
import static sun.java2d.SunGraphicsEnvironment.toDeviceSpaceAbs;

final class WRobotPeer implements RobotPeer {

@@ -40,7 +40,7 @@
public native void mouseMoveImpl(int x, int y);
@Override
public void mouseMove(int x, int y) {
Point point = SunGraphicsEnvironment.convertToDeviceSpace(x, y);
Point point = toDeviceSpaceAbs(x, y);
mouseMoveImpl(point.x, point.y);
}
@Override
@@ -68,5 +68,10 @@ public int getRGBPixel(int x, int y) {
return pixelArray;
}

@Override
public boolean useAbsoluteCoordinates() {
return true;
}

private native void getRGBPixels(int x, int y, int width, int height, int pixelArray[]);
}

1 comment on commit fcb396f

@openjdk-notifier

This comment has been minimized.

Copy link

@openjdk-notifier openjdk-notifier bot commented on fcb396f Oct 15, 2021

Please sign in to comment.