changeset 13220:bc2d1130105f

8137571: Linux HiDPI Graphics support Reviewed-by: flar, serb
author alexsch
date Fri, 13 Nov 2015 18:36:14 +0400
parents a8e9ad77ac81
children c02fde8e6d02
files make/mapfiles/libawt/mapfile-vers-linux make/mapfiles/libawt_xawt/mapfile-vers src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java src/java.desktop/unix/classes/sun/awt/X11/XBaseWindow.java src/java.desktop/unix/classes/sun/awt/X11/XChoicePeer.java src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java src/java.desktop/unix/classes/sun/awt/X11/XDragSourceContextPeer.java src/java.desktop/unix/classes/sun/awt/X11/XEmbedClientHelper.java src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java src/java.desktop/unix/classes/sun/awt/X11/XPopupMenuPeer.java src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java src/java.desktop/unix/classes/sun/awt/X11/XWM.java src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java src/java.desktop/unix/classes/sun/awt/X11/XWindow.java src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java src/java.desktop/unix/classes/sun/awt/X11/XlibUtil.java src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceDataProxy.java src/java.desktop/unix/classes/sun/java2d/xr/XRVolatileSurfaceManager.java src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h test/java/awt/hidpi/properties/HiDPIPropertiesLinuxTest.java
diffstat 31 files changed, 567 insertions(+), 194 deletions(-) [+]
line wrap: on
line diff
--- a/make/mapfiles/libawt/mapfile-vers-linux	Fri Nov 13 05:02:26 2015 -0800
+++ b/make/mapfiles/libawt/mapfile-vers-linux	Fri Nov 13 18:36:14 2015 +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;
--- a/make/mapfiles/libawt_xawt/mapfile-vers	Fri Nov 13 05:02:26 2015 -0800
+++ b/make/mapfiles/libawt_xawt/mapfile-vers	Fri Nov 13 18:36:14 2015 +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;
--- a/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java	Fri Nov 13 18:36:14 2015 +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);
--- a/src/java.desktop/unix/classes/sun/awt/X11/XBaseWindow.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XBaseWindow.java	Fri Nov 13 18:36:14 2015 +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 <code>params</code>
      * @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
--- a/src/java.desktop/unix/classes/sun/awt/X11/XChoicePeer.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XChoicePeer.java	Fri Nov 13 18:36:14 2015 +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();
--- a/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java	Fri Nov 13 18:36:14 2015 +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(),
--- a/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java	Fri Nov 13 18:36:14 2015 +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}",
@@ -793,7 +789,8 @@
         try {
             updateSizeHints(rec.x, rec.y, rec.width, rec.height);
             XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getShell(),
-                            rec.x, rec.y, rec.width, rec.height);
+                                          scaleUp(rec.x), scaleUp(rec.y),
+                                          scaleUp(rec.width), scaleUp(rec.height));
         }
         finally {
             XToolkit.awtUnlock();
@@ -806,7 +803,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 +817,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();
--- a/src/java.desktop/unix/classes/sun/awt/X11/XDragSourceContextPeer.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XDragSourceContextPeer.java	Fri Nov 13 18:36:14 2015 +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;
+    }
 }
--- a/src/java.desktop/unix/classes/sun/awt/X11/XEmbedClientHelper.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XEmbedClientHelper.java	Fri Nov 13 18:36:14 2015 +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()))
             {
--- a/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java	Fri Nov 13 18:36:14 2015 +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;
     }
 
--- a/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java	Fri Nov 13 18:36:14 2015 +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) {
--- a/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java	Fri Nov 13 18:36:14 2015 +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) {
--- a/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java	Fri Nov 13 18:36:14 2015 +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 = XlibUtil.scaleDown(point.x, scale);
+                        point.y = XlibUtil.scaleDown(point.y, scale);
+                    }
                     return i;
                 }
             }
--- a/src/java.desktop/unix/classes/sun/awt/X11/XPopupMenuPeer.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XPopupMenuPeer.java	Fri Nov 13 18:36:14 2015 +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) {
--- a/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java	Fri Nov 13 18:36:14 2015 +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);
 }
--- a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java	Fri Nov 13 18:36:14 2015 +0400
@@ -57,6 +57,7 @@
 import sun.security.action.GetPropertyAction;
 import sun.security.action.GetBooleanAction;
 import sun.util.logging.PlatformLogger;
+import static sun.awt.X11.XlibUtil.scaleDown;
 
 public final class XToolkit extends UNIXToolkit implements Runnable {
     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XToolkit");
@@ -422,7 +423,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 +432,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 +455,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 +497,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 ) {
@@ -670,8 +676,8 @@
                     XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
                                                      XToolkit.getDefaultRootWindow(),
                                                      pattr.pData);
-                    screenWidth  = pattr.get_width();
-                    screenHeight = pattr.get_height();
+                    screenWidth  = config.scaleDown(pattr.get_width());
+                    screenHeight = config.scaleDown(pattr.get_height());
                 } finally {
                     pattr.dispose();
                 }
@@ -701,7 +707,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 +723,10 @@
                 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(scaleDown(rootX, scale),
+                                     scaleDown(rootY, scale),
+                                     scaleDown(rootWidth, scale),
+                                     scaleDown(rootHeight, scale));
             }
         }
         finally
@@ -750,15 +759,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 +778,7 @@
                 }
             }
 
