--- old/make/mapfiles/libawt/mapfile-vers-linux 2015-10-05 07:32:33.335038768 -0400 +++ new/make/mapfiles/libawt/mapfile-vers-linux 2015-10-05 07:32:33.215038770 -0400 @@ -206,6 +206,7 @@ Java_sun_awt_X11GraphicsDevice_enumDisplayModes; Java_sun_awt_X11GraphicsDevice_configDisplayMode; Java_sun_awt_X11GraphicsDevice_resetNativeData; + Java_sun_awt_X11GraphicsDevice_getNativeScaleFactor; Java_sun_awt_X11GraphicsEnvironment_checkShmExt; Java_sun_awt_X11GraphicsEnvironment_getDefaultScreenNum; Java_sun_awt_X11GraphicsEnvironment_getDisplayString; --- old/make/mapfiles/libawt_xawt/mapfile-vers 2015-10-05 07:32:33.651038761 -0400 +++ new/make/mapfiles/libawt_xawt/mapfile-vers 2015-10-05 07:32:33.535038763 -0400 @@ -214,6 +214,7 @@ Java_sun_awt_X11GraphicsDevice_enumDisplayModes; Java_sun_awt_X11GraphicsDevice_configDisplayMode; Java_sun_awt_X11GraphicsDevice_resetNativeData; + Java_sun_awt_X11GraphicsDevice_getNativeScaleFactor; Java_sun_awt_X11GraphicsConfig_initIDs; Java_sun_awt_X11GraphicsConfig_getXResolution; Java_sun_awt_X11GraphicsConfig_getYResolution; --- old/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java 2015-10-05 07:32:34.023038753 -0400 +++ new/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java 2015-10-05 07:32:33.903038755 -0400 @@ -166,7 +166,12 @@ } @Override - public int getDefaultScale() { + public double getDefaultScaleX() { + return scale; + } + + @Override + public double getDefaultScaleY() { return scale; } --- old/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java 2015-10-05 07:32:34.411038744 -0400 +++ new/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java 2015-10-05 07:32:34.295038747 -0400 @@ -1156,7 +1156,9 @@ && !(dst instanceof NullSurfaceData) && !(src instanceof NullSurfaceData) && src.getSurfaceType().equals(dst.getSurfaceType()) - && src.getDefaultScale() == dst.getDefaultScale()) { + && src.getDefaultScaleX() == dst.getDefaultScaleX() + && src.getDefaultScaleY() == dst.getDefaultScaleY()) + { final Rectangle size = src.getBounds(); final Blit blit = Blit.locate(src.getSurfaceType(), CompositeType.Src, --- old/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java 2015-10-05 07:32:34.827038735 -0400 +++ new/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java 2015-10-05 07:32:34.671038738 -0400 @@ -290,16 +290,30 @@ } /** - * Returns a scale factor of the image. This is utility method, which - * fetches information from the SurfaceData of the image. + * Returns a horizontal scale factor of the image. This is utility method, + * which fetches information from the SurfaceData of the image. * - * @see SurfaceData#getDefaultScale + * @see SurfaceData#getDefaultScaleX */ - public static int getImageScale(final Image img) { + public static double getImageScaleX(final Image img) { if (!(img instanceof VolatileImage)) { return 1; } final SurfaceManager sm = getManager(img); - return sm.getPrimarySurfaceData().getDefaultScale(); + return sm.getPrimarySurfaceData().getDefaultScaleX(); + } + + /** + * Returns a vertical scale factor of the image. This is utility method, + * which fetches information from the SurfaceData of the image. + * + * @see SurfaceData#getDefaultScaleY + */ + public static double getImageScaleY(final Image img) { + if (!(img instanceof VolatileImage)) { + return 1; + } + final SurfaceManager sm = getManager(img); + return sm.getPrimarySurfaceData().getDefaultScaleY(); } } --- old/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java 2015-10-05 07:32:35.167038728 -0400 +++ new/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java 2015-10-05 07:32:35.043038730 -0400 @@ -61,7 +61,6 @@ import java.awt.Rectangle; import java.text.AttributedCharacterIterator; import java.awt.Font; -import java.awt.Point; import java.awt.image.ImageObserver; import java.awt.Transparency; import java.awt.font.GlyphVector; @@ -99,6 +98,7 @@ import static java.awt.geom.AffineTransform.TYPE_FLIP; import static java.awt.geom.AffineTransform.TYPE_MASK_SCALE; import static java.awt.geom.AffineTransform.TYPE_TRANSLATION; +import java.awt.image.VolatileImage; import sun.awt.image.MultiResolutionToolkitImage; import sun.awt.image.ToolkitImage; @@ -3086,22 +3086,30 @@ } // end of text rendering methods - private boolean isHiDPIImage(final Image img) { - return (SurfaceManager.getImageScale(img) != 1) - || img instanceof MultiResolutionImage; - } - - private boolean drawHiDPIImage(Image img, int dx1, int dy1, int dx2, - int dy2, int sx1, int sy1, int sx2, int sy2, - Color bgcolor, ImageObserver observer) { - - if (SurfaceManager.getImageScale(img) != 1) { // Volatile Image - final int scale = SurfaceManager.getImageScale(img); - sx1 = Region.clipScale(sx1, scale); - sx2 = Region.clipScale(sx2, scale); - sy1 = Region.clipScale(sy1, scale); - sy2 = Region.clipScale(sy2, scale); - } else if (img instanceof MultiResolutionImage) { + private Boolean drawHiDPIImage(Image img, + int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer, + AffineTransform xform) { + + if (img instanceof VolatileImage) { + final SurfaceData sd = SurfaceManager.getManager(img) + .getPrimarySurfaceData(); + final double scaleX = sd.getDefaultScaleX(); + final double scaleY = sd.getDefaultScaleY(); + if (scaleX == 1 && scaleY == 1) { + return null; + } + sx1 = Region.clipScale(sx1, scaleX); + sx2 = Region.clipScale(sx2, scaleX); + sy1 = Region.clipScale(sy1, scaleY); + sy2 = Region.clipScale(sy2, scaleY); + + return scaleImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, + bgcolor, observer, xform); + } else if (resolutionVariantHint != SunHints.INTVAL_RESOLUTION_VARIANT_BASE + && (img instanceof MultiResolutionImage)) { // get scaled destination image size int width = img.getWidth(observer); @@ -3133,9 +3141,26 @@ observer = rvObserver; img = resolutionVariant; + return scaleImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, + bgcolor, observer, xform); } } } + return null; + } + + private boolean scaleImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer, + AffineTransform xform) { + + AffineTransform tx = null; + + if (xform != null) { + tx = new AffineTransform(transform); + transform(xform); + } try { return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1, sy1, @@ -3153,6 +3178,11 @@ } } finally { surfaceData.markDirty(); + + if (tx != null) { + transform.setTransform(tx); + invalidateTransform(); + } } } @@ -3277,9 +3307,11 @@ final int imgW = img.getWidth(null); final int imgH = img.getHeight(null); - if (isHiDPIImage(img)) { - return drawHiDPIImage(img, x, y, x + width, y + height, 0, 0, imgW, - imgH, bg, observer); + Boolean hidpiImageDrawn = drawHiDPIImage(img, x, y, x + width, y + height, + 0, 0, imgW, imgH, bg, observer, + null); + if (hidpiImageDrawn != null) { + return hidpiImageDrawn; } if (width == imgW && height == imgH) { @@ -3323,11 +3355,13 @@ return true; } - if (isHiDPIImage(img)) { - final int imgW = img.getWidth(null); - final int imgH = img.getHeight(null); - return drawHiDPIImage(img, x, y, x + imgW, y + imgH, 0, 0, imgW, - imgH, bg, observer); + final int imgW = img.getWidth(null); + final int imgH = img.getHeight(null); + Boolean hidpiImageDrawn = drawHiDPIImage(img, x, y, x + imgW, y + imgH, + 0, 0, imgW, imgH, bg, observer, + null); + if (hidpiImageDrawn != null) { + return hidpiImageDrawn; } try { @@ -3378,9 +3412,12 @@ return true; } - if (isHiDPIImage(img)) { - return drawHiDPIImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, - bgcolor, observer); + Boolean hidpiImageDrawn = drawHiDPIImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, + bgcolor, observer, null); + + if (hidpiImageDrawn != null) { + return hidpiImageDrawn; } if (((sx2 - sx1) == (dx2 - dx1)) && @@ -3461,16 +3498,13 @@ return drawImage(img, 0, 0, null, observer); } - if (isHiDPIImage(img)) { - final int w = img.getWidth(null); - final int h = img.getHeight(null); - final AffineTransform tx = new AffineTransform(transform); - transform(xform); - boolean result = drawHiDPIImage(img, 0, 0, w, h, 0, 0, w, h, null, - observer); - transform.setTransform(tx); - invalidateTransform(); - return result; + final int w = img.getWidth(null); + final int h = img.getHeight(null); + Boolean hidpiImageDrawn = drawHiDPIImage(img, 0, 0, w, h, 0, 0, w, h, + null, observer, xform); + + if (hidpiImageDrawn != null) { + return hidpiImageDrawn; } try { --- old/src/java.desktop/share/classes/sun/java2d/SurfaceData.java 2015-10-05 07:32:35.515038720 -0400 +++ new/src/java.desktop/share/classes/sun/java2d/SurfaceData.java 2015-10-05 07:32:35.395038723 -0400 @@ -1059,12 +1059,22 @@ public abstract Object getDestination(); /** - * Returns default scale factor of the destination surface. Scale factor - * describes the mapping between virtual and physical coordinates of the + * Returns default horizontal scale factor of the destination surface. Scale + * factor describes the mapping between virtual and physical coordinates of the * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be * doubled for physical pixels. */ - public int getDefaultScale() { + public double getDefaultScaleX() { + return 1; + } + + /** + * Returns default vertical scale factor of the destination surface. Scale + * factor describes the mapping between virtual and physical coordinates of the + * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be + * doubled for physical pixels. + */ + public double getDefaultScaleY() { return 1; } } --- old/src/java.desktop/share/classes/sun/java2d/pipe/DrawImage.java 2015-10-05 07:32:35.883038712 -0400 +++ new/src/java.desktop/share/classes/sun/java2d/pipe/DrawImage.java 2015-10-05 07:32:35.747038715 -0400 @@ -736,9 +736,10 @@ atfm.scale(m00, m11); atfm.translate(srcX-sx1, srcY-sy1); - final int scale = SurfaceManager.getImageScale(img); - final int imgW = img.getWidth(null) * scale; - final int imgH = img.getHeight(null) * scale; + final double scaleX = SurfaceManager.getImageScaleX(img); + final double scaleY = SurfaceManager.getImageScaleY(img); + final int imgW = (int) Math.ceil(img.getWidth(null) * scaleX); + final int imgH = (int) Math.ceil(img.getHeight(null) * scaleY); srcW += srcX; srcH += srcY; // Make sure we are not out of bounds --- old/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java 2015-10-05 07:32:36.275038704 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java 2015-10-05 07:32:36.159038706 -0400 @@ -80,9 +80,7 @@ pack(); Dimension size = getSize(); - // TODO: When 6356322 is fixed we should get screen bounds in - // this way: eframe.getGraphicsConfiguration().getBounds(). - Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize(); + Rectangle scrSize = getGraphicsConfiguration().getBounds(); if (corner.x < scrSize.width/2 && corner.y < scrSize.height/2) { // 1st square setLocation(corner.x + indent, corner.y + indent); --- old/src/java.desktop/unix/classes/sun/awt/X11/XBaseWindow.java 2015-10-05 07:32:36.647038695 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XBaseWindow.java 2015-10-05 07:32:36.531038698 -0400 @@ -300,6 +300,22 @@ } /** + * Returns scale factor of the window. It is used to convert native + * coordinates to local and vice verse. + */ + protected int getScale() { + return 1; + } + + protected int scaleUp(int x) { + return x; + } + + protected int scaleDown(int x) { + return x; + } + + /** * Creates window with parameters specified by params * @see #init */ @@ -366,15 +382,17 @@ log.fine("Creating window for " + this + " with the following attributes: \n" + params); } window = XlibWrapper.XCreateWindow(XToolkit.getDisplay(), - parentWindow.longValue(), - bounds.x, bounds.y, // location - bounds.width, bounds.height, // size - 0, // border - depth.intValue(), // depth - visual_class.intValue(), // class - visual.longValue(), // visual - value_mask, // value mask - xattr.pData); // attributes + parentWindow.longValue(), + scaleUp(bounds.x), + scaleUp(bounds.y), + scaleUp(bounds.width), + scaleUp(bounds.height), + 0, // border + depth.intValue(), // depth + visual_class.intValue(), // class + visual.longValue(), // visual + value_mask, // value mask + xattr.pData); // attributes if (window == 0) { throw new IllegalStateException("Couldn't create window because of wrong parameters. Run with NOISY_AWT to see details"); @@ -492,18 +510,18 @@ // we want to reset PPosition in hints. This is necessary // for locationByPlatform functionality if ((flags & XUtilConstants.PPosition) != 0) { - hints.set_x(x); - hints.set_y(y); + hints.set_x(scaleUp(x)); + hints.set_y(scaleUp(y)); } if ((flags & XUtilConstants.PSize) != 0) { - hints.set_width(width); - hints.set_height(height); + hints.set_width(scaleUp(width)); + hints.set_height(scaleUp(height)); } else if ((hints.get_flags() & XUtilConstants.PSize) != 0) { flags |= XUtilConstants.PSize; } if ((flags & XUtilConstants.PMinSize) != 0) { - hints.set_min_width(width); - hints.set_min_height(height); + hints.set_min_width(scaleUp(width)); + hints.set_min_height(scaleUp(height)); } else if ((hints.get_flags() & XUtilConstants.PMinSize) != 0) { flags |= XUtilConstants.PMinSize; //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced. @@ -512,31 +530,31 @@ if ((flags & XUtilConstants.PMaxSize) != 0) { if (maxBounds != null) { if (maxBounds.width != Integer.MAX_VALUE) { - hints.set_max_width(maxBounds.width); + hints.set_max_width(scaleUp(maxBounds.width)); } else { hints.set_max_width(XToolkit.getDefaultScreenWidth()); } if (maxBounds.height != Integer.MAX_VALUE) { - hints.set_max_height(maxBounds.height); + hints.set_max_height(scaleUp(maxBounds.height)); } else { hints.set_max_height(XToolkit.getDefaultScreenHeight()); } } else { - hints.set_max_width(width); - hints.set_max_height(height); + hints.set_max_width(scaleUp(width)); + hints.set_max_height(scaleUp(height)); } } else if ((hints.get_flags() & XUtilConstants.PMaxSize) != 0) { flags |= XUtilConstants.PMaxSize; if (maxBounds != null) { if (maxBounds.width != Integer.MAX_VALUE) { - hints.set_max_width(maxBounds.width); + hints.set_max_width(scaleUp(maxBounds.width)); } else { - hints.set_max_width(XToolkit.getDefaultScreenWidth()); + hints.set_max_width(scaleUp(XToolkit.getDefaultScreenWidth())); } if (maxBounds.height != Integer.MAX_VALUE) { - hints.set_max_height(maxBounds.height); + hints.set_max_height(scaleUp(maxBounds.height)); } else { - hints.set_max_height(XToolkit.getDefaultScreenHeight()); + hints.set_max_height(scaleUp(XToolkit.getDefaultScreenHeight())); } } else { // Leave intact @@ -723,7 +741,9 @@ height = Math.max(MIN_SIZE, height); XToolkit.awtLock(); try { - XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getWindow(), x,y,width,height); + XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getWindow(), + scaleUp(x), scaleUp(y), + scaleUp(width), scaleUp(height)); } finally { XToolkit.awtUnlock(); } @@ -756,7 +776,8 @@ rpt.x = x + srcPeer.getAbsoluteX(); rpt.y = y + srcPeer.getAbsoluteY(); } else { - rpt = XlibUtil.translateCoordinates(src, dst, new Point(x, y)); + int scale = srcPeer == null ? 1 : srcPeer.getScale(); + rpt = XlibUtil.translateCoordinates(src, dst, new Point(x, y), scale); } return rpt; } @@ -1042,10 +1063,11 @@ if (insLog.isLoggable(PlatformLogger.Level.FINER)) { insLog.finer("Configure, {0}", xe); } - x = xe.get_x(); - y = xe.get_y(); - width = xe.get_width(); - height = xe.get_height(); + + x = scaleDown(xe.get_x()); + y = scaleDown(xe.get_y()); + width = scaleDown(xe.get_width()); + height = scaleDown(xe.get_height()); } /** * Checks ButtonRelease released all Mouse buttons --- old/src/java.desktop/unix/classes/sun/awt/X11/XChoicePeer.java 2015-10-05 07:32:37.131038685 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XChoicePeer.java 2015-10-05 07:32:36.971038688 -0400 @@ -785,7 +785,7 @@ numItemsDisplayed = Math.min(MAX_UNFURLED_ITEMS, numItems); } Point global = XChoicePeer.this.toGlobal(0,0); - Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); + Rectangle screen = graphicsConfig.getBounds(); if (alignUnder != null) { Rectangle choiceRec = XChoicePeer.this.getBounds(); --- old/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java 2015-10-05 07:32:37.571038675 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java 2015-10-05 07:32:37.395038679 -0400 @@ -158,7 +158,9 @@ XComponentPeer newPeer = (XComponentPeer)newNativeParent; XToolkit.awtLock(); try { - XlibWrapper.XReparentWindow(XToolkit.getDisplay(), getWindow(), newPeer.getContentWindow(), x, y); + XlibWrapper.XReparentWindow(XToolkit.getDisplay(), + getWindow(), newPeer.getContentWindow(), + scaleUp(x), scaleUp(y)); parentWindow = newPeer; } finally { XToolkit.awtUnlock(); @@ -1394,6 +1396,12 @@ XToolkit.awtLock(); try { if (shape != null) { + + int scale = getScale(); + if (scale != 1) { + shape = shape.getScaledRegion(scale, scale); + } + XlibWrapper.SetRectangularShape( XToolkit.getDisplay(), getWindow(), --- old/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java 2015-10-05 07:32:37.915038668 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java 2015-10-05 07:32:37.799038670 -0400 @@ -737,16 +737,12 @@ updateChildrenSizes(); - // Bounds of the window - Rectangle targetBounds = AWTAccessor.getComponentAccessor().getBounds(target); - Point newLocation = getNewLocation(xe, currentInsets.left, currentInsets.top); - WindowDimensions newDimensions = new WindowDimensions(newLocation, - new Dimension(xe.get_width(), xe.get_height()), - copy(currentInsets), - true); + new Dimension(scaleDown(xe.get_width()), + scaleDown(xe.get_height())), + copy(currentInsets), true); if (insLog.isLoggable(PlatformLogger.Level.FINER)) { insLog.finer("Insets are {0}, new dimensions {1}", @@ -792,8 +788,10 @@ XToolkit.awtLock(); try { updateSizeHints(rec.x, rec.y, rec.width, rec.height); - XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height); - XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y); + XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), + scaleUp(rec.width), scaleUp(rec.height)); + XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), + scaleUp(rec.x), scaleUp(rec.y)); } finally { XToolkit.awtUnlock(); @@ -806,7 +804,8 @@ XToolkit.awtLock(); try { updateSizeHints(rec.x, rec.y, rec.width, rec.height); - XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height); + XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), + scaleUp(rec.width), scaleUp(rec.height)); } finally { XToolkit.awtUnlock(); @@ -819,7 +818,8 @@ XToolkit.awtLock(); try { updateSizeHints(rec.x, rec.y, rec.width, rec.height); - XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y); + XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), + scaleUp(rec.x), scaleUp(rec.y)); } finally { XToolkit.awtUnlock(); --- old/src/java.desktop/unix/classes/sun/awt/X11/XDragSourceContextPeer.java 2015-10-05 07:32:38.247038661 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XDragSourceContextPeer.java 2015-10-05 07:32:38.123038663 -0400 @@ -83,6 +83,8 @@ private long[] sourceFormats = null; /* The XID of the root subwindow that contains the current target. */ private long targetRootSubwindow = 0; + /* window scale factor */ + int windowScale = 1; /* The pointer location. */ private int xRoot = 0; private int yRoot = 0; @@ -130,8 +132,8 @@ long xcursor = 0; long rootWindow = 0; - long dragWindow = 0; long timeStamp = 0; + windowScale = wpeer.getScale(); /* Retrieve the X cursor for the drag operation. */ { @@ -156,8 +158,6 @@ rootWindow = XlibWrapper.RootWindow(XToolkit.getDisplay(), screen); } - dragWindow = XWindow.getXAWTRootWindow().getWindow(); - timeStamp = XToolkit.getCurrentServerTime(); int dropActions = getDragSourceContext().getSourceActions(); @@ -441,8 +441,8 @@ private void updateTargetWindow(XMotionEvent xmotion) { assert XToolkit.isAWTLockHeldByCurrentThread(); - int x = xmotion.get_x_root(); - int y = xmotion.get_y_root(); + int x = scaleDown(xmotion.get_x_root()); + int y = scaleDown(xmotion.get_y_root()); long time = xmotion.get_time(); long subwindow = xmotion.get_subwindow(); @@ -498,9 +498,13 @@ if (!dragInProgress) { return; } - if (xRoot != xmotion.get_x_root() || yRoot != xmotion.get_y_root()) { - xRoot = xmotion.get_x_root(); - yRoot = xmotion.get_y_root(); + + int motionXRoot = scaleDown(xmotion.get_x_root()); + int motionYRoot = scaleDown(xmotion.get_y_root()); + + if (xRoot != motionXRoot || yRoot != motionYRoot) { + xRoot = motionXRoot; + yRoot = motionYRoot; postDragSourceDragEvent(targetAction, XWindow.getModifiers(xmotion.get_state(),0,0), @@ -519,8 +523,8 @@ updateTargetWindow(xmotion); if (dragProtocol != null) { - dragProtocol.sendMoveMessage(xmotion.get_x_root(), - xmotion.get_y_root(), + dragProtocol.sendMoveMessage(scaleDown(xmotion.get_x_root()), + scaleDown(xmotion.get_y_root()), sourceAction, sourceActions, xmotion.get_time()); } @@ -528,8 +532,8 @@ private void processDrop(XButtonEvent xbutton) { try { - dragProtocol.initiateDrop(xbutton.get_x_root(), - xbutton.get_y_root(), + dragProtocol.initiateDrop(scaleDown(xbutton.get_x_root()), + scaleDown(xbutton.get_y_root()), sourceAction, sourceActions, xbutton.get_time()); } catch (XException e) { @@ -805,4 +809,12 @@ dndInProgress = false; cleanup(XConstants.CurrentTime); } + + public int scaleUp(int x) { + return x * windowScale; + } + + public int scaleDown(int x) { + return x / windowScale; + } } --- old/src/java.desktop/unix/classes/sun/awt/X11/XEmbedClientHelper.java 2015-10-05 07:32:38.671038651 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XEmbedClientHelper.java 2015-10-05 07:32:38.471038656 -0400 @@ -182,7 +182,7 @@ embedded.notifyStopped(); // check if newParent is a root window X11GraphicsConfig gc = (X11GraphicsConfig)embedded.getGraphicsConfiguration(); - X11GraphicsDevice gd = (X11GraphicsDevice)gc.getDevice(); + X11GraphicsDevice gd = gc.getDevice(); if ((newParent == XlibUtil.getRootWindow(gd.getScreen())) || (newParent == XToolkit.getDefaultRootWindow())) { --- old/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java 2015-10-05 07:32:39.039038643 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java 2015-10-05 07:32:38.923038646 -0400 @@ -146,18 +146,18 @@ // fix for 5063031 // if we use super.handleConfigureNotifyEvent() we would get wrong // size and position because embedded frame really is NOT a decorated one - checkIfOnNewScreen(toGlobal(new Rectangle(xe.get_x(), - xe.get_y(), - xe.get_width(), - xe.get_height()))); + checkIfOnNewScreen(toGlobal(new Rectangle(scaleDown(xe.get_x()), + scaleDown(xe.get_y()), + scaleDown(xe.get_width()), + scaleDown(xe.get_height())))); Rectangle oldBounds = getBounds(); synchronized (getStateLock()) { - x = xe.get_x(); - y = xe.get_y(); - width = xe.get_width(); - height = xe.get_height(); + x = scaleDown(xe.get_x()); + y = scaleDown(xe.get_y()); + width = scaleDown(xe.get_width()); + height = scaleDown(xe.get_height()); dimensions.setClientSize(width, height); dimensions.setLocation(x, y); @@ -215,10 +215,10 @@ try { XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), getWindow(), attr.pData); - x = attr.get_x(); - y = attr.get_y(); - w = attr.get_width(); - h = attr.get_height(); + x = scaleDown(attr.get_x()); + y = scaleDown(attr.get_y()); + w = scaleDown(attr.get_width()); + h = scaleDown(attr.get_height()); } finally { XToolkit.awtUnlock(); } @@ -276,7 +276,7 @@ { Point absoluteLoc = XlibUtil.translateCoordinates(getWindow(), XToolkit.getDefaultRootWindow(), - new Point(0, 0)); + new Point(0, 0), getScale()); return absoluteLoc != null ? absoluteLoc.x : 0; } @@ -284,7 +284,7 @@ { Point absoluteLoc = XlibUtil.translateCoordinates(getWindow(), XToolkit.getDefaultRootWindow(), - new Point(0, 0)); + new Point(0, 0), getScale()); return absoluteLoc != null ? absoluteLoc.y : 0; } --- old/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java 2015-10-05 07:32:39.451038634 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java 2015-10-05 07:32:39.331038637 -0400 @@ -296,7 +296,7 @@ */ protected Rectangle getSubmenuBounds(Rectangle itemBounds, Dimension windowSize) { Rectangle globalBounds = toGlobal(itemBounds); - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension screenSize = graphicsConfig.getBounds().getSize(); Rectangle res; res = fitWindowBelow(globalBounds, windowSize, screenSize); if (res != null) { --- old/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java 2015-10-05 07:32:39.843038626 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java 2015-10-05 07:32:39.651038630 -0400 @@ -278,7 +278,7 @@ */ protected Rectangle getSubmenuBounds(Rectangle itemBounds, Dimension windowSize) { Rectangle globalBounds = toGlobal(itemBounds); - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension screenSize = graphicsConfig.getBounds().getSize(); Rectangle res; res = fitWindowRight(globalBounds, windowSize, screenSize); if (res != null) { --- old/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java 2015-10-05 07:32:40.291038616 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java 2015-10-05 07:32:40.167038619 -0400 @@ -30,6 +30,7 @@ import java.awt.GraphicsEnvironment; import java.awt.GraphicsDevice; import java.awt.peer.MouseInfoPeer; +import sun.awt.X11GraphicsDevice; import sun.awt.AWTAccessor; @@ -64,6 +65,12 @@ if (pointerFound) { point.x = Native.getInt(XlibWrapper.larg3); point.y = Native.getInt(XlibWrapper.larg4); + GraphicsDevice device = gds[i]; + if (device instanceof X11GraphicsDevice) { + int scale = ((X11GraphicsDevice) device).getScaleFactor(); + point.x /= scale; + point.y /= scale; + } return i; } } --- old/src/java.desktop/unix/classes/sun/awt/X11/XPopupMenuPeer.java 2015-10-05 07:32:40.807038605 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XPopupMenuPeer.java 2015-10-05 07:32:40.655038608 -0400 @@ -215,7 +215,7 @@ */ protected Rectangle getWindowBounds(Point origin, Dimension windowSize) { Rectangle globalBounds = new Rectangle(origin.x, origin.y, 0, 0); - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension screenSize = graphicsConfig.getBounds().getSize(); Rectangle res; res = fitWindowRight(globalBounds, windowSize, screenSize); if (res != null) { --- old/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java 2015-10-05 07:32:41.179038597 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java 2015-10-05 07:32:41.007038600 -0400 @@ -64,7 +64,7 @@ @Override public void mouseMove(int x, int y) { - mouseMoveImpl(xgc, x, y); + mouseMoveImpl(xgc, xgc.scaleUp(x), xgc.scaleUp(y)); } @Override @@ -95,7 +95,8 @@ @Override public int getRGBPixel(int x, int y) { int pixelArray[] = new int[1]; - getRGBPixelsImpl(xgc, x, y, 1, 1, pixelArray, isGtkSupported); + getRGBPixelsImpl(xgc, x, y, 1, 1, xgc.getScale(), pixelArray, + isGtkSupported); return pixelArray[0]; } @@ -103,7 +104,7 @@ public int [] getRGBPixels(Rectangle bounds) { int pixelArray[] = new int[bounds.width*bounds.height]; getRGBPixelsImpl(xgc, bounds.x, bounds.y, bounds.width, bounds.height, - pixelArray, isGtkSupported); + xgc.getScale(), pixelArray, isGtkSupported); return pixelArray; } @@ -118,5 +119,6 @@ private static synchronized native void keyReleaseImpl(int keycode); private static synchronized native void getRGBPixelsImpl(X11GraphicsConfig xgc, - int x, int y, int width, int height, int pixelArray[], boolean isGtkSupported); + int x, int y, int width, int height, int scale, + int pixelArray[], boolean isGtkSupported); } --- old/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java 2015-10-05 07:32:41.591038588 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java 2015-10-05 07:32:41.431038591 -0400 @@ -422,7 +422,7 @@ } } - private void processGlobalMotionEvent(XEvent e) { + private void processGlobalMotionEvent(XEvent e, XBaseWindow win) { // Only our windows guaranteely generate MotionNotify, so we // should track enter/leave, to catch the moment when to // switch to XQueryPointer @@ -431,9 +431,11 @@ awtLock(); try { if (lastCursorPos == null) { - lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root()); + lastCursorPos = new Point(win.scaleDown(ev.get_x_root()), + win.scaleDown(ev.get_y_root())); } else { - lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root()); + lastCursorPos.setLocation(win.scaleDown(ev.get_x_root()), + win.scaleDown(ev.get_y_root())); } } finally { awtUnlock(); @@ -452,9 +454,11 @@ awtLock(); try { if (lastCursorPos == null) { - lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root()); + lastCursorPos = new Point(win.scaleDown(ev.get_x_root()), + win.scaleDown(ev.get_y_root())); } else { - lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root()); + lastCursorPos.setLocation(win.scaleDown(ev.get_x_root()), + win.scaleDown(ev.get_y_root())); } } finally { awtUnlock(); @@ -492,10 +496,11 @@ private void dispatchEvent(XEvent ev) { final XAnyEvent xany = ev.get_xany(); - if (windowToXWindow(xany.get_window()) != null && - (ev.get_type() == XConstants.MotionNotify || ev.get_type() == XConstants.EnterNotify || ev.get_type() == XConstants.LeaveNotify)) - { - processGlobalMotionEvent(ev); + XBaseWindow baseWindow = windowToXWindow(xany.get_window()); + if (baseWindow != null && (ev.get_type() == XConstants.MotionNotify + || ev.get_type() == XConstants.EnterNotify + || ev.get_type() == XConstants.LeaveNotify)) { + processGlobalMotionEvent(ev, baseWindow); } if( ev.get_type() == XConstants.MappingNotify ) { @@ -701,7 +706,7 @@ return getDefaultScreenHeight(); } - private static Rectangle getWorkArea(long root) + private static Rectangle getWorkArea(long root, int scale) { XAtom XA_NET_WORKAREA = XAtom.get("_NET_WORKAREA"); @@ -717,7 +722,8 @@ int rootWidth = (int)Native.getLong(native_ptr, 2); int rootHeight = (int)Native.getLong(native_ptr, 3); - return new Rectangle(rootX, rootY, rootWidth, rootHeight); + return new Rectangle(rootX / scale, rootY / scale, + rootWidth / scale, rootHeight / scale); } } finally @@ -750,15 +756,16 @@ try { X11GraphicsConfig x11gc = (X11GraphicsConfig)gc; - X11GraphicsDevice x11gd = (X11GraphicsDevice)x11gc.getDevice(); + X11GraphicsDevice x11gd = x11gc.getDevice(); long root = XlibUtil.getRootWindow(x11gd.getScreen()); - Rectangle rootBounds = XlibUtil.getWindowGeometry(root); + int scale = x11gc.getScale(); + Rectangle rootBounds = XlibUtil.getWindowGeometry(root, scale); X11GraphicsEnvironment x11ge = (X11GraphicsEnvironment) GraphicsEnvironment.getLocalGraphicsEnvironment(); if (!x11ge.runningXinerama()) { - Rectangle workArea = XToolkit.getWorkArea(root); + Rectangle workArea = XToolkit.getWorkArea(root, scale); if (workArea != null) { return new Insets(workArea.y, @@ -768,7 +775,7 @@ } } - return getScreenInsetsManually(root, rootBounds, gc.getBounds()); + return getScreenInsetsManually(root, rootBounds, gc.getBounds(), scale); } finally { @@ -783,7 +790,8 @@ * * This method should be called under XToolkit.awtLock() */ - private Insets getScreenInsetsManually(long root, Rectangle rootBounds, Rectangle screenBounds) + private Insets getScreenInsetsManually(long root, Rectangle rootBounds, + Rectangle screenBounds, int scale) { /* * During the manual calculation of screen insets we iterate @@ -831,20 +839,23 @@ if (strutPresent) { // second, verify that window is located on the proper screen - Rectangle windowBounds = XlibUtil.getWindowGeometry(window); + Rectangle windowBounds = XlibUtil.getWindowGeometry(window, + scale); if (windowLevel > 1) { - windowBounds = XlibUtil.translateCoordinates(window, root, windowBounds); + windowBounds = XlibUtil.translateCoordinates(window, root, + windowBounds, + scale); } // if _NET_WM_STRUT_PARTIAL is present, we should use its values to detect // if the struts area intersects with screenBounds, however some window // managers don't set this hint correctly, so we just get intersection with windowBounds if (windowBounds != null && windowBounds.intersects(screenBounds)) { - int left = (int)Native.getLong(native_ptr, 0); - int right = (int)Native.getLong(native_ptr, 1); - int top = (int)Native.getLong(native_ptr, 2); - int bottom = (int)Native.getLong(native_ptr, 3); + int left = (int)Native.getLong(native_ptr, 0) / scale; + int right = (int)Native.getLong(native_ptr, 1) / scale; + int top = (int)Native.getLong(native_ptr, 2) / scale; + int bottom = (int)Native.getLong(native_ptr, 3) / scale; /* * struts could be relative to root window bounds, so @@ -2487,7 +2498,8 @@ oops_updated = false; long event_number = getEventNumber(); // Generate OOPS ConfigureNotify event - XlibWrapper.XMoveWindow(getDisplay(), win.getWindow(), ++oops_position, 0); + XlibWrapper.XMoveWindow(getDisplay(), win.getWindow(), + win.scaleUp(++oops_position), 0); // Change win position each time to avoid system optimization if (oops_position > 50) { oops_position = 0; --- old/src/java.desktop/unix/classes/sun/awt/X11/XWM.java 2015-10-05 07:32:42.027038578 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XWM.java 2015-10-05 07:32:41.903038581 -0400 @@ -1024,8 +1024,12 @@ shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top); window.updateSizeHints(window.getDimensions()); requestWMExtents(window.getWindow()); - XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(), - shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height); + XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), + window.getShell(), + window.scaleUp(shellBounds.x), + window.scaleUp(shellBounds.y), + window.scaleUp(shellBounds.width), + window.scaleUp(shellBounds.height)); /* REMINDER: will need to revisit when setExtendedStateBounds is added */ //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced. //We need to update frame's minimum size, not to reset it @@ -1058,8 +1062,12 @@ window.updateSizeHints(newDimensions); requestWMExtents(window.getWindow()); XToolkit.XSync(); - XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(), - shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height); + XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), + window.getShell(), + window.scaleUp(shellBounds.x), + window.scaleUp(shellBounds.y), + window.scaleUp(shellBounds.width), + window.scaleUp(shellBounds.height)); } if (!justChangeSize) { /* update decorations */ setShellDecor(window); @@ -1701,6 +1709,12 @@ pattr.dispose(); } } + + correctWM.top = win.scaleUp(correctWM.top); + correctWM.bottom = win.scaleUp(correctWM.bottom); + correctWM.left = win.scaleUp(correctWM.left); + correctWM.right = win.scaleUp(correctWM.right); + if (storedInsets.get(win.getClass()) == null) { storedInsets.put(win.getClass(), correctWM); } --- old/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java 2015-10-05 07:32:42.491038568 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java 2015-10-05 07:32:42.371038571 -0400 @@ -258,10 +258,10 @@ super.handleExposeEvent(xev); XExposeEvent xe = xev.get_xexpose(); - final int x = xe.get_x(); - final int y = xe.get_y(); - final int width = xe.get_width(); - final int height = xe.get_height(); + final int x = scaleDown(xe.get_x()); + final int y = scaleDown(xe.get_y()); + final int width = scaleDown(xe.get_width()); + final int height = scaleDown(xe.get_height()); SunToolkit.executeOnEventHandlerThread(target, new Runnable() { public void run() { --- old/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java 2015-10-05 07:32:43.007038557 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java 2015-10-05 07:32:42.683038564 -0400 @@ -547,10 +547,11 @@ if (isEventDisabled(xev)) { return; } - int x = xe.get_x(); - int y = xe.get_y(); - int w = xe.get_width(); - int h = xe.get_height(); + + int x = scaleDown(xe.get_x()); + int y = scaleDown(xe.get_y()); + int w = scaleDown(xe.get_width()); + int h = scaleDown(xe.get_height()); Component target = getEventSource(); ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); @@ -675,10 +676,11 @@ when = xbe.get_time(); long jWhen = XToolkit.nowMillisUTC_offset(when); - int x = xbe.get_x(); - int y = xbe.get_y(); + int x = scaleDown(xbe.get_x()); + int y = scaleDown(xbe.get_y()); if (xev.get_xany().get_window() != window) { - Point localXY = toLocal(xbe.get_x_root(), xbe.get_y_root()); + Point localXY = toLocal(scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root())); x = localXY.x; y = localXY.y; } @@ -729,8 +731,8 @@ MouseEvent me = new MouseEvent(getEventSource(), type == XConstants.ButtonPress ? MouseEvent.MOUSE_PRESSED : MouseEvent.MOUSE_RELEASED, jWhen,modifiers, x, y, - xbe.get_x_root(), - xbe.get_y_root(), + scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root()), clickCount,popupTrigger,button); postEventToEventQueue(me); @@ -743,8 +745,8 @@ jWhen, modifiers, x, y, - xbe.get_x_root(), - xbe.get_y_root(), + scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root()), clickCount, false, button)); } @@ -756,8 +758,8 @@ MouseWheelEvent mwe = new MouseWheelEvent(getEventSource(),MouseEvent.MOUSE_WHEEL, jWhen, modifiers, x, y, - xbe.get_x_root(), - xbe.get_y_root(), + scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root()), 1,false,MouseWheelEvent.WHEEL_UNIT_SCROLL, 3,button==4 ? -1 : 1); postEventToEventQueue(mwe); @@ -804,8 +806,8 @@ /* Fix for 6176814 . Add multiclick checking. */ - int x = xme.get_x(); - int y = xme.get_y(); + int x = scaleDown(xme.get_x()); + int y = scaleDown(xme.get_y()); XWindow lastWindow = (lastWindowRef != null) ? (lastWindowRef.get()):(null); if (!(lastWindow == this && @@ -827,7 +829,8 @@ Component source = getEventSource(); if (xme.get_window() != window) { - Point localXY = toLocal(xme.get_x_root(), xme.get_y_root()); + Point localXY = toLocal(scaleDown(xme.get_x_root()), + scaleDown(xme.get_y_root())); x = localXY.x; y = localXY.y; } @@ -836,7 +839,9 @@ */ if ((isDragging && clickCount == 0) || !isDragging) { MouseEvent mme = new MouseEvent(source, mouseEventType, jWhen, - modifiers, x, y, xme.get_x_root(), xme.get_y_root(), + modifiers, x, y, + scaleDown(xme.get_x_root()), + scaleDown(xme.get_y_root()), clickCount, popupTrigger, MouseEvent.NOBUTTON); postEventToEventQueue(mme); } @@ -948,10 +953,11 @@ int modifiers = getModifiers(xce.get_state(),0,0); int clickCount = 0; boolean popupTrigger = false; - int x = xce.get_x(); - int y = xce.get_y(); + int x = scaleDown(xce.get_x()); + int y = scaleDown(xce.get_y()); if (xce.get_window() != window) { - Point localXY = toLocal(xce.get_x_root(), xce.get_y_root()); + Point localXY = toLocal(scaleDown(xce.get_x_root()), + scaleDown(xce.get_y_root())); x = localXY.x; y = localXY.y; } @@ -959,18 +965,27 @@ // This code tracks boundary crossing and ensures MOUSE_ENTER/EXIT // are posted in alternate pairs if (compWithMouse != null) { - MouseEvent me = new MouseEvent(compWithMouse, - MouseEvent.MOUSE_EXITED, jWhen, modifiers, xce.get_x(), - xce.get_y(), xce.get_x_root(), xce.get_y_root(), clickCount, popupTrigger, - MouseEvent.NOBUTTON); + MouseEvent me = new MouseEvent(compWithMouse, MouseEvent.MOUSE_EXITED, + jWhen, modifiers, + scaleDown(xce.get_x()), + scaleDown(xce.get_y()), + scaleDown(xce.get_x_root()), + scaleDown(xce.get_y_root()), + clickCount, popupTrigger, + MouseEvent.NOBUTTON); postEventToEventQueue(me); eventLog.finest("Clearing last window ref"); lastWindowRef = null; } if (xce.get_type() == XConstants.EnterNotify) { MouseEvent me = new MouseEvent(getEventSource(), MouseEvent.MOUSE_ENTERED, - jWhen, modifiers, xce.get_x(), xce.get_y(), xce.get_x_root(), xce.get_y_root(), clickCount, - popupTrigger, MouseEvent.NOBUTTON); + jWhen, modifiers, + scaleDown(xce.get_x()), + scaleDown(xce.get_y()), + scaleDown(xce.get_x_root()), + scaleDown(xce.get_y_root()), + clickCount, popupTrigger, + MouseEvent.NOBUTTON); postEventToEventQueue(me); } } @@ -1527,4 +1542,18 @@ } } + @Override + protected int getScale() { + return graphicsConfig.getScale(); + } + + @Override + protected int scaleUp(int x) { + return graphicsConfig.scaleUp(x); + } + + @Override + protected int scaleDown(int x) { + return graphicsConfig.scaleDown(x); + } } --- old/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java 2015-10-05 07:32:43.767038540 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java 2015-10-05 07:32:43.523038545 -0400 @@ -29,6 +29,7 @@ import java.awt.event.ComponentEvent; import java.awt.event.FocusEvent; import java.awt.event.WindowEvent; +import java.awt.geom.AffineTransform; import java.awt.peer.ComponentPeer; import java.awt.peer.WindowPeer; @@ -750,10 +751,10 @@ private Point queryXLocation() { - return XlibUtil.translateCoordinates( - getContentWindow(), - XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()), - new Point(0, 0)); + return XlibUtil.translateCoordinates(getContentWindow(), XlibWrapper + .RootWindow(XToolkit.getDisplay(), + getScreenNumber()), + new Point(0, 0), getScale()); } protected Point getNewLocation(XConfigureEvent xe, int leftInset, int topInset) { @@ -764,7 +765,8 @@ Point newLocation = targetBounds.getLocation(); if (xe.get_send_event() || runningWM == XWM.NO_WM || XWM.isNonReparentingWM()) { // Location, Client size + insets - newLocation = new Point(xe.get_x() - leftInset, xe.get_y() - topInset); + newLocation = new Point(scaleDown(xe.get_x()) - leftInset, + scaleDown(xe.get_y()) - topInset); } else { // ICCCM 4.1.5 states that a real ConfigureNotify will be sent when // a window is resized but the client can not tell if the window was @@ -807,12 +809,12 @@ * See getNewLocation() for the details. */ Point newLocation = getNewLocation(xe, 0, 0); - xe.set_x(newLocation.x); - xe.set_y(newLocation.y); - checkIfOnNewScreen(new Rectangle(xe.get_x(), - xe.get_y(), - xe.get_width(), - xe.get_height())); + xe.set_x(scaleUp(newLocation.x)); + xe.set_y(scaleUp(newLocation.y)); + checkIfOnNewScreen(new Rectangle(newLocation.x, + newLocation.y, + scaleDown(xe.get_width()), + scaleDown(xe.get_height()))); // Don't call super until we've handled a screen change. Otherwise // there could be a race condition in which a ComponentListener could @@ -2115,7 +2117,9 @@ XCrossingEvent xce = xev.get_xcrossing(); if (grabLog.isLoggable(PlatformLogger.Level.FINE)) { grabLog.fine("{0}, when grabbed {1}, contains {2}", - xce, isGrabbed(), containsGlobal(xce.get_x_root(), xce.get_y_root())); + xce, isGrabbed(), + containsGlobal(scaleDown(xce.get_x_root()), + scaleDown(xce.get_y_root()))); } if (isGrabbed()) { // When window is grabbed, all events are dispatched to @@ -2141,7 +2145,9 @@ XMotionEvent xme = xev.get_xmotion(); if (grabLog.isLoggable(PlatformLogger.Level.FINER)) { grabLog.finer("{0}, when grabbed {1}, contains {2}", - xme, isGrabbed(), containsGlobal(xme.get_x_root(), xme.get_y_root())); + xme, isGrabbed(), + containsGlobal(scaleDown(xme.get_x_root()), + scaleDown(xme.get_y_root()))); } if (isGrabbed()) { boolean dragging = false; @@ -2166,9 +2172,10 @@ // So, I do not want to implement complicated logic for better retargeting. target = pressTarget.isVisible() ? pressTarget : this; xme.set_window(target.getWindow()); - Point localCoord = target.toLocal(xme.get_x_root(), xme.get_y_root()); - xme.set_x(localCoord.x); - xme.set_y(localCoord.y); + Point localCoord = target.toLocal(scaleDown(xme.get_x_root()), + scaleDown(xme.get_y_root())); + xme.set_x(scaleUp(localCoord.x)); + xme.set_y(scaleUp(localCoord.y)); } if (grabLog.isLoggable(PlatformLogger.Level.FINER)) { grabLog.finer(" - Grab event target {0}", target); @@ -2182,7 +2189,9 @@ // note that we need to pass dragging events to the grabber (6390326) // see comment above for more inforamtion. - if (!containsGlobal(xme.get_x_root(), xme.get_y_root()) && !dragging) { + if (!containsGlobal(scaleDown(xme.get_x_root()), + scaleDown(xme.get_y_root())) + && !dragging) { // Outside of Java return; } @@ -2195,7 +2204,6 @@ public void handleButtonPressRelease(XEvent xev) { XButtonEvent xbe = xev.get_xbutton(); - /* * Ignore the buttons above 20 due to the bit limit for * InputEvent.BUTTON_DOWN_MASK. @@ -2206,7 +2214,11 @@ } if (grabLog.isLoggable(PlatformLogger.Level.FINE)) { grabLog.fine("{0}, when grabbed {1}, contains {2} ({3}, {4}, {5}x{6})", - xbe, isGrabbed(), containsGlobal(xbe.get_x_root(), xbe.get_y_root()), getAbsoluteX(), getAbsoluteY(), getWidth(), getHeight()); + xbe, isGrabbed(), + containsGlobal(scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root())), + getAbsoluteX(), getAbsoluteY(), + getWidth(), getHeight()); } if (isGrabbed()) { // When window is grabbed, all events are dispatched to @@ -2232,9 +2244,10 @@ // see 6390326 for more information. target = pressTarget.isVisible() ? pressTarget : this; xbe.set_window(target.getWindow()); - Point localCoord = target.toLocal(xbe.get_x_root(), xbe.get_y_root()); - xbe.set_x(localCoord.x); - xbe.set_y(localCoord.y); + Point localCoord = target.toLocal(scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root())); + xbe.set_x(scaleUp(localCoord.x)); + xbe.set_y(scaleUp(localCoord.y)); pressTarget = this; } if (target != null && target != getContentXWindow() && target != this) { @@ -2246,7 +2259,10 @@ // Target is either us or our content window - // check that event is inside. 'Us' in case of // shell will mean that this will also filter out press on title - if ((target == this || target == getContentXWindow()) && !containsGlobal(xbe.get_x_root(), xbe.get_y_root())) { + if ((target == this || target == getContentXWindow()) + && !containsGlobal(scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root()))) + { // Outside this toplevel hierarchy // According to the specification of UngrabEvent, post it // when press occurs outside of the window and not on its owned windows --- old/src/java.desktop/unix/classes/sun/awt/X11/XlibUtil.java 2015-10-05 07:32:44.467038525 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XlibUtil.java 2015-10-05 07:32:44.215038530 -0400 @@ -102,7 +102,7 @@ /** * Returns the bounds of the given window, in absolute coordinates */ - static Rectangle getWindowGeometry(long window) + static Rectangle getWindowGeometry(long window, int scale) { XToolkit.awtLock(); try @@ -126,7 +126,9 @@ long width = Native.getUInt(XlibWrapper.larg4); long height = Native.getUInt(XlibWrapper.larg5); - return new Rectangle(x, y, (int)width, (int)height); + return new Rectangle(x / scale, y / scale, + (int) (width / scale), + (int) (height / scale)); } finally { @@ -138,7 +140,7 @@ * Translates the given point from one window to another. Returns * null if the translation is failed */ - static Point translateCoordinates(long src, long dst, Point p) + static Point translateCoordinates(long src, long dst, Point p, int scale) { Point translated = null; @@ -146,7 +148,7 @@ try { XTranslateCoordinates xtc = - new XTranslateCoordinates(src, dst, p.x, p.y); + new XTranslateCoordinates(src, dst, p.x * scale, p.y * scale); try { int status = xtc.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); @@ -154,7 +156,7 @@ ((XErrorHandlerUtil.saved_error == null) || (XErrorHandlerUtil.saved_error.get_error_code() == XConstants.Success))) { - translated = new Point(xtc.get_dest_x(), xtc.get_dest_y()); + translated = new Point(xtc.get_dest_x() / scale, xtc.get_dest_y() / scale); } } finally @@ -174,9 +176,12 @@ * Translates the given rectangle from one window to another. * Returns null if the translation is failed */ - static Rectangle translateCoordinates(long src, long dst, Rectangle r) + static Rectangle translateCoordinates(long src, long dst, Rectangle r, + int scale) { - Point translatedLoc = translateCoordinates(src, dst, r.getLocation()); + Point translatedLoc = translateCoordinates(src, dst, r.getLocation(), + scale); + if (translatedLoc == null) { return null; --- old/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java 2015-10-05 07:32:45.159038510 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java 2015-10-05 07:32:44.903038515 -0400 @@ -133,7 +133,7 @@ /** * Return the graphics device associated with this configuration. */ - public GraphicsDevice getDevice() { + public X11GraphicsDevice getDevice() { return screen; } @@ -256,7 +256,20 @@ * For image buffers, this Transform will be the Identity transform. */ public AffineTransform getDefaultTransform() { - return new AffineTransform(); + double scale = getScale(); + return AffineTransform.getScaleInstance(scale, scale); + } + + public int getScale() { + return getDevice().getScaleFactor(); + } + + public int scaleUp(int x) { + return x * getScale(); + } + + public int scaleDown(int x) { + return x / getScale(); } /** @@ -308,7 +321,14 @@ } public Rectangle getBounds() { - return pGetBounds(screen.getScreen()); + Rectangle rect = pGetBounds(screen.getScreen()); + if (getScale() != 1) { + rect.x = scaleDown(rect.x); + rect.y = scaleDown(rect.y); + rect.width = scaleDown(rect.width); + rect.height = scaleDown(rect.height); + } + return rect; } private native Rectangle pGetBounds(int screenNum); --- old/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java 2015-10-05 07:32:45.827038495 -0400 +++ new/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java 2015-10-05 07:32:45.575038501 -0400 @@ -44,6 +44,7 @@ import sun.awt.util.ThreadGroupUtils; import sun.misc.ManagedLocalsThread; +import sun.security.action.GetPropertyAction; /** * This is an implementation of a GraphicsDevice object for a single @@ -63,9 +64,11 @@ private SunDisplayChanger topLevels = new SunDisplayChanger(); private DisplayMode origDisplayMode; private boolean shutdownHookRegistered; + private int scale; public X11GraphicsDevice(int screennum) { this.screen = screennum; + this.scale = initScaleFactor(); } /* @@ -279,6 +282,7 @@ int width, int height, int displayMode); private static native void resetNativeData(int screen); + private static native int getNativeScaleFactor(int screen); /** * Returns true only if: @@ -509,6 +513,33 @@ topLevels.add(client); } + public int getScaleFactor(){ + return scale; + } + + private int initScaleFactor() { + + boolean hidpiEnabled = "true".equals(AccessController.doPrivileged( + new GetPropertyAction("sun.java2d.uiScale.enabled", "true"))); + + if (!hidpiEnabled) { + return 1; + } + + String hidpiScale = AccessController.doPrivileged( + new GetPropertyAction("sun.java2d.uiScale", "-1")); + try { + int scale = Integer.parseInt(hidpiScale); + if (scale >= 1) { + return scale; + } + } catch (NumberFormatException ignore) { + } + + int scale = getNativeScaleFactor(screen); + return scale >= 1 ? scale : 1; + } + /** * Remove a DisplayChangeListener from this X11GraphicsDevice. */ --- old/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java 2015-10-05 07:32:46.739038475 -0400 +++ new/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java 2015-10-05 07:32:46.507038480 -0400 @@ -244,7 +244,8 @@ int width, int height, ColorModel cm, Image image, long drawable, - int transparency) { + int transparency, + boolean isTexture) { int depth; // If we have a 32 bit color model for the window it needs // alpha to support translucency of the window so we need @@ -267,7 +268,7 @@ return new XRPixmapSurfaceData (gc, width, height, image, getSurfaceType(gc, transparency), cm, drawable, transparency, - XRUtils.getPictureFormatForTransparency(transparency), depth); + XRUtils.getPictureFormatForTransparency(transparency), depth, isTexture); } protected XRSurfaceData(X11ComponentPeer peer, XRGraphicsConfig gc, @@ -542,11 +543,16 @@ } public static class XRWindowSurfaceData extends XRSurfaceData { + + protected final int scale; + public XRWindowSurfaceData(X11ComponentPeer peer, XRGraphicsConfig gc, SurfaceType sType) { super(peer, gc, sType, peer.getColorModel(), peer.getColorModel().getPixelSize(), Transparency.OPAQUE); + this.scale = gc.getScale(); + if (isXRDrawableValid()) { // If we have a 32 bit color model for the window it needs // alpha to support translucency of the window so we need @@ -571,6 +577,8 @@ public Rectangle getBounds() { Rectangle r = peer.getBounds(); r.x = r.y = 0; + r.width *= scale; + r.height *= scale; return r; } @@ -596,6 +604,16 @@ super.invalidate(); } + + @Override + public double getDefaultScaleX() { + return scale; + } + + @Override + public double getDefaultScaleY() { + return scale; + } } public static class XRInternalSurfaceData extends XRSurfaceData { @@ -627,18 +645,20 @@ int width; int height; int transparency; + private final int scale; public XRPixmapSurfaceData(XRGraphicsConfig gc, int width, int height, Image image, SurfaceType sType, ColorModel cm, long drawable, int transparency, int pictFormat, - int depth) { + int depth, boolean isTexture) { super(null, gc, sType, cm, depth, transparency); - this.width = width; - this.height = height; + this.scale = isTexture ? 1 : gc.getDevice().getScaleFactor(); + this.width = width * scale; + this.height = height * scale; offscreenImage = image; this.transparency = transparency; - initSurface(depth, width, height, drawable, pictFormat); + initSurface(depth, this.width, this.height, drawable, pictFormat); initXRender(pictFormat); makePipes(); @@ -696,6 +716,16 @@ public Object getDestination() { return offscreenImage; } + + @Override + public double getDefaultScaleX() { + return scale; + } + + @Override + public double getDefaultScaleY() { + return scale; + } } public long getGC() { --- old/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceDataProxy.java 2015-10-05 07:32:47.615038456 -0400 +++ new/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceDataProxy.java 2015-10-05 07:32:47.243038464 -0400 @@ -59,8 +59,9 @@ public SurfaceData validateSurfaceData(SurfaceData srcData, SurfaceData cachedData, int w, int h) { if (cachedData == null) { - cachedData = XRSurfaceData.createData(xrgc, w, h, xrgc - .getColorModel(), null, 0, getTransparency()); + cachedData = XRSurfaceData.createData(xrgc, w, h, + xrgc.getColorModel(), null, 0, + getTransparency(), true); } return cachedData; } --- old/src/java.desktop/unix/classes/sun/java2d/xr/XRVolatileSurfaceManager.java 2015-10-05 07:32:48.803038430 -0400 +++ new/src/java.desktop/unix/classes/sun/java2d/xr/XRVolatileSurfaceManager.java 2015-10-05 07:32:48.335038441 -0400 @@ -59,10 +59,10 @@ drawable = ((Long)context).longValue(); } sData = XRSurfaceData.createData(gc, - vImg.getWidth(), - vImg.getHeight(), - cm, vImg, drawable, - vImg.getTransparency()); + vImg.getWidth(), + vImg.getHeight(), + cm, vImg, drawable, + vImg.getTransparency(), false); } catch (NullPointerException ex) { sData = null; } catch (OutOfMemoryError er) { --- old/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c 2015-10-05 07:32:49.963038405 -0400 +++ new/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c 2015-10-05 07:32:49.583038413 -0400 @@ -51,6 +51,7 @@ #include "gdefs.h" #include #include "Trace.h" +#include #ifdef NETSCAPE #include @@ -2082,3 +2083,35 @@ /** * End DisplayMode/FullScreen support */ + +/* + * Class: sun_awt_X11GraphicsDevice + * Method: getNativeScaleFactor + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_sun_awt_X11GraphicsDevice_getNativeScaleFactor + (JNIEnv *env, jobject this, jint screen) { + + // for debug purposes + char *uiScale = getenv("J2D_WIN_UISCALE"); + + if (uiScale != NULL) { + double scale = strtod(uiScale, NULL); + if (errno != ERANGE && scale >= 1) { + return (int) ceil(scale); + } + } + + uiScale = getenv("GDK_SCALE"); + + if (uiScale != NULL) { + double scale = strtod(uiScale, NULL); + if (errno != ERANGE && scale >= 1) { + return (int) ceil(scale); + } + } + + return 1; +} + --- old/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c 2015-10-05 07:32:50.679038389 -0400 +++ new/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c 2015-10-05 07:32:50.423038395 -0400 @@ -210,6 +210,7 @@ jint jy, jint jwidth, jint jheight, + jint scale, jintArray pixelArray, jboolean isGtkSupported) { XImage *image; @@ -230,14 +231,19 @@ DASSERT(adata != NULL); AWT_LOCK(); + + jint sx = jx * scale; + jint sy = jy * scale; + jint swidth = jwidth * scale; + jint sheight = jheight * scale; rootWindow = XRootWindow(awt_display, adata->awt_visInfo.screen); if (!XGetWindowAttributes(awt_display, rootWindow, &attr) - || jx + jwidth <= attr.x - || attr.x + attr.width <= jx - || jy + jheight <= attr.y - || attr.y + attr.height <= jy) { + || sx + swidth <= attr.x + || attr.x + attr.width <= sx + || sy + sheight <= attr.y + || attr.y + attr.height <= sy) { AWT_UNLOCK(); return; // Does not intersect with root window @@ -246,14 +252,14 @@ gboolean gtk_failed = TRUE; jint _x, _y; - jint x = MAX(jx, attr.x); - jint y = MAX(jy, attr.y); - jint width = MIN(jx + jwidth, attr.x + attr.width) - x; - jint height = MIN(jy + jheight, attr.y + attr.height) - y; + jint x = MAX(sx, attr.x); + jint y = MAX(sy, attr.y); + jint width = MIN(sx + swidth, attr.x + attr.width) - x; + jint height = MIN(sy + sheight, attr.y + attr.height) - y; - int dx = attr.x > jx ? attr.x - jx : 0; - int dy = attr.y > jy ? attr.y - jy : 0; + int dx = attr.x > sx ? attr.x - sx : 0; + int dy = attr.y > sy ? attr.y - sy : 0; int index; @@ -264,7 +270,16 @@ pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(NULL, root, NULL, x, y, 0, 0, width, height); - + if (pixbuf && scale != 1) { + x /= scale; + y /= scale; + width /= scale; + height /= scale; + dx /= scale; + dy /= scale; + pixbuf = (*fp_gdk_pixbuf_scale_simple)(pixbuf, width, height, GDK_INTERP_BILINEAR); + } + if (pixbuf) { int nchan = (*fp_gdk_pixbuf_get_n_channels)(pixbuf); int stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf); @@ -276,7 +291,7 @@ && nchan >= 3 ) { guchar *p, *pix = (*fp_gdk_pixbuf_get_pixels)(pixbuf); - + ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL); if (!ary) { (*fp_g_object_unref)(pixbuf); @@ -312,7 +327,7 @@ } if (gtk_failed) { - image = getWindowImage(awt_display, rootWindow, x, y, width, height); + image = getWindowImage(awt_display, rootWindow, sx, sy, swidth, sheight); ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL); @@ -322,10 +337,16 @@ return; } + dx /= scale; + dy /= scale; + width /= scale; + height /= scale; + /* convert to Java ARGB pixels */ for (_y = 0; _y < height; _y++) { for (_x = 0; _x < width; _x++) { - jint pixel = (jint) XGetPixel(image, _x, _y); /* Note ignore upper + jint pixel = (jint) XGetPixel(image, _x * scale, _y * scale); + /* Note ignore upper * 32-bits on 64-bit * OSes. */ --- old/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c 2015-10-05 07:32:51.447038373 -0400 +++ new/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c 2015-10-05 07:32:51.167038379 -0400 @@ -648,6 +648,8 @@ fp_gdk_pixmap_new = dl_symbol("gdk_pixmap_new"); fp_gdk_pixbuf_get_from_drawable = dl_symbol("gdk_pixbuf_get_from_drawable"); + fp_gdk_pixbuf_scale_simple = + dl_symbol("gdk_pixbuf_scale_simple"); fp_gdk_gc_new = dl_symbol("gdk_gc_new"); fp_gdk_rgb_gc_set_foreground = dl_symbol("gdk_rgb_gc_set_foreground"); --- old/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h 2015-10-05 07:32:52.119038358 -0400 +++ new/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h 2015-10-05 07:32:51.883038363 -0400 @@ -270,6 +270,13 @@ G_PARAM_PRIVATE = 1 << 5 } GParamFlags; +typedef enum { + GDK_INTERP_NEAREST, + GDK_INTERP_TILES, + GDK_INTERP_BILINEAR, + GDK_INTERP_HYPER +} GdkInterpType; + /* We define all structure pointers to be void* */ typedef void GError; typedef void GMainContext; @@ -787,6 +794,8 @@ GdkPixbuf *(*fp_gdk_pixbuf_get_from_drawable)(GdkPixbuf *dest, GdkDrawable *src, GdkColormap *cmap, int src_x, int src_y, int dest_x, int dest_y, int width, int height); +GdkPixbuf *(*fp_gdk_pixbuf_scale_simple)(GdkPixbuf *src, + int dest_width, int dest_heigh, GdkInterpType interp_type); void (*fp_gtk_widget_destroy)(GtkWidget *widget); --- /dev/null 2015-10-05 05:39:31.281027740 -0400 +++ new/test/java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java 2015-10-05 07:32:52.571038348 -0400 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015, 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.Frame; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.UIManager; + +/* @test + * @bug 8073320 8137571 + * @summary Windows and Linux HiDPI Graphics support + * @author Alexander Scherbatiy + * @requires (os.family == "windows" | os.family == "linux") + * @run main/othervm -Dsun.java2d.uiScale=2 HiDPIRobotMouseClick + */ +public class HiDPIRobotMouseClick { + + private static final String[] SUPPORTED_LAFS = { + "com.sun.java.swing.plaf.windows.WindowsLookAndFeel", + "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" + }; + + private static volatile int mouseX; + private static volatile int mouseY; + + public static void main(String[] args) throws Exception { + + if (!setSupportedLAF()) { + return; + } + + Frame frame = new Frame(); + frame.setBounds(30, 20, 400, 300); + frame.setUndecorated(true); + + frame.addMouseListener(new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + mouseX = e.getXOnScreen(); + mouseY = e.getYOnScreen(); + } + }); + + frame.setVisible(true); + + Robot robot = new Robot(); + robot.waitForIdle(); + Thread.sleep(200); + + Rectangle rect = frame.getBounds(); + rect.setLocation(frame.getLocationOnScreen()); + + int x = (int) rect.getCenterX(); + int y = (int) rect.getCenterY(); + + robot.mouseMove(x, y); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + + if (x != mouseX || y != mouseY) { + throw new RuntimeException("Wrong mouse click point!"); + } + } + + private static boolean setSupportedLAF() { + + for (String supportedLAF : SUPPORTED_LAFS) { + try { + UIManager.setLookAndFeel(supportedLAF); + return true; + } catch (Exception ignored) { + } + } + + return false; + } +} \ No newline at end of file --- /dev/null 2015-10-05 05:39:31.281027740 -0400 +++ new/test/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java 2015-10-05 07:32:53.175038335 -0400 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015, 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.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; +import javax.swing.UIManager; + +/* @test + * @bug 8073320 8137571 + * @summary Windows and Linux HiDPI Graphics support + * @author Alexander Scherbatiy + * @requires (os.family == "windows" | os.family == "linux") + * @run main/othervm -Dsun.java2d.uiScale=2 HiDPIRobotScreenCaptureTest + */ +public class HiDPIRobotScreenCaptureTest { + + private static final Color[] COLORS = { + Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED}; + + private static final String[] SUPPORTED_LAFS = { + "com.sun.java.swing.plaf.windows.WindowsLookAndFeel", + "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" + }; + + public static void main(String[] args) throws Exception { + + if (!setSupportedLAF()) { + return; + } + + Frame frame = new Frame(); + frame.setBounds(10, 20, 200, 150); + frame.setUndecorated(true); + + Panel panel = new Panel(new BorderLayout()); + Canvas canvas = new Canvas() { + @Override + public void paint(Graphics g) { + super.paint(g); + int w = getWidth(); + int h = getHeight(); + g.setColor(COLORS[0]); + g.fillRect(0, 0, w / 2, h / 2); + g.setColor(COLORS[1]); + g.fillRect(w / 2, 0, w / 2, h / 2); + g.setColor(COLORS[2]); + g.fillRect(0, h / 2, w / 2, h / 2); + g.setColor(COLORS[3]); + g.fillRect(w / 2, h / 2, w / 2, h / 2); + } + }; + + panel.add(canvas); + frame.add(panel); + frame.setVisible(true); + Robot robot = new Robot(); + robot.waitForIdle(); + Thread.sleep(200); + + Rectangle rect = canvas.getBounds(); + rect.setLocation(canvas.getLocationOnScreen()); + + BufferedImage image = robot.createScreenCapture(rect); + frame.dispose(); + + int w = image.getWidth(); + int h = image.getHeight(); + + if (w != frame.getWidth() || h != frame.getHeight()) { + throw new RuntimeException("Wrong image size!"); + } + + if (image.getRGB(w / 4, h / 4) != COLORS[0].getRGB()) { + throw new RuntimeException("Wrong image color!"); + } + + if (image.getRGB(3 * w / 4, h / 4) != COLORS[1].getRGB()) { + throw new RuntimeException("Wrong image color!"); + } + + if (image.getRGB(w / 4, 3 * h / 4) != COLORS[2].getRGB()) { + throw new RuntimeException("Wrong image color!"); + } + + if (image.getRGB(3 * w / 4, 3 * h / 4) != COLORS[3].getRGB()) { + throw new RuntimeException("Wrong image color!"); + } + } + + private static boolean setSupportedLAF() { + + for (String supportedLAF : SUPPORTED_LAFS) { + try { + UIManager.setLookAndFeel(supportedLAF); + return true; + } catch (Exception ignored) { + } + } + + return false; + } +} \ No newline at end of file --- /dev/null 2015-10-05 05:39:31.281027740 -0400 +++ new/test/java/awt/hidpi/properties/HiDPIPropertiesLinuxTest.java 2015-10-05 07:32:53.799038321 -0400 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, 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.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import javax.swing.UIManager; + +/* @test + * @bug 8137571 + * @summary Linux HiDPI Graphics support + * @author Alexander Scherbatiy + * @requires (os.family == "linux") + * @run main/othervm -Dsun.java2d.uiScale.enabled=false + * -Dsun.java2d.uiScale=2 + * HiDPIPropertiesLinuxTest UISCALE_DISABLED + * HiDPIPropertiesTest UISCALE_DISABLED + * @run main/othervm -Dsun.java2d.uiScale.enabled=true + * -Dsun.java2d.uiScale=3 + * HiDPIPropertiesLinuxTest UISCALE_3 + * @run main/othervm -Dsun.java2d.uiScale=4 + * HiDPIPropertiesLinuxTest UISCALE_4 + */ +public class HiDPIPropertiesLinuxTest { + + public static void main(String[] args) throws Exception { + + try { + UIManager.setLookAndFeel( + "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); + } catch (Exception e) { + return; + } + + String testCase = args[0]; + switch (testCase) { + case "UISCALE_DISABLED": + testScale(1.0, 1.0); + break; + case "UISCALE_3": + testScale(3.0, 3.0); + break; + case "UISCALE_4": + testScale(4.0, 4.0); + break; + default: + throw new RuntimeException("Unknown test case: " + testCase); + } + } + + private static void testScale(double scaleX, double scaleY) { + + Dialog dialog = new Dialog((Frame) null, true) { + + @Override + public void paint(Graphics g) { + super.paint(g); + AffineTransform tx = ((Graphics2D) g).getTransform(); + dispose(); + if (scaleX != tx.getScaleX() || scaleY != tx.getScaleY()) { + throw new RuntimeException(String.format("Wrong scale:" + + "[%f, %f] instead of [%f, %f].", + tx.getScaleX(), tx.getScaleY(), scaleX, scaleY)); + } + } + }; + dialog.setSize(200, 300); + dialog.setVisible(true); + } +}