8211999: Window positioning bugs due to overlapping GraphicsDevice bounds (Windows/HiDPI)

Reviewed-by: kizune, aivanov
This commit is contained in:
Sergey Bylokhov 2020-11-11 01:29:33 +00:00
parent 0a41ca6b75
commit be635258fa
35 changed files with 1128 additions and 442 deletions

View File

@ -43,6 +43,9 @@ import sun.awt.SunToolkit;
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
@ -385,13 +388,9 @@ public class Robot {
*/
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));
}
/**
@ -523,17 +522,16 @@ public class Robot {
imageArray[0] = highResolutionImage;
} 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);

View File

@ -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 @@ public interface RobotPeer
* @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;
}
}

View File

@ -27,6 +27,7 @@ package sun.java2d;
import java.awt.AWTError;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
@ -348,54 +349,125 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment
return current;
}
/**
* 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 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 toDeviceSpaceAbs(int x, int y) {
GraphicsConfiguration gc = getLocalGraphicsEnvironment()
.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();
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 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 coordinate in the user's space
* @param y coordinate in the user's space
* @return the point which uses device space (pixels)
*/
public static Point convertToDeviceSpace(double x, double y) {
GraphicsConfiguration gc = getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration();
gc = getGraphicsConfigurationAtPoint(gc, x, y);
AffineTransform tx = gc.getDefaultTransform();
x = Region.clipRound(x * tx.getScaleX());
y = Region.clipRound(y * tx.getScaleY());
return new Point((int) x, (int) y);
}
/**
* Converts bounds 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)
*/
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())
);
}
}

View File

@ -467,7 +467,7 @@ public class Win32GraphicsDevice extends GraphicsDevice implements
// 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 {

View File

