--- old/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java 2018-09-11 14:48:21.000000000 -0700 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java 2018-09-11 14:48:21.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2018, 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 @@ -215,6 +215,12 @@ static long awt_defaultFg; // Pixel private static XMouseInfoPeer xPeer; + /** + * Should we check "_NET_WM_STRUT/_NET_WM_STRUT_PARTIAL" during insets + * calculation. + */ + private static Boolean checkSTRUT; + static { initSecurityWarning(); if (GraphicsEnvironment.isHeadless()) { @@ -826,13 +832,26 @@ } /* - * If we're running in non-Xinerama environment and the current - * window manager supports _NET protocol then the screen insets - * are calculated using _NET_WM_WORKAREA property of the root - * window. - * Otherwise, i. e. if Xinerama is on or _NET_WM_WORKAREA is - * not set, we try to calculate the insets ourselves using - * getScreenInsetsManually method. + * If the current window manager supports _NET protocol then the screen + * insets are calculated using _NET_WORKAREA property of the root window. + *

+ * Note that _NET_WORKAREA is a rectangular area and it does not work + * well in the Xinerama mode. + *

+ * We will trust the part of this rectangular area only if it starts at the + * requested graphics configuration. Below is an example when the + * _NET_WORKAREA intersects with the requested graphics configuration but + * produces wrong result. + * + * //<-x1,y1/////// + * // // //////////////// + * // SCREEN1 // // SCREEN2 // + * // ********** // // x2,y2->// + * //////////////// // // + * //////////////// + * + * When two screens overlap and the first contains a dock(*****), then + * _NET_WORKAREA may start at point x1,y1 and end at point x2,y2. */ @Override public Insets getScreenInsets(GraphicsConfiguration gc) @@ -846,30 +865,33 @@ XToolkit.awtLock(); try { - X11GraphicsConfig x11gc = (X11GraphicsConfig)gc; - X11GraphicsDevice x11gd = x11gc.getDevice(); - long root = XlibUtil.getRootWindow(x11gd.getScreen()); - int scale = x11gc.getScale(); - Rectangle rootBounds = XlibUtil.getWindowGeometry(root, scale); - X11GraphicsEnvironment x11ge = (X11GraphicsEnvironment) - GraphicsEnvironment.getLocalGraphicsEnvironment(); - if (!x11ge.runningXinerama()) - { - Insets screenInsets = getInsets(root, rootBounds, scale); - if (screenInsets != null) return screenInsets; - } - - Insets insets = getScreenInsetsManually(root, rootBounds, - gc.getBounds(), scale); - if ((insets.left | insets.top | insets.bottom | insets.right) == 0 - && rootBounds != null ) { - root = XlibWrapper.RootWindow(XToolkit.getDisplay(), - x11gd.getScreen()); - Insets screenInsets = getInsets(root, rootBounds, scale); - if (screenInsets != null) return screenInsets; + GraphicsEnvironment.getLocalGraphicsEnvironment(); + X11GraphicsConfig x11gc = (X11GraphicsConfig) gc; + long root = XlibUtil.getRootWindow(x11gc.getDevice().getScreen()); + int scale = x11gc.getScale(); + if (x11ge.runningXinerama() && checkSTRUT()) { + // implementation based on _NET_WM_STRUT/_NET_WM_STRUT_PARTIAL + Rectangle rootBounds = XlibUtil.getWindowGeometry(root, scale); + Insets insets = getScreenInsetsManually(root, rootBounds, + gc.getBounds(), scale); + if ((insets.left | insets.top | insets.bottom | insets.right) != 0 + || rootBounds == null) { + return insets; + } + } + Rectangle workArea = XToolkit.getWorkArea(root, scale); + Rectangle screen = gc.getBounds(); + if (workArea != null && screen.contains(workArea.getLocation())) { + workArea = workArea.intersection(screen); + int top = workArea.y - screen.y; + int left = workArea.x - screen.x; + int bottom = screen.height - workArea.height - top; + int right = screen.width - workArea.width - left; + return new Insets(top, left, bottom, right); } - return insets; + // Note that it is better to return zeros than inadequate values + return new Insets(0, 0, 0, 0); } finally { @@ -877,14 +899,16 @@ } } - private Insets getInsets(long root, Rectangle rootBounds, int scale) { - Rectangle workArea = XToolkit.getWorkArea(root, scale); - if (workArea == null) { - return null; + /** + * Returns the value of "sun.awt.X11.checkSTRUT" property. Default value is + * {@code false}. + */ + private static boolean checkSTRUT() { + if (checkSTRUT == null) { + checkSTRUT = AccessController.doPrivileged( + new GetBooleanAction("sun.awt.X11.checkSTRUT")); } - return new Insets(workArea.y, workArea.x, - rootBounds.height - workArea.height - workArea.y, - rootBounds.width - workArea.width - workArea.x); + return checkSTRUT; } /* @@ -893,6 +917,14 @@ * hints' values to screen insets. * * This method should be called under XToolkit.awtLock() + * + * This method is unused by default because of two reasons: + * - Iteration over windows may be extremely slow, and execution of + * getScreenInsets() can be x100 slower than in one monitor config. + * - _NET_WM_STRUT/_NET_WM_STRUT_PARTIAL are hints for the applications. + * WM should take into account these hints when "_NET_WORKAREA" is + * calculated, but the system panels do not necessarily contain these + * hints(Gnome 3 for example). */ private Insets getScreenInsetsManually(long root, Rectangle rootBounds, Rectangle screenBounds, int scale) --- old/test/jdk/java/awt/Mixing/AWT_Mixing/FrameBorderCounter.java 2018-09-11 14:48:23.000000000 -0700 +++ new/test/jdk/java/awt/Mixing/AWT_Mixing/FrameBorderCounter.java 2018-09-11 14:48:23.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -20,15 +20,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Frame; import java.awt.Point; import java.awt.Robot; -import java.awt.event.MouseEvent; import java.awt.event.MouseAdapter; -import java.awt.event.WindowEvent; -import java.awt.event.WindowAdapter; +import java.awt.event.MouseEvent; public class FrameBorderCounter { @@ -59,6 +58,7 @@ background.setVisible(true); } }); + robot.waitForIdle(); EventQueue.invokeAndWait(new Runnable() { public void run() { frame = new Frame("Frame"); --- old/test/jdk/java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java 2018-09-11 14:48:25.000000000 -0700 +++ new/test/jdk/java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java 2018-09-11 14:48:24.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,13 @@ @run main ScreenInsetsTest */ -import java.awt.*; -import java.awt.event.*; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.Toolkit; import test.java.awt.regtesthelpers.Util; @@ -41,21 +46,33 @@ { public static void main(String[] args) { - if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) - { - // this state is used in the test - sorry - return; - } - boolean passed = true; GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] gds = ge.getScreenDevices(); - for (GraphicsDevice gd : gds) - { + for (GraphicsDevice gd : gds) { + GraphicsConfiguration gc = gd.getDefaultConfiguration(); Rectangle gcBounds = gc.getBounds(); Insets gcInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc); + int left = gcInsets.left; + int right = gcInsets.right; + int bottom = gcInsets.bottom; + int top = gcInsets.top; + if (left < 0 || right < 0 || bottom < 0 || top < 0) { + throw new RuntimeException("Negative value: " + gcInsets); + } + int maxW = gcBounds.width / 3; + int maxH = gcBounds.height / 3; + if (left > maxW || right > maxW || bottom > maxH || top > maxH) { + throw new RuntimeException("Big value: " + gcInsets); + } + + if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) + { + // this state is used in the test - sorry + continue; + } Frame f = new Frame("Test", gc); f.setUndecorated(true);