-            return getScreenInsetsManually(root, rootBounds, gc.getBounds());
+            return getScreenInsetsManually(root, rootBounds, gc.getBounds(), scale);
         }
         finally
         {
@@ -783,7 +793,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 +842,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 = scaleDown((int)Native.getLong(native_ptr, 0), scale);
+                        int right = scaleDown((int)Native.getLong(native_ptr, 1), scale);
+                        int top = scaleDown((int)Native.getLong(native_ptr, 2), scale);
+                        int bottom = scaleDown((int)Native.getLong(native_ptr, 3), scale);
 
                         /*
                          * struts could be relative to root window bounds, so
@@ -2487,7 +2501,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;
--- a/src/java.desktop/unix/classes/sun/awt/X11/XWM.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XWM.java	Fri Nov 13 18:36:14 2015 +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);
         }
--- a/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java	Fri Nov 13 18:36:14 2015 +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() {
--- a/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java	Fri Nov 13 18:36:14 2015 +0400
@@ -548,10 +548,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();
@@ -676,10 +677,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;
         }
@@ -730,8 +732,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);
@@ -744,8 +746,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));
             }
@@ -757,8 +759,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);
@@ -805,8 +807,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 &&
@@ -828,7 +830,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;
         }
@@ -837,7 +840,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);
         }
@@ -949,10 +954,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;
         }
@@ -960,18 +966,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);
         }
     }
@@ -1531,4 +1546,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);
+    }
 }
--- a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java	Fri Nov 13 18:36:14 2015 +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
--- a/src/java.desktop/unix/classes/sun/awt/X11/XlibUtil.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XlibUtil.java	Fri Nov 13 18:36:14 2015 +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(scaleDown(x, scale), scaleDown(y, scale),
+                                 scaleDown((int) width, scale),
+                                 scaleDown((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,8 @@
                     ((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(scaleDown(xtc.get_dest_x(), scale),
+                                           scaleDown(xtc.get_dest_y(), scale));
                 }
             }
             finally
@@ -174,9 +177,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;
@@ -406,4 +412,8 @@
             return 1 << (7 + button);
         }
     }
+
+    static int scaleDown(int x, int scale) {
+        return x / scale;
+    }
 }
--- a/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java	Fri Nov 13 18:36:14 2015 +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);
--- a/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java	Fri Nov 13 18:36:14 2015 +0400
@@ -43,6 +43,7 @@
 import sun.java2d.loops.SurfaceType;
 
 import sun.awt.util.ThreadGroupUtils;
+import sun.java2d.SunGraphicsEnvironment;
 import sun.misc.ManagedLocalsThread;
 
 /**
@@ -63,9 +64,11 @@
     private SunDisplayChanger topLevels = new SunDisplayChanger();
     private DisplayMode origDisplayMode;
     private boolean shutdownHookRegistered;
+    private final 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,27 @@
         topLevels.add(client);
     }
 
+    public int getScaleFactor() {
+        return scale;
+    }
+
+    private int initScaleFactor() {
+
+        if (SunGraphicsEnvironment.isUIScaleEnabled()) {
+
+            double debugScale = SunGraphicsEnvironment.getDebugScale();
+
+            if (debugScale >= 1) {
+                return (int) debugScale;
+            }
+
+            int nativeScale = getNativeScaleFactor(screen);
+            return nativeScale >= 1 ? nativeScale : 1;
+        }
+
+        return 1;
+    }
+
     /**
      * Remove a DisplayChangeListener from this X11GraphicsDevice.
      */
--- a/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java	Fri Nov 13 18:36:14 2015 +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() {
--- a/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceDataProxy.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceDataProxy.java	Fri Nov 13 18:36:14 2015 +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;
     }
--- a/src/java.desktop/unix/classes/sun/java2d/xr/XRVolatileSurfaceManager.java	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/classes/sun/java2d/xr/XRVolatileSurfaceManager.java	Fri Nov 13 18:36:14 2015 +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) {
--- a/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c	Fri Nov 13 18:36:14 2015 +0400
@@ -2082,3 +2082,38 @@
 /**
  * End DisplayMode/FullScreen support
  */
+
+int getScale(const char *name) {
+    char *uiScale = getenv(name);
+    if (uiScale != NULL) {
+        double scale = strtod(uiScale, NULL);
+        if (errno == ERANGE || scale < 1) {
+            return -1;
+        }
+        return (int) scale;
+    }
+    return -1;
+}
+
+/*
+ * 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
+    static int scale = -2.0;
+
+    if (scale == -2) {
+        scale = getScale("J2D_UISCALE");
+    }
+
+    if (scale >= 1) {
+        return scale;
+    }
+
+    return getScale("GDK_SCALE");
+}
--- a/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c	Fri Nov 13 18:36:14 2015 +0400
@@ -210,6 +210,7 @@
                              jint jy,
                              jint jwidth,
                              jint jheight,
+                             jint scale,
                              jintArray pixelArray,
                              jboolean isGtkSupported) {
     XImage *image;
@@ -231,13 +232,18 @@
 
     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,6 +270,19 @@
 
         pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(NULL, root, NULL,
                                                     x, y, 0, 0, width, height);
+        if (pixbuf && scale != 1) {
+            GdkPixbuf *scaledPixbuf;
+            x /= scale;
+            y /= scale;
+            width /= scale;
+            height /= scale;
+            dx /= scale;
+            dy /= scale;
+            scaledPixbuf = (*fp_gdk_pixbuf_scale_simple)(pixbuf, width, height,
+                                                         GDK_INTERP_BILINEAR);
+            (*fp_g_object_unref)(pixbuf);
+            pixbuf = scaledPixbuf;
+        }
 
         if (pixbuf) {
             int nchan = (*fp_gdk_pixbuf_get_n_channels)(pixbuf);
@@ -312,7 +331,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 +341,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.
                                                                */
--- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c	Fri Nov 13 18:36:14 2015 +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");
--- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h	Fri Nov 13 05:02:26 2015 -0800
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h	Fri Nov 13 18:36:14 2015 +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	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/awt/hidpi/properties/HiDPIPropertiesLinuxTest.java	Fri Nov 13 18:36:14 2015 +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);
+    }
+}