@ -533,7 +533,11 @@ public abstract class WComponentPeer extends WObjectPeer
@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) {
@ -542,6 +546,14 @@ public abstract class WComponentPeer extends WObjectPeer
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() {

View File

@ -36,6 +36,8 @@ import java.awt.peer.DialogPeer;
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 @@ final class WDialogPeer extends WWindowPeer implements DialogPeer {
if (((Dialog)target).isUndecorated()) {
return super.getMinimumSize();
}
return new Dimension(scaleDownX(getSysMinWidth()),
scaleDownY(getSysMinHeight()));
return toUserSpace(getGraphicsConfiguration(),
getSysMinWidth(), getSysMinHeight());
}
@Override

View File

@ -38,7 +38,9 @@ import sun.awt.AWTAccessor;
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 @@ class WFramePeer extends WWindowPeer implements FramePeer {
*/
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 @@ class WFramePeer extends WWindowPeer implements FramePeer {
@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;
}

View File

@ -29,14 +29,14 @@ import java.awt.Point;
import java.awt.Rectangle;
import java.awt.peer.RobotPeer;
import sun.java2d.SunGraphicsEnvironment;
import static sun.java2d.SunGraphicsEnvironment.toDeviceSpaceAbs;
final class WRobotPeer implements RobotPeer {
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
@ -64,5 +64,10 @@ final class WRobotPeer implements RobotPeer {
return pixelArray;
}
@Override
public boolean useAbsoluteCoordinates() {
return true;
}
private native void getRGBPixels(int x, int y, int width, int height, int[] pixelArray);
}

View File

@ -63,10 +63,11 @@ import sun.awt.TimedWindowEvent;
import sun.awt.Win32GraphicsConfig;
import sun.awt.Win32GraphicsDevice;
import sun.awt.Win32GraphicsEnvironment;
import sun.java2d.SunGraphicsEnvironment;
import sun.java2d.pipe.Region;
import sun.util.logging.PlatformLogger;
import static sun.java2d.SunGraphicsEnvironment.toUserSpace;
public class WWindowPeer extends WPanelPeer implements WindowPeer,
DisplayChangedListener
{
@ -108,8 +109,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
* WindowStateEvent is posted to the EventQueue.
*/
private WindowListener windowListener;
private float scaleX;
private float scaleY;
/**
* Initialize JNI field IDs
@ -222,8 +221,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
GraphicsConfiguration gc = getGraphicsConfiguration();
Win32GraphicsDevice gd = (Win32GraphicsDevice) gc.getDevice();
gd.addDisplayChangedListener(this);
scaleX = gd.getDefaultScaleX();
scaleY = gd.getDefaultScaleY();
initActiveWindowsTracking((Window)target);
@ -310,6 +307,12 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
}
}
@Override
final void syncBounds() {
// Windows will take care of the top-level window/frame/dialog, and
// update the location/size when DPI changes.
}
// Synchronize the insets members (here & in helper) with actual window
// state.
native void updateInsets(Insets i);
@ -438,9 +441,10 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
minimumSize = ((Component)target).getMinimumSize();
}
if (minimumSize != null) {
int w = Math.max(minimumSize.width, scaleDownX(getSysMinWidth()));
int h = Math.max(minimumSize.height, scaleDownY(getSysMinHeight()));
setMinSize(w, h);
Dimension sysMin = toUserSpace(getGraphicsConfiguration(),
getSysMinWidth(), getSysMinHeight());
setMinSize(Math.max(minimumSize.width, sysMin.width),
Math.max(minimumSize.height, sysMin.height));
} else {
setMinSize(0, 0);
}
@ -598,21 +602,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
AWTAccessor.getComponentAccessor().
setGraphicsConfiguration((Component)target, winGraphicsConfig);
checkDPIChange(oldDev, newDev);
}
private void checkDPIChange(Win32GraphicsDevice oldDev,
Win32GraphicsDevice newDev) {
float newScaleX = newDev.getDefaultScaleX();
float newScaleY = newDev.getDefaultScaleY();
if (scaleX != newScaleX || scaleY != newScaleY) {
windowDPIChange(oldDev.getScreen(), scaleX, scaleY,
newDev.getScreen(), newScaleX, newScaleY);
scaleX = newScaleX;
scaleY = newScaleY;
}
}
/**
@ -666,77 +655,9 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
return true;
}
// These are the peer bounds. They get updated at:
// 1. the WWindowPeer.setBounds() method.
// 2. the native code (on WM_SIZE/WM_MOVE)
private volatile int sysX = 0;
private volatile int sysY = 0;
private volatile int sysW = 0;
private volatile int sysH = 0;
@Override
public native void repositionSecurityWarning();
@Override
public void setBounds(int x, int y, int width, int height, int op) {
sysX = x;
sysY = y;
sysW = width;
sysH = height;
int cx = x + width / 2;
int cy = y + height / 2;
GraphicsConfiguration current = getGraphicsConfiguration();
GraphicsConfiguration other = SunGraphicsEnvironment
.getGraphicsConfigurationAtPoint(current, cx, cy);
if (!current.equals(other)) {
AffineTransform tx = other.getDefaultTransform();
double otherScaleX = tx.getScaleX();
double otherScaleY = tx.getScaleY();
initScales();
if (scaleX != otherScaleX || scaleY != otherScaleY) {
x = (int) Math.floor(x * otherScaleX / scaleX);
y = (int) Math.floor(y * otherScaleY / scaleY);
}
}
super.setBounds(x, y, width, height, op);
}
private void initScales() {
if (scaleX >= 1 && scaleY >= 1) {
return;
}
GraphicsConfiguration gc = getGraphicsConfiguration();
if (gc instanceof Win32GraphicsConfig) {
Win32GraphicsDevice gd = ((Win32GraphicsConfig) gc).getDevice();
scaleX = gd.getDefaultScaleX();
scaleY = gd.getDefaultScaleY();
} else {
AffineTransform tx = gc.getDefaultTransform();
scaleX = (float) tx.getScaleX();
scaleY = (float) tx.getScaleY();
}
}
final int scaleUpX(int x) {
return Region.clipRound(x * scaleX);
}
final int scaleUpY(int y) {
return Region.clipRound(y * scaleY);
}
final int scaleDownX(int x) {
return Region.clipRound(x / scaleX);
}
final int scaleDownY(int y) {
return Region.clipRound(y / scaleY);
}
@Override
public void print(Graphics g) {
// We assume we print the whole frame,
@ -905,9 +826,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
}
}
native void windowDPIChange(int prevScreen, float prevScaleX, float prevScaleY,
int newScreen, float newScaleX, float newScaleY);
/*
* The method maps the list of the active windows to the window's AppContext,
* then the method registers ActiveWindowListener, GuiDisposedListener listeners;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -106,8 +106,8 @@ Java_sun_awt_windows_WMouseInfoPeer_fillPointWithCoords(JNIEnv *env, jclass cls,
yID = env->GetFieldID(pointClass, "y", "I");
CHECK_NULL_RETURN(yID, (jint)0);
int x = (device == NULL) ? pt.x : device->ScaleDownX(pt.x);
int y = (device == NULL) ? pt.y : device->ScaleDownY(pt.y);
int x = (device == NULL) ? pt.x : device->ScaleDownAbsX(pt.x);
int y = (device == NULL) ? pt.y : device->ScaleDownAbsY(pt.y);
env->SetIntField(point, xID, x);
env->SetIntField(point, yID, y);

View File

@ -603,7 +603,7 @@ AwtComponent::CreateHWnd(JNIEnv *env, LPCWSTR title,
/*
* Fix for 4046446.
*/
SetWindowPos(GetHWnd(), 0, x, y, w, h, SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOACTIVATE);
Reshape(x, y, w, h);
/* Set default colors. */
m_colorForeground = colorForeground;
@ -1087,6 +1087,7 @@ void SpyWinMessage(HWND hwnd, UINT message, LPCTSTR szComment) {
WIN_MSG(WM_DESTROY)
WIN_MSG(WM_MOVE)
WIN_MSG(WM_SIZE)
WIN_MSG(WM_DPICHANGED)
WIN_MSG(WM_ACTIVATE)
WIN_MSG(WM_SETFOCUS)
WIN_MSG(WM_KILLFOCUS)
@ -1505,9 +1506,9 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
case WM_SIZE:
{
RECT r;
// fix 4128317 : use GetClientRect for full 32-bit int precision and
// fix 4128317 : use GetWindowRect for full 32-bit int precision and
// to avoid negative client area dimensions overflowing 16-bit params - robi
::GetClientRect( GetHWnd(), &r );
::GetWindowRect(GetHWnd(), &r);
mr = WmSize(static_cast<UINT>(wParam), r.right - r.left, r.bottom - r.top);
//mr = WmSize(wParam, LOWORD(lParam), HIWORD(lParam));
SetCompositionWindow(r);
@ -3888,8 +3889,8 @@ void AwtComponent::OpenCandidateWindow(int x, int y)
}
HWND hTop = GetTopLevelParentForWindow(hWnd);
::ClientToScreen(hTop, &p);
int sx = ScaleUpX(x) - p.x;
int sy = ScaleUpY(y) - p.y;
int sx = ScaleUpAbsX(x) - p.x;
int sy = ScaleUpAbsY(y) - p.y;
if (!m_bitsCandType) {
SetCandidateWindow(m_bitsCandType, sx, sy);
return;
@ -4767,34 +4768,71 @@ void AwtComponent::FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha)
}
}
int AwtComponent::GetScreenImOn() {
HWND hWindow = GetAncestor(GetHWnd(), GA_ROOT);
AwtComponent *comp = AwtComponent::GetComponent(hWindow);
if (comp && comp->IsTopLevel()) {
return comp->GetScreenImOn();
}
return AwtWin32GraphicsDevice::DeviceIndexForWindow(hWindow);
}
int AwtComponent::ScaleUpX(int x) {
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
int screen = GetScreenImOn();
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
return device == NULL ? x : device->ScaleUpX(x);
}
int AwtComponent::ScaleUpAbsX(int x) {
int screen = GetScreenImOn();
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
return device == NULL ? x : device->ScaleUpAbsX(x);
}
int AwtComponent::ScaleUpY(int y) {
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
int screen = GetScreenImOn();
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
return device == NULL ? y : device->ScaleUpY(y);
}
int AwtComponent::ScaleUpAbsY(int y) {
int screen = GetScreenImOn();
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
return device == NULL ? y : device->ScaleUpAbsY(y);
}
int AwtComponent::ScaleDownX(int x) {
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
int screen = GetScreenImOn();
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
return device == NULL ? x : device->ScaleDownX(x);
}
int AwtComponent::ScaleDownAbsX(int x) {
int screen = GetScreenImOn();
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
return device == NULL ? x : device->ScaleDownAbsX(x);
}
int AwtComponent::ScaleDownY(int y) {
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
int screen = GetScreenImOn();
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
return device == NULL ? y : device->ScaleDownY(y);
}
int AwtComponent::ScaleDownAbsY(int y) {
int screen = GetScreenImOn();
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
return device == NULL ? y : device->ScaleDownAbsY(y);
}
jintArray AwtComponent::CreatePrintedPixels(SIZE &loc, SIZE &size, int alpha) {
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
@ -5090,7 +5128,7 @@ void AwtComponent::SendMouseEvent(jint id, jlong when, jint x, jint y,
id, when, modifiers,
ScaleDownX(x + insets.left),
ScaleDownY(y + insets.top),
ScaleDownX(xAbs), ScaleDownY(yAbs),
ScaleDownAbsX(xAbs), ScaleDownAbsY(yAbs),
clickCount, popupTrigger, button);
if (safe_ExceptionOccurred(env)) {
@ -5163,8 +5201,8 @@ AwtComponent::SendMouseWheelEvent(jint id, jlong when, jint x, jint y,
id, when, modifiers,
ScaleDownX(x + insets.left),
ScaleDownY(y + insets.top),
ScaleDownX(xAbs),
ScaleDownY(yAbs),
ScaleDownAbsX(xAbs),
ScaleDownAbsY(yAbs),
clickCount, popupTrigger,
scrollType, scrollAmount,
roundedWheelRotation, preciseWheelRotation);
@ -5674,8 +5712,8 @@ jobject AwtComponent::_GetLocationOnScreen(void *param)
RECT rect;
VERIFY(::GetWindowRect(p->GetHWnd(),&rect));
result = JNU_NewObjectByName(env, "java/awt/Point", "(II)V",
p->ScaleDownX(rect.left),
p->ScaleDownY(rect.top));
p->ScaleDownAbsX(rect.left),
p->ScaleDownAbsY(rect.top));
}
ret:
env->DeleteGlobalRef(self);

View File

@ -275,6 +275,7 @@ public:
/*
* methods on this component
*/
virtual int GetScreenImOn();
virtual void Show();
virtual void Hide();
virtual void Reshape(int x, int y, int w, int h);
@ -755,9 +756,13 @@ protected:
virtual void FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha);
int ScaleUpX(int x);
int ScaleUpAbsX(int x);
int ScaleUpY(int y);
int ScaleUpAbsY(int y);
int ScaleDownX(int x);
int ScaleDownAbsX(int x);
int ScaleDownY(int y);
int ScaleDownAbsY(int y);
private:
/* A bitmask keeps the button's numbers as MK_LBUTTON, MK_MBUTTON, MK_RBUTTON

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -475,8 +475,8 @@ Java_sun_awt_windows_WGlobalCursorManager_getCursorPos(JNIEnv *env,
int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor);
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
int x = (device == NULL) ? p.x : device->ScaleDownX(p.x);
int y = (device == NULL) ? p.y : device->ScaleDownY(p.y);
int x = (device == NULL) ? p.x : device->ScaleDownAbsX(p.x);
int y = (device == NULL) ? p.y : device->ScaleDownAbsY(p.y);
env->SetIntField(point, AwtCursor::pointXID, x);
env->SetIntField(point, AwtCursor::pointYID, y);

View File

@ -1174,14 +1174,14 @@ HRESULT __stdcall AwtDragSource::GetProcessId(FORMATETC __RPC_FAR *pFormatEtc, S
return S_OK;
}
static void ScaleDown(POINT &pt) {
static void ScaleDownAbs(POINT &pt) {
HMONITOR monitor = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor);
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
if (device) {
pt.x = device->ScaleDownX(pt.x);
pt.y = device->ScaleDownY(pt.y);
pt.x = device->ScaleDownAbsX(pt.x);
pt.y = device->ScaleDownAbsY(pt.y);
}
}
@ -1190,7 +1190,7 @@ DECLARE_JAVA_CLASS(dSCClazz, "sun/awt/windows/WDragSourceContextPeer")
void
AwtDragSource::call_dSCenter(JNIEnv* env, jobject self, jint targetActions,
jint modifiers, POINT pt) {
ScaleDown(pt);
ScaleDownAbs(pt);
DECLARE_VOID_JAVA_METHOD(dSCenter, dSCClazz, "dragEnter", "(IIII)V");
DASSERT(!JNU_IsNull(env, self));
env->CallVoidMethod(self, dSCenter, targetActions, modifiers, pt.x, pt.y);
@ -1203,7 +1203,7 @@ AwtDragSource::call_dSCenter(JNIEnv* env, jobject self, jint targetActions,
void
AwtDragSource::call_dSCmotion(JNIEnv* env, jobject self, jint targetActions,
jint modifiers, POINT pt) {
ScaleDown(pt);
ScaleDownAbs(pt);
DECLARE_VOID_JAVA_METHOD(dSCmotion, dSCClazz, "dragMotion", "(IIII)V");
DASSERT(!JNU_IsNull(env, self));
env->CallVoidMethod(self, dSCmotion, targetActions, modifiers, pt.x, pt.y);
@ -1216,7 +1216,7 @@ AwtDragSource::call_dSCmotion(JNIEnv* env, jobject self, jint targetActions,
void
AwtDragSource::call_dSCchanged(JNIEnv* env, jobject self, jint targetActions,
jint modifiers, POINT pt) {
ScaleDown(pt);
ScaleDownAbs(pt);
DECLARE_VOID_JAVA_METHOD(dSCchanged, dSCClazz, "operationChanged",
"(IIII)V");
DASSERT(!JNU_IsNull(env, self));
@ -1229,7 +1229,7 @@ AwtDragSource::call_dSCchanged(JNIEnv* env, jobject self, jint targetActions,
void
AwtDragSource::call_dSCexit(JNIEnv* env, jobject self, POINT pt) {
ScaleDown(pt);
ScaleDownAbs(pt);
DECLARE_VOID_JAVA_METHOD(dSCexit, dSCClazz, "dragExit", "(II)V");
DASSERT(!JNU_IsNull(env, self));
env->CallVoidMethod(self, dSCexit, pt.x, pt.y);
@ -1242,7 +1242,7 @@ AwtDragSource::call_dSCexit(JNIEnv* env, jobject self, POINT pt) {
void
AwtDragSource::call_dSCddfinished(JNIEnv* env, jobject self, jboolean success,
jint operations, POINT pt) {
ScaleDown(pt);
ScaleDownAbs(pt);
DECLARE_VOID_JAVA_METHOD(dSCddfinished, dSCClazz, "dragDropFinished", "(ZIII)V");
DASSERT(!JNU_IsNull(env, self));
env->CallVoidMethod(self, dSCddfinished, success, operations, pt.x, pt.y);
@ -1255,7 +1255,7 @@ AwtDragSource::call_dSCddfinished(JNIEnv* env, jobject self, jboolean success,
void
AwtDragSource::call_dSCmouseMoved(JNIEnv* env, jobject self, jint targetActions,
jint modifiers, POINT pt) {
ScaleDown(pt);
ScaleDownAbs(pt);
DECLARE_VOID_JAVA_METHOD(dSCmouseMoved, dSCClazz, "dragMouseMoved",
"(IIII)V");
DASSERT(!JNU_IsNull(env, self));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 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
@ -631,18 +631,18 @@ Java_sun_awt_windows_WFileDialogPeer_toBack(JNIEnv *env, jobject peer)
CATCH_BAD_ALLOC;
}
int ScaleDownX(int x, HWND hwnd) {
int ScaleDownAbsX(int x, HWND hwnd) {
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(hwnd);
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
return device == NULL ? x : device->ScaleDownX(x);
return device == NULL ? x : device->ScaleDownAbsX(x);
}
int ScaleDownY(int y, HWND hwnd) {
int ScaleDownAbsY(int y, HWND hwnd) {
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(hwnd);
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
return device == NULL ? y : device->ScaleDownY(y);
return device == NULL ? y : device->ScaleDownAbsY(y);
}
jobject AwtFileDialog::_GetLocationOnScreen(void *param)
@ -657,7 +657,8 @@ jobject AwtFileDialog::_GetLocationOnScreen(void *param)
RECT rect;
VERIFY(::GetWindowRect(hwnd, &rect));
result = JNU_NewObjectByName(env, "java/awt/Point", "(II)V",
ScaleDownX(rect.left, hwnd), ScaleDownY(rect.top, hwnd));
ScaleDownAbsX(rect.left, hwnd),
ScaleDownAbsY(rect.top, hwnd));
}
if (result != NULL)

View File

@ -328,17 +328,13 @@ AwtFrame* AwtFrame::Create(jobject self, jobject parent)
frame->CreateHWnd(env, L"",
style,
exStyle,
0, 0, 0, 0,
x, y, width, height,
hwndParent,
NULL,
::GetSysColor(COLOR_WINDOWTEXT),
::GetSysColor(COLOR_WINDOWFRAME),
self);
/*
* Reshape here instead of during create, so that a
* WM_NCCALCSIZE is sent.
*/
frame->Reshape(x, y, width, height);
frame->RecalcNonClient();
}
}
} catch (...) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 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
@ -288,14 +288,17 @@ void AwtList::SetMultiSelect(BOOL ms) {
UnsubclassHWND();
AwtToolkit::DestroyComponentHWND(m_hwnd);
CreateHWnd(env, L"", style, exStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
CreateHWnd(env, L"", style, exStyle, 0, 0, 0, 0,
parentHWnd,
NULL,
::GetSysColor(COLOR_WINDOWTEXT),
::GetSysColor(COLOR_WINDOW),
peer);
SetWindowPos(GetHWnd(), 0,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOACTIVATE);
SendListMessage(WM_SETFONT, (WPARAM)font, (LPARAM)FALSE);
SendListMessage(LB_SETITEMHEIGHT, 0, MAKELPARAM(itemHeight, 0));
SendListMessage(LB_RESETCONTENT);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2014, 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
@ -99,16 +99,12 @@ JNIEXPORT jobject JNICALL
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
if (TRUE == MonitorBounds(AwtWin32GraphicsDevice::GetMonitor(screen), &rRW)) {
int x = (device == NULL) ? rRW.left : device->ScaleDownX(rRW.left);
int y = (device == NULL) ? rRW.top : device->ScaleDownY(rRW.top);
int w = (device == NULL) ? rRW.right - rRW.left
: device->ScaleDownX(rRW.right - rRW.left);
int h = (device == NULL) ? rRW.bottom - rRW.top
: device->ScaleDownY(rRW.bottom - rRW.top);
bounds = env->NewObject(clazz, mid, x, y, w, h);
bounds = env->NewObject(clazz, mid, rRW.left, rRW.top, w, h);
}
else {
// 4910760 - don't return a null bounds, return the bounds of the

View File

@ -77,6 +77,7 @@ AwtWin32GraphicsDevice::AwtWin32GraphicsDevice(int screen,
this->devicesArray = arr;
this->scaleX = 1;
this->scaleY = 1;
disableScaleAutoRefresh = FALSE;
javaDevice = NULL;
colorData = new ImgColorData;
colorData->grayscale = GS_NOTGRAY;
@ -633,21 +634,45 @@ int AwtWin32GraphicsDevice::ScaleUpX(int x)
return ClipRound(x * scaleX);
}
int AwtWin32GraphicsDevice::ScaleUpAbsX(int x)
{
LONG screen = pMonitorInfo->rcMonitor.left;
return screen + ClipRound((x - screen) * scaleX);
}
int AwtWin32GraphicsDevice::ScaleUpY(int y)
{
return ClipRound(y * scaleY);
}
int AwtWin32GraphicsDevice::ScaleUpAbsY(int y)
{
LONG screen = pMonitorInfo->rcMonitor.top;
return screen + ClipRound((y - screen) * scaleY);
}
int AwtWin32GraphicsDevice::ScaleDownX(int x)
{
return ClipRound(x / scaleX);
}
int AwtWin32GraphicsDevice::ScaleDownAbsX(int x)
{
LONG screen = pMonitorInfo->rcMonitor.left;
return screen + ClipRound((x - screen) / scaleX);
}
int AwtWin32GraphicsDevice::ScaleDownY(int y)
{
return ClipRound(y / scaleY);
}
int AwtWin32GraphicsDevice::ScaleDownAbsY(int y)
{
LONG screen = pMonitorInfo->rcMonitor.top;
return screen + ClipRound((y - screen) / scaleY);
}
int AwtWin32GraphicsDevice::ClipRound(double value)
{
value -= 0.5;
@ -666,11 +691,13 @@ int AwtWin32GraphicsDevice::ClipRound(double value)
void AwtWin32GraphicsDevice::InitDesktopScales()
{
float dpiX = -1.0f;
float dpiY = -1.0f;
GetScreenDpi(GetMonitor(), &dpiX, &dpiY);
if (dpiX > 0 && dpiY > 0) {
SetScale(dpiX / 96, dpiY / 96);
if (!disableScaleAutoRefresh) {
float dpiX = -1.0f;
float dpiY = -1.0f;
GetScreenDpi(GetMonitor(), &dpiX, &dpiY);
if (dpiX > 0 && dpiY > 0) {
SetScale(dpiX / 96, dpiY / 96);
}
}
}
@ -694,6 +721,11 @@ void AwtWin32GraphicsDevice::DisableOffscreenAcceleration()
// REMIND: noop for now
}
void AwtWin32GraphicsDevice::DisableScaleAutoRefresh()
{
disableScaleAutoRefresh = TRUE;
}
/**
* Invalidates the GraphicsDevice object associated with this
* device by disabling offscreen acceleration and calling
@ -754,6 +786,21 @@ void AwtWin32GraphicsDevice::ResetAllMonitorInfo()
}
}
/**
* This function updates the scale factor for all monitors on the system.
*/
void AwtWin32GraphicsDevice::ResetAllDesktopScales()
{
if (!Devices::GetInstance()){
return;
}
Devices::InstanceAccess devices;
int devicesNum = devices->GetNumDevices();
for (int deviceIndex = 0; deviceIndex < devicesNum; deviceIndex++) {
devices->GetDevice(deviceIndex)->InitDesktopScales();
}
}
void AwtWin32GraphicsDevice::DisableOffscreenAccelerationForDevice(
HMONITOR hMonitor)
{
@ -1393,6 +1440,7 @@ JNIEXPORT void JNICALL
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
if (device != NULL ) {
device->DisableScaleAutoRefresh();
device->SetScale(scaleX, scaleY);
}
}
@ -1441,4 +1489,3 @@ Java_sun_awt_Win32GraphicsDevice_initNativeScale
device->InitDesktopScales();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -65,15 +65,20 @@ public:
int GetDeviceIndex() { return screen; }
void Release();
void DisableOffscreenAcceleration();
void DisableScaleAutoRefresh();
void Invalidate(JNIEnv *env);
void InitDesktopScales();
void SetScale(float scaleX, float scaleY);
float GetScaleX();
float GetScaleY();
int ScaleUpX(int x);
int ScaleUpAbsX(int x);
int ScaleUpY(int y);
int ScaleUpAbsY(int x);
int ScaleDownX(int x);
int ScaleDownAbsX(int x);
int ScaleDownY(int y);
int ScaleDownAbsY(int y);
static int DeviceIndexForWindow(HWND hWnd);
static jobject GetColorModel(JNIEnv *env, jboolean dynamic,
@ -88,6 +93,7 @@ public:
static HMONITOR GetMonitor(int deviceIndex);
static LPMONITORINFO GetMonitorInfo(int deviceIndex);
static void ResetAllMonitorInfo();
static void ResetAllDesktopScales();
static BOOL IsPrimaryPalettized() { return primaryPalettized; }
static int GetDefaultDeviceIndex() { return primaryIndex; }
static void DisableOffscreenAccelerationForDevice(HMONITOR hMonitor);
@ -117,6 +123,7 @@ private:
Devices *devicesArray;
float scaleX;
float scaleY;
BOOL disableScaleAutoRefresh;
static HDC MakeDCFromMonitor(HMONITOR);
static int ClipRound(double value);

View File

@ -153,17 +153,6 @@ struct SetFullScreenExclusiveModeStateStruct {
jboolean isFSEMState;
};
// struct for _WindowDPIChange() method
struct ScaleStruct {
jobject window;
jint prevScreen;
jfloat prevScaleX;
jfloat prevScaleY;
jint screen;
jfloat scaleX;
jfloat scaleY;
};
struct OverrideHandle {
jobject frame;
HWND handle;
@ -179,10 +168,6 @@ jfieldID AwtWindow::autoRequestFocusID;
jfieldID AwtWindow::securityWarningWidthID;
jfieldID AwtWindow::securityWarningHeightID;
jfieldID AwtWindow::sysXID;
jfieldID AwtWindow::sysYID;
jfieldID AwtWindow::sysWID;
jfieldID AwtWindow::sysHID;
jfieldID AwtWindow::windowTypeID;
jmethodID AwtWindow::notifyWindowStateChangedMID;
@ -1128,20 +1113,19 @@ AwtWindow* AwtWindow::Create(jobject self, jobject parent)
// specify WS_EX_TOOLWINDOW to remove parentless windows from taskbar
exStyle |= WS_EX_TOOLWINDOW;
}
window->CreateHWnd(env, L"",
style, exStyle,
0, 0, 0, 0,
(awtParent != NULL) ? awtParent->GetHWnd() : NULL,
NULL,
::GetSysColor(COLOR_WINDOWTEXT),
::GetSysColor(COLOR_WINDOW),
self);
jint x = env->GetIntField(target, AwtComponent::xID);
jint y = env->GetIntField(target, AwtComponent::yID);
jint width = env->GetIntField(target, AwtComponent::widthID);
jint height = env->GetIntField(target, AwtComponent::heightID);
window->CreateHWnd(env, L"",
style, exStyle,
x, y, width, height,
(awtParent != NULL) ? awtParent->GetHWnd() : NULL,
NULL,
::GetSysColor(COLOR_WINDOWTEXT),
::GetSysColor(COLOR_WINDOW),
self);
/*
* Initialize icon as inherited from parent if it exists
*/
@ -1151,13 +1135,7 @@ AwtWindow* AwtWindow::Create(jobject self, jobject parent)
window->m_iconInherited = TRUE;
}
window->DoUpdateIcon();
/*
* Reshape here instead of during create, so that a WM_NCCALCSIZE
* is sent.
*/
window->Reshape(x, y, width, height);
window->RecalcNonClient();
}
} catch (...) {
env->DeleteLocalRef(target);
@ -1215,6 +1193,48 @@ void AwtWindow::moveToDefaultLocation() {
VERIFY(::SetWindowPos(GetHWnd(), NULL, defLoc.left, defLoc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER));
}
/**
* Override AwtComponent::Reshape() to handle absolute screen coordinates used
* by the top-level windows.
*/
void AwtWindow::Reshape(int x, int y, int w, int h) {
if (IsEmbeddedFrame()) {
// Not the "real" top level window
return AwtComponent::Reshape(x, y, w, h);
}
// Yes, use x,y in user's space to find the nearest monitor in device space.
POINT pt = {x + w / 2, y + h / 2};
Devices::InstanceAccess devices;
HMONITOR monitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor);
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
// Try to set the correct size and jump to the correct location, even if it is
// on the different monitor. Note that for the "size" we use the current
// monitor, so the WM_DPICHANGED will adjust it for the "target" monitor.
int scaleUpAbsX = device == NULL ? x : device->ScaleUpAbsX(x);
int scaleUpAbsY = device == NULL ? y : device->ScaleUpAbsY(y);
ReshapeNoScale(scaleUpAbsX, scaleUpAbsY, ScaleUpX(w), ScaleUpY(h));
// The window manager may tweak the size for different reasons, so try
// to make sure our window has the correct size in the user's space.
// NOOP if the size was changed already or changing is in progress.
RECT rc;
::GetWindowRect(GetHWnd(), &rc);
ReshapeNoScale(rc.left, rc.top, ScaleUpX(w), ScaleUpY(h));
// the window manager may ignore our "SetWindowPos" request, in this,
// case the WmMove/WmSize will not come and we need to manually resync
// the "java.awt.Window" locations, because "java.awt.Window" already
// uses location ignored by the window manager.
::GetWindowRect(GetHWnd(), &rc);
if (x != ScaleDownAbsX(rc.left) || y != ScaleDownAbsY(rc.top)) {
WmMove(rc.left, rc.top);
}
int userW = ScaleDownX(rc.right - rc.left);
int userH = ScaleDownY(rc.bottom - rc.top);
if (w != userW || h != userH) {
WmSize(SIZENORMAL, rc.right - rc.left, rc.bottom - rc.top);
}
}
void AwtWindow::Show()
{
m_visible = true;
@ -1774,6 +1794,15 @@ MsgRouting AwtWindow::WmShowWindow(BOOL show, UINT status)
return AwtCanvas::WmShowWindow(show, status);
}
void AwtWindow::WmDPIChanged(const LPARAM &lParam) {
// need to update the scales now, otherwise the ReshapeNoScale() will
// calculate the bounds wrongly
AwtWin32GraphicsDevice::ResetAllDesktopScales();
RECT *r = (RECT *) lParam;
ReshapeNoScale(r->left, r->top, r->right - r->left, r->bottom - r->top);
CheckIfOnNewScreen(true);
}
/*
* Override AwtComponent's move handling to first update the
* java AWT target's position fields directly, since Windows
@ -1789,30 +1818,21 @@ MsgRouting AwtWindow::WmMove(int x, int y)
// NOTE: See also AwtWindow::Reshape
return mrDoDefault;
}
if (m_screenNum == -1) {
// Set initial value
m_screenNum = GetScreenImOn();
}
else {
CheckIfOnNewScreen();
}
// Check for the new screen and update the java peer
CheckIfOnNewScreen(false); // postpone if different DPI
/* Update the java AWT target component's fields directly */
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
if (env->EnsureLocalCapacity(1) < 0) {
return mrConsume;
}
jobject peer = GetPeer(env);
jobject target = env->GetObjectField(peer, AwtObject::targetID);
jobject target = GetTarget(env);
RECT rect;
::GetWindowRect(GetHWnd(), &rect);
(env)->SetIntField(target, AwtComponent::xID, ScaleDownX(rect.left));
(env)->SetIntField(target, AwtComponent::yID, ScaleDownY(rect.top));
(env)->SetIntField(peer, AwtWindow::sysXID, ScaleDownX(rect.left));
(env)->SetIntField(peer, AwtWindow::sysYID, ScaleDownY(rect.top));
(env)->SetIntField(target, AwtComponent::xID, ScaleDownAbsX(rect.left));
(env)->SetIntField(target, AwtComponent::yID, ScaleDownAbsY(rect.top));
SendComponentEvent(java_awt_event_ComponentEvent_COMPONENT_MOVED);
env->DeleteLocalRef(target);
@ -1857,13 +1877,22 @@ MsgRouting AwtWindow::WmSizing()
MsgRouting AwtWindow::WmEnterSizeMove()
{
m_winSizeMove = TRUE;
// Below is a workaround, see CheckWindowDPIChange
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(m_screenNum);
if (device) {
prevScaleRec.screen = m_screenNum;
prevScaleRec.scaleX = device->GetScaleX();
prevScaleRec.scaleY = device->GetScaleY();
}
// Above is a workaround
return mrDoDefault;
}
MsgRouting AwtWindow::WmExitSizeMove()
{
m_winSizeMove = FALSE;
CheckWindowDPIChange();
CheckWindowDPIChange(); // workaround
return mrDoDefault;
}
@ -1880,6 +1909,8 @@ MsgRouting AwtWindow::WmSize(UINT type, int w, int h)
UpdateSecurityWarningVisibility();
return mrDoDefault;
}
// Check for the new screen and update the java peer
CheckIfOnNewScreen(false); // postpone if different DPI
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
if (env->EnsureLocalCapacity(1) < 0)
@ -1887,15 +1918,8 @@ MsgRouting AwtWindow::WmSize(UINT type, int w, int h)
jobject target = GetTarget(env);
// fix 4167248 : ensure the insets are up-to-date before using
BOOL insetsChanged = UpdateInsets(NULL);
int newWidth = w + m_insets.left + m_insets.right;
int newHeight = h + m_insets.top + m_insets.bottom;
(env)->SetIntField(target, AwtComponent::widthID, ScaleDownX(newWidth));
(env)->SetIntField(target, AwtComponent::heightID, ScaleDownY(newHeight));
jobject peer = GetPeer(env);
(env)->SetIntField(peer, AwtWindow::sysWID, ScaleDownX(newWidth));
(env)->SetIntField(peer, AwtWindow::sysHID, ScaleDownY(newHeight));
(env)->SetIntField(target, AwtComponent::widthID, ScaleDownX(w));
(env)->SetIntField(target, AwtComponent::heightID, ScaleDownY(h));
if (!AwtWindow::IsResizing()) {
WindowResized();
@ -1977,6 +2001,11 @@ LRESULT AwtWindow::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
LRESULT retValue = 0L;
switch(message) {
case WM_DPICHANGED: {
WmDPIChanged(lParam);
mr = mrConsume;
break;
}
case WM_GETICON:
mr = WmGetIcon(wParam, retValue);
break;
@ -2120,14 +2149,28 @@ int AwtWindow::GetScreenImOn() {
return scrnNum;
}
/* Check to see if we've been moved onto another screen.
/*
* Check to see if we've been moved onto another screen.
* If so, update internal data, surfaces, etc.
*/
void AwtWindow::CheckIfOnNewScreen() {
void AwtWindow::CheckIfOnNewScreen(BOOL force) {
int curScrn = GetScreenImOn();
if (curScrn != m_screenNum) { // we've been moved
// if moved from one monitor to another with different DPI, we should
// update the m_screenNum only if the size was updated as well in the
// WM_DPICHANGED.
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* oldDevice = devices->GetDevice(m_screenNum);
AwtWin32GraphicsDevice* newDevice = devices->GetDevice(curScrn);
if (!force && m_winSizeMove && oldDevice && newDevice) {
if (oldDevice->GetScaleX() != newDevice->GetScaleX()
|| oldDevice->GetScaleY() != newDevice->GetScaleY()) {
// scales are different, wait for WM_DPICHANGED
return;
}
}
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
jclass peerCls = env->GetObjectClass(m_peerObject);
@ -2149,67 +2192,39 @@ void AwtWindow::CheckIfOnNewScreen() {
}
}
// The shared code is not ready to the top-level window which crosses a few
// monitors with different DPI. Popup windows will start to use wrong screen,
// will be placed in the wrong place and will use the wrong size, see 8249164
// So we will "JUMP TO" the new screen.
void AwtWindow::CheckWindowDPIChange() {
if (prevScaleRec.screen != -1 ) {
float prevScaleX = prevScaleRec.scaleX;
float prevScaleY = prevScaleRec.scaleY;
if (prevScaleX >= 1 && prevScaleY >= 1) {
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(m_screenNum);
if (device) {
float scaleX = device->GetScaleX();
float scaleY = device->GetScaleY();
if (prevScaleX != scaleX || prevScaleY != scaleY) {
WindowDPIChange(prevScaleRec.screen, prevScaleX, prevScaleY,
m_screenNum, scaleX, scaleY);
if (prevScaleRec.screen != -1 && prevScaleRec.screen != m_screenNum) {
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice *device = devices->GetDevice(m_screenNum);
if (device) {
if (prevScaleRec.scaleX != device->GetScaleX()
|| prevScaleRec.scaleY != device->GetScaleY()) {
RECT rect;
::GetWindowRect(GetHWnd(), &rect);
int x = rect.left;
int y = rect.top;
int w = rect.right - rect.left;
int h = rect.bottom - rect.top;
RECT bounds;
if (MonitorBounds(device->GetMonitor(), &bounds)) {
x = x < bounds.left ? bounds.left : x;
y = y < bounds.top ? bounds.top : y;
x = (x + w > bounds.right) ? bounds.right - w : x;
y = (y + h > bounds.bottom) ? bounds.bottom - h : y;
}
ReshapeNoScale(x, y, w, h);
}
}
prevScaleRec.screen = -1;
prevScaleRec.scaleX = -1.0f;
prevScaleRec.scaleY = -1.0f;
}
}
void AwtWindow::WindowDPIChange(int prevScreen,
float prevScaleX, float prevScaleY,
int screen, float scaleX,
float scaleY)
{
int x;
int y;
int w;
int h;
RECT rect;
if (prevScaleX == scaleX && prevScaleY == scaleY) {
return;
}
::GetWindowRect(GetHWnd(), &rect);
x = rect.left;
y = rect.top;
w = (rect.right - rect.left) * scaleX / prevScaleX;
h = (rect.bottom - rect.top) * scaleY / prevScaleY;
if (prevScreen != screen) {
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
if (device) {
RECT bounds;
if (MonitorBounds(device->GetMonitor(), &bounds)) {
x = x < bounds.left ? bounds.left : x;
y = y < bounds.top ? bounds.top : y;
x = (x + w > bounds.right) ? bounds.right - w : x;
y = (y + h > bounds.bottom) ? bounds.bottom - h : y;
}
}
}
ReshapeNoScale(x, y, w, h);
}
BOOL AwtWindow::IsFocusableWindow() {
/*
* For Window/Frame/Dialog to accept focus it should:
@ -2582,15 +2597,11 @@ void AwtWindow::_ReshapeFrame(void *param)
{
env->SetIntField(target, AwtComponent::widthID,
w = minWidth);
env->SetIntField(peer, AwtWindow::sysWID,
w);
}
if (h < minHeight)
{
env->SetIntField(target, AwtComponent::heightID,
h = minHeight);
env->SetIntField(peer, AwtWindow::sysHID,
h);
}
}
env->DeleteLocalRef(target);
@ -3257,39 +3268,6 @@ void AwtWindow::_GetNativeWindowSize(void* param) {
env->DeleteGlobalRef(self);
}
void AwtWindow::_WindowDPIChange(void* param)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
ScaleStruct *ss = (ScaleStruct *)param;
jobject self = ss->window;
jint prevScreen = ss->prevScreen;
jfloat prevScaleX = ss->prevScaleX;
jfloat prevScaleY = ss->prevScaleY;
jint screen = ss->screen;
jfloat scaleX = ss->scaleX;
jfloat scaleY = ss->scaleY;
PDATA pData;
JNI_CHECK_PEER_GOTO(self, ret);
AwtWindow *window = (AwtWindow *)pData;
if (window->m_winSizeMove) {
if (window->prevScaleRec.screen == -1) {
window->prevScaleRec.screen = prevScreen;
window->prevScaleRec.scaleX = prevScaleX;
window->prevScaleRec.scaleY = prevScaleY;
}
}
else {
window->WindowDPIChange(prevScreen, prevScaleX, prevScaleY,
screen, scaleX, scaleY);
}
ret:
env->DeleteGlobalRef(self);
delete ss;
}
extern "C" int getSystemMetricValue(int msgType);
extern "C" {
@ -3347,11 +3325,6 @@ Java_sun_awt_windows_WWindowPeer_initIDs(JNIEnv *env, jclass cls)
{
TRY;
CHECK_NULL(AwtWindow::sysXID = env->GetFieldID(cls, "sysX", "I"));
CHECK_NULL(AwtWindow::sysYID = env->GetFieldID(cls, "sysY", "I"));
CHECK_NULL(AwtWindow::sysWID = env->GetFieldID(cls, "sysW", "I"));
CHECK_NULL(AwtWindow::sysHID = env->GetFieldID(cls, "sysH", "I"));
AwtWindow::windowTypeID = env->GetFieldID(cls, "windowType",
"Ljava/awt/Window$Type;");
@ -3991,33 +3964,6 @@ Java_sun_awt_windows_WWindowPeer_repositionSecurityWarning(JNIEnv *env,
CATCH_BAD_ALLOC;
}
/*
* Class: sun_awt_windows_WWindowPeer
* Method: windowDPIChange
* Signature: (IFFIFF)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_windows_WWindowPeer_windowDPIChange(JNIEnv *env, jobject self,
jint prevScreen, jfloat prevScaleX, jfloat prevScaleY,
jint screen, jfloat scaleX, jfloat scaleY)
{
TRY;
ScaleStruct *ss = new ScaleStruct;
ss->window = env->NewGlobalRef(self);
ss->prevScreen = prevScreen;
ss->prevScaleX = prevScaleX;
ss->prevScaleY = prevScaleY;
ss->screen = screen;
ss->scaleX = scaleX;
ss->scaleY = scaleY;
AwtToolkit::GetInstance().InvokeFunction(AwtWindow::_WindowDPIChange, ss);
// global refs and ss are deleted in _WindowDPIChange
CATCH_BAD_ALLOC;
}
/*
* Class: sun_awt_windows_WLightweightFramePeer
* Method: overrideNativeHandle

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 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
@ -58,12 +58,6 @@ public:
static jfieldID securityWarningHeightID;
/* sun.awt.windows.WWindowPeer field and method IDs */
// The coordinates at the peer.
static jfieldID sysXID;
static jfieldID sysYID;
static jfieldID sysWID;
static jfieldID sysHID;
static jfieldID windowTypeID;
static jmethodID notifyWindowStateChangedMID;
@ -129,6 +123,7 @@ public:
return FALSE;
}
virtual void Reshape(int x, int y, int w, int h);
virtual void Invalidate(RECT* r);
virtual void Show();
virtual void SetResizable(BOOL isResizable);
@ -136,7 +131,7 @@ public:
virtual void RecalcNonClient();
virtual void RedrawNonClient();
virtual int GetScreenImOn();
virtual void CheckIfOnNewScreen();
virtual void CheckIfOnNewScreen(BOOL force);
virtual void Grab();
virtual void Ungrab();
virtual void Ungrab(BOOL doPost);
@ -248,7 +243,6 @@ public:
static void _RepositionSecurityWarning(void* param);
static void _SetFullScreenExclusiveModeState(void* param);
static void _GetNativeWindowSize(void* param);
static void _WindowDPIChange(void* param);
static void _OverrideHandle(void *param);
inline static BOOL IsResizing() {
@ -409,8 +403,7 @@ private:
void InitOwner(AwtWindow *owner);
void CheckWindowDPIChange();
void WindowDPIChange(int prevScreen, float prevScaleX, float prevScaleY,
int newScreen, float scaleX, float scaleY);
void WmDPIChanged(const LPARAM &lParam);
Type m_windowType;
void InitType(JNIEnv *env, jobject peer);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 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
@ -41,6 +41,10 @@ extern const UINT SYSCOMMAND_IMM;
* See winuser.h for details.
*/
#ifndef WM_DPICHANGED
#define WM_DPICHANGED 0x02E0
#endif //WM_DPICHANGED
#ifndef WM_MOUSEWHEEL
#define WM_MOUSEWHEEL 0x020A
#endif //WM_MOUSEWHEEL

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.Button;
import java.awt.Canvas;
import java.awt.Checkbox;
import java.awt.Choice;
import java.awt.Component;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Label;
import java.awt.List;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.ScrollPane;
import java.awt.Scrollbar;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.Window;
/**
* @test
* @key headful
* @bug 8211999
* @run main/othervm SetComponentsBounds
* @run main/othervm -Dsun.java2d.uiScale=1 SetComponentsBounds
* @run main/othervm -Dsun.java2d.uiScale=2.25 SetComponentsBounds
*/
public final class SetComponentsBounds {
private static final int X = 111;
private static final int Y = 222;
private static final int WIDTH = 321;
private static final int HEIGHT = 123;
public static void main(String[] args) throws Exception {
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
for (GraphicsDevice gd : ge.getScreenDevices()) {
test(gd.getDefaultConfiguration(), true);
test(gd.getDefaultConfiguration(), false);
}
}
private static void test(GraphicsConfiguration gc, boolean visible) throws Exception {
Rectangle screen = gc.getBounds();
Window frame = new Frame();
try {
frame.setLayout(null); // trigger use the minimum size of
// the peer
frame.setBounds(screen.x + 100, screen.y + 100, 500, 500);
frame.add(new Button());
frame.add(new Canvas());
frame.add(new Checkbox());
frame.add(new Choice());
frame.add(new Label());
frame.add(new List());
frame.add(new Scrollbar());
frame.add(new ScrollPane());
frame.add(new TextArea());
frame.add(new TextField());
for (Component comp : frame.getComponents()) {
comp.setBounds(X, Y, WIDTH, HEIGHT);
}
if (visible) {
frame.setVisible(true);
} else {
frame.pack();
}
Robot robot = new Robot();
robot.waitForIdle();
checkGC(gc, frame);
for (Component comp : frame.getComponents()) {
Rectangle bounds = comp.getBounds();
if (bounds.x != X || bounds.y != Y || bounds.width != WIDTH) {
System.err.println("Screen bounds:" + screen);
System.err.println("Component:" + comp);
throw new RuntimeException("Wrong bounds:" + bounds);
}
if (bounds.height > HEIGHT) {
// different check for HEIGHT, it depends on the font
throw new RuntimeException("Wrong height:" + bounds.height);
}
checkGC(gc, comp);
}
} finally {
frame.dispose();
}
}
private static void checkGC(GraphicsConfiguration gc, Component comp) {
GraphicsConfiguration compGC = comp.getGraphicsConfiguration();
if (compGC != gc) {
System.err.println("Expected GC:" + gc);
System.err.println("Actual GC:" + compGC);
throw new RuntimeException();
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
@ -24,7 +24,7 @@
/**
* @test
* @key headful
* @bug 6345003 8171363
* @bug 6345003 8171363 8211999
* @summary grab problems with EmbeddedFrame
* @requires (os.family == "windows")
* @modules java.desktop/java.awt.peer
@ -67,6 +67,7 @@ public class EmbeddedFrameGrabTest {
final Frame frame = new Frame("AWT Frame");
frame.pack();
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
FramePeer frame_peer = AWTAccessor.getComponentAccessor()
.getPeer(frame);
Class comp_peer_class
@ -88,6 +89,7 @@ public class EmbeddedFrameGrabTest {
final Panel p = new Panel();
p.setLayout(new BorderLayout());
embedded_frame.add(p, BorderLayout.CENTER);
embedded_frame.setBounds(0, 0, 150, 150);
embedded_frame.validate();
p.add(combo);
p.validate();

View File

@ -21,6 +21,7 @@
* questions.
*/
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
@ -30,7 +31,7 @@ import java.awt.Toolkit;
/**
* @test
* @bug 8176359 8231564
* @bug 8176359 8231564 8211999
* @key headful
* @requires (os.family == "windows" | os.family == "mac")
* @summary setMaximizedBounds() should work if set to the screen other than
@ -58,15 +59,23 @@ public final class MaximizedToOppositeScreenSmall {
Rectangle framAt = gd1.getDefaultConfiguration().getBounds();
framAt.grow(-framAt.width / 2 + 100, -framAt.height / 2 + 100);
for (GraphicsDevice gd2 : gds) {
Rectangle maxTo = gd2.getDefaultConfiguration().getBounds();
maxTo.grow(-maxTo.width / 2 + 120, -maxTo.height / 2 + 120);
Frame frame = new Frame(gd1.getDefaultConfiguration());
try {
frame.setLayout(null); // trigger use the minimum size of
// the peer
frame.setBounds(framAt);
frame.setVisible(true);
robot.waitForIdle();
robot.delay(1000);
Dimension minimumSize = frame.getMinimumSize();
minimumSize.width = Math.max(minimumSize.width, 120);
minimumSize.height = Math.max(minimumSize.height, 120);
Rectangle maxTo = gd2.getDefaultConfiguration().getBounds();
maxTo.grow(-maxTo.width / 2 + minimumSize.width,
-maxTo.height / 2 + minimumSize.height);
frame.setMaximizedBounds(maxTo);
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
robot.waitForIdle();

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
/**
* @test
* @bug 8211999
* @key headful
* @summary verifies the full-screen window bounds and graphics configuration
*/
public final class FullscreenWindowProps {
public static void main(String[] args) throws Exception {
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
if (!gd.isFullScreenSupported()) {
return;
}
Frame frame = new Frame() {
@Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.GREEN);
g.fillRect(0, 0, getWidth(), getHeight());
}
};
try {
frame.setBackground(Color.MAGENTA);
frame.setVisible(true);
gd.setFullScreenWindow(frame);
Thread.sleep(4000);
for (DisplayMode dm : gd.getDisplayModes()) {
if (dm.getWidth() == 1024 && dm.getHeight() == 768) {
gd.setDisplayMode(dm);
Thread.sleep(4000);
break;
}
}
GraphicsConfiguration frameGC = frame.getGraphicsConfiguration();
Rectangle frameBounds = frame.getBounds();
GraphicsConfiguration screenGC = gd.getDefaultConfiguration();
Rectangle screenBounds = screenGC.getBounds();
if (frameGC != screenGC) {
System.err.println("Expected: " + screenGC);
System.err.println("Actual: " + frameGC);
throw new RuntimeException();
}
checkSize(frameBounds.x, screenBounds.x, "x");
checkSize(frameBounds.y, screenBounds.y, "Y");
checkSize(frameBounds.width, screenBounds.width, "width");
checkSize(frameBounds.height, screenBounds.height, "height");
} finally {
gd.setFullScreenWindow(null);
frame.dispose();
Thread.sleep(10000);
}
}
private static void checkSize(int actual, int expected, String prop) {
if (Math.abs(actual - expected) > 30) { // let's allow size variation,
// the bug is reproduced anyway
System.err.println("Expected: " + expected);
System.err.println("Actual: " + actual);
throw new RuntimeException(prop + " is wrong");
}
}
}

View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 1996, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.List;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;
/**
* @test
* @bug 4909485 8211999
* @key headful
*/
public final class ListMultipleSelectTest {
private static List aList;
private static Panel panel;
private static Point p;
private static Robot robot;
private static int[] selected;
public static void main(String[] args) throws Exception {
Frame frame = new Frame();
try {
panel = new Panel();
aList = new List();
aList.add("Test item1");
aList.add("Test item2");
aList.add("Test item3");
aList.add("Test item4");
frame.setLayout(new FlowLayout()); //list should fill whole frame's space
panel.add(aList);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
panel.setVisible(true);
frame.add(panel);
frame.setVisible(true);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(" InterruptedException. Test failed. ");
}
Dimension listSize = aList.getSize();
p = aList.getLocationOnScreen();
int stepY = listSize.height / aList.getItemCount();
// System.out.println("itemCount = "+aList.getItemCount());
// System.out.println("Size Of aList="+ listSize);
// System.out.println("stepY = "+stepY);
// System.out.println("Point:" +p);
System.out.println("Multiple mode is ON");
aList.setMultipleMode(true);
//=================================================
robot = new Robot();
robot.setAutoDelay(0);
robot.setAutoWaitForIdle(false);
robot.delay(10);
robot.waitForIdle();
//=================================================
for (int i = 0; i < aList.getItemCount(); i++) {
//select all items in the List
mousePress(p.x + listSize.width / 2, p.y + stepY / 2 + stepY * i);
}
selected = aList.getSelectedIndexes();
System.out.println("Multiple mode is ON");
aList.setMultipleMode(true);
int[] newSelected = aList.getSelectedIndexes();
if (!java.util.Arrays.equals(newSelected, selected)) {
throw new RuntimeException(" Incorrect item remains selected " +
"after setMultipleMode(true). ");
}
aList.setMultipleMode(false);
System.out.println("Multiple mode is OFF");
selected = aList.getSelectedIndexes();
if (selected[0] != 3 || selected.length != 1) {
throw new RuntimeException(" Incorrect item remains selected " +
"after setMultipleMode(false) or it is more then one " +
"item remaining.Forward. ");
}
System.out.println("Multiple mode is ON");
aList.setMultipleMode(true);
if (selected[0] != 3 || selected.length != 1) {
throw new RuntimeException(" Incorrect item remains selected " +
"after setMultipleMode(true) or it is more then one " +
"item remaining. ");
}
deselectAll();
for (int i = aList.getItemCount() - 1; i >= 0; i--) {
mousePress(p.x + listSize.width / 2, p.y + stepY / 2 + stepY * i);
}
System.out.println("Multiple mode is OFF");
aList.setMultipleMode(false);
selected = aList.getSelectedIndexes();
if (selected[0] != 0 || selected.length != 1) {
throw new RuntimeException(" Incorrect item remains selected " +
"after setMultipleMode(false) or it is more then one " +
"item remaining.Backward. ");
}
System.out.println("Test succeeded.");
} finally {
frame.dispose();
}
}
private static void mousePress(int x, int y) {
robot.mouseMove(x, y);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.delay(1000);
}
private static void deselectAll() {
for (int i = 0; i < selected.length; i++) {
aList.deselect(selected[i]);
}
}
}

View File

@ -24,7 +24,7 @@
/*
@test
@key headful
@bug 8017472
@bug 8017472 8211999
@summary MouseEvent has wrong coordinates when using multiple monitors
@run main MouseEventTest
*/

View File

@ -24,6 +24,8 @@
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
@ -38,7 +40,7 @@ import javax.imageio.ImageIO;
/**
* @test
* @key headful
* @bug 8215105
* @bug 8215105 8211999
* @summary tests that Robot can capture the common colors without artifacts
*/
public final class CheckCommonColors {
@ -48,16 +50,20 @@ public final class CheckCommonColors {
public static void main(final String[] args) throws Exception {
robot = new Robot();
try {
test();
} finally {
frame.dispose();
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
for (GraphicsDevice gd : ge.getScreenDevices()) {
try {
test(gd.getDefaultConfiguration().getBounds());
} finally {
frame.dispose();
}
}
}
private static void test() {
private static void test(Rectangle screen) {
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setLocation((int)screen.getCenterX() - 200,
(int)screen.getCenterY() - 200);
frame.setUndecorated(true);
for (final Color color : List.of(Color.WHITE, Color.LIGHT_GRAY,
Color.GRAY, Color.DARK_GRAY,
@ -69,16 +75,25 @@ public final class CheckCommonColors {
robot.waitForIdle();
frame.setBackground(color);
frame.setVisible(true);
checkPixels(color);
checkPixels(color, true);
checkPixels(color, false);
}
}
private static void checkPixels(final Color color) {
private static void checkPixels(final Color color, boolean useRect) {
System.out.println("color = " + color + ", useRect = " + useRect);
int attempt = 0;
while (true) {
Point p = frame.getLocationOnScreen();
p.translate(frame.getWidth() / 2, frame.getHeight() / 2);
Color pixel = robot.getPixelColor(p.x, p.y);
Color pixel;
Rectangle rect = new Rectangle(p.x, p.y, 1, 1);
if (useRect) {
BufferedImage bi = robot.createScreenCapture(rect);
pixel = new Color(bi.getRGB(0, 0));
} else {
pixel = robot.getPixelColor(rect.x, rect.y);
}
if (color.equals(pixel)) {
return;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 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
@ -32,7 +32,7 @@ import java.awt.Robot;
/**
* @test
* @key headful
* @bug 8201364 8232433
* @bug 8201364 8232433 8211999
* @summary Component.getLocation() should returns correct location if
* Component.setBounds() was ignored by the OS
*/
@ -64,8 +64,11 @@ public final class LocationAtScreenCorner {
Rectangle bounds = device.getDefaultConfiguration().getBounds();
test(robot, frame, bounds.x, bounds.y);
test(robot, frame, bounds.width, bounds.y);
test(robot, frame, bounds.x + bounds.width, bounds.y);
test(robot, frame, bounds.x, bounds.height);
test(robot, frame, bounds.x, bounds.y + bounds.height);
test(robot, frame, bounds.width, bounds.height);
test(robot, frame, bounds.x + bounds.width, bounds.y + bounds.height);
}
frame.dispose();
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.Window;
/**
* @test
* @key headful
* @bug 8211999
* @run main/timeout=300 SlowMotion
* @summary places the window on the screen outside of any insets, and waits to
* catch any strange window moving
*/
public final class SlowMotion {
// some additional space, if getScreenInsets() does not work, say on Linux
private static final int SAFE = 100;
private static final int HEIGHT = 350;
private static final int WIDTH = 279;
private static Robot robot;
public static void main(final String[] args) throws Exception {
robot = new Robot();
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] sds = ge.getScreenDevices();
for (GraphicsDevice sd : sds) {
GraphicsConfiguration gc = sd.getDefaultConfiguration();
Rectangle bounds = gc.getBounds();
bounds.translate(SAFE, SAFE);
Point point = new Point(bounds.x, bounds.y);
Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
while (point.y < bounds.y + bounds.height - insets.bottom - HEIGHT - SAFE * 2) {
while (point.x < bounds.x + bounds.width - insets.right - WIDTH - SAFE * 2) {
test(point, new Frame());
test(point, new Window(null));
test(point, new Dialog((Dialog) null));
point.translate(bounds.width / 6, 0);
}
point.setLocation(bounds.x, point.y + bounds.height / 5);
}
}
}
private static void test(final Point loc, Window window) {
try {
window.setBounds(loc.x, loc.y, WIDTH, HEIGHT);
window.setVisible(true);
robot.delay(1000); // intentionally very slow, we try to catch
// very very last suspicion event
Rectangle bounds = window.getBounds();
if (loc.x != bounds.x || loc.y != bounds.y
|| bounds.width != WIDTH || bounds.height != HEIGHT) {
System.err.println("Component = " + window);
System.err.println("Actual bounds = " + bounds);
System.err.println("Expected location = " + loc);
System.err.println("Expected width = " + WIDTH);
System.err.println("Expected height = " + HEIGHT);
throw new RuntimeException();
}
} finally {
window.dispose();
}
}
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.Color;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Window;
/**
* @test
* @key headful
* @bug 8211999
* @summary The test creates the packed/unpacked top level components on the
* different screens and compares their bounds
* @run main/othervm WindowSizeDifferentScreens
* @run main/othervm -Dsun.java2d.uiScale=1 WindowSizeDifferentScreens
* @run main/othervm -Dsun.java2d.uiScale=1.25 WindowSizeDifferentScreens
*/
public final class WindowSizeDifferentScreens {
public static void main(String[] args) throws Exception {
test("window");
test("dialog");
test("frame");
}
private static void test(String top) throws Exception {
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Robot robot = new Robot();
Window main = getTopLevel(top);
try {
main.setVisible(true);
robot.waitForIdle();
main.setSize(500, 500);
robot.waitForIdle();
for (GraphicsDevice gd : ge.getScreenDevices()) {
Rectangle bounds = gd.getDefaultConfiguration().getBounds();
Point point = bounds.getLocation();
point.translate(100, 100);
main.setLocation(point);
main.setBackground(Color.RED);
robot.waitForIdle();
Window packed = getTopLevel(top);
Window unpacked = getTopLevel(top);
try {
packed.pack();
robot.waitForIdle();
packed.setBackground(Color.GREEN);
unpacked.setBackground(Color.BLUE);
packed.setSize(500, 500);
unpacked.setSize(500, 500);
packed.setLocation(point);
unpacked.setLocation(point);
robot.waitForIdle();
packed.setVisible(true);
unpacked.setVisible(true);
robot.waitForIdle();
Rectangle mBounds = main.getBounds();
Rectangle pBounds = packed.getBounds();
Rectangle uBounds = unpacked.getBounds();
if (!mBounds.equals(uBounds) ||
!mBounds.equals(pBounds)) {
System.err.println("Expected bounds: " + mBounds);
System.err.println("Actual unpacked: " + uBounds);
System.err.println("Actual packed: " + pBounds);
throw new RuntimeException();
}
} finally {
packed.dispose();
unpacked.dispose();
}
}
} finally {
main.dispose();
}
}
private static Window getTopLevel(String top) {
return switch (top) {
case "window" -> new Window(null);
case "dialog" -> new Dialog((Dialog) null);
case "frame" -> new Frame();
default -> throw new IllegalArgumentException("Unexpected: " + top);
};
}
}

View File

@ -23,10 +23,10 @@
import java.awt.Color;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.datatransfer.StringSelection;
import java.awt.dnd.DnDConstants;
@ -47,7 +47,7 @@ import test.java.awt.regtesthelpers.Util;
/**
* @test
* @key headful
* @bug 4955110 8238575
* @bug 4955110 8238575 8211999
* @summary tests that DragSourceDragEvent.getDropAction() accords to its new
* spec (does not depend on the user drop action)
* @library ../../regtesthelpers
@ -57,6 +57,7 @@ import test.java.awt.regtesthelpers.Util;
*/
public final class Button2DragTest {
private static final int SIZE = 200;
private volatile boolean dropSuccess;
private volatile boolean locationValid = true;
@ -79,8 +80,8 @@ public final class Button2DragTest {
final DragSourceListener dragSourceListener = new DragSourceListener() {
private void checkLocation(DragSourceEvent dsde) {
if (!frame.getBounds().contains(dsde.getLocation())) {
System.err.println("Expected in" + frame.getBounds());
System.err.println("Actual" + dsde.getLocation());
System.err.println("Expected in: " + frame.getBounds());
System.err.println("Actual: " + dsde.getLocation());
locationValid = false;
}
}
@ -130,8 +131,10 @@ public final class Button2DragTest {
frame.setBackground(Color.GREEN);
frame.setUndecorated(true);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
Rectangle screen = frame.getGraphicsConfiguration().getBounds();
int x = (int) (screen.getCenterX() - SIZE / 2);
int y = (int) (screen.getCenterY() - SIZE / 2);
frame.setBounds(x, y, SIZE, SIZE);
frame.setVisible(true);
Robot robot = Util.createRobot();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -24,7 +24,10 @@
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.InputEvent;
import javax.swing.JFrame;
@ -35,13 +38,15 @@ import javax.swing.SwingUtilities;
/**
* @test
* @key headful
* @bug 8149849
* @bug 8149849 8211999
* @summary [hidpi] DnD issues (cannot DnD from JFileChooser to JEditorPane or
* other text component) when scale > 1
* @run main/othervm DNDTextToScaledArea
* @run main/othervm -Dsun.java2d.uiScale=2 DNDTextToScaledArea
*/
public class DNDTextToScaledArea {
private static final int SIZE = 300;
private static final String TEXT = "ABCDEFGH";
private static JFrame frame;
private static JTextArea srcTextArea;
@ -51,10 +56,17 @@ public class DNDTextToScaledArea {
private static volatile boolean passed = false;
public static void main(String[] args) throws Exception {
Robot robot = new Robot();
robot.setAutoDelay(50);
var lge = GraphicsEnvironment.getLocalGraphicsEnvironment();
for (GraphicsDevice device : lge.getScreenDevices()) {
test(device);
}
}
SwingUtilities.invokeAndWait(DNDTextToScaledArea::createAndShowGUI);
private static void test(GraphicsDevice device) throws Exception {
Robot robot = new Robot();
robot.setAutoDelay(150);
SwingUtilities.invokeAndWait(() -> createAndShowGUI(device));
robot.waitForIdle();
SwingUtilities.invokeAndWait(() -> {
@ -62,6 +74,11 @@ public class DNDTextToScaledArea {
dstPoint = getPoint(dstTextArea, 0.75);
});
robot.waitForIdle();
// check the destination
robot.mouseMove(dstPoint.x, dstPoint.y);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.waitForIdle();
dragAndDrop(robot, srcPoint, dstPoint);
robot.waitForIdle();
@ -77,11 +94,12 @@ public class DNDTextToScaledArea {
}
}
private static void createAndShowGUI() {
frame = new JFrame();
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
private static void createAndShowGUI(GraphicsDevice device) {
frame = new JFrame(device.getDefaultConfiguration());
Rectangle screen = device.getDefaultConfiguration().getBounds();
int x = (int) (screen.getCenterX() - SIZE / 2);
int y = (int) (screen.getCenterY() - SIZE / 2);
frame.setBounds(x, y, SIZE, SIZE);
JPanel panel = new JPanel(new BorderLayout());