8170937: Swing apps are slow if displaying from a remote source to many local displays
Reviewed-by: prr, aivanov
--- a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java Tue Sep 18 18:12:40 2018 +0530
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java Tue Sep 18 18:32:03 2018 -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.
+ * <p>
+ * Note that _NET_WORKAREA is a rectangular area and it does not work
+ * well in the Xinerama mode.
+ * <p>
+ * 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());
+ X11GraphicsEnvironment x11ge = (X11GraphicsEnvironment)
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ X11GraphicsConfig x11gc = (X11GraphicsConfig) gc;
+ long root = XlibUtil.getRootWindow(x11gc.getDevice().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;
+ 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;
+ }
}
-
- 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;
+ 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)
--- a/test/jdk/java/awt/Mixing/AWT_Mixing/FrameBorderCounter.java Tue Sep 18 18:12:40 2018 +0530
+++ b/test/jdk/java/awt/Mixing/AWT_Mixing/FrameBorderCounter.java Tue Sep 18 18:32:03 2018 -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.MouseAdapter;
import java.awt.event.MouseEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.WindowEvent;
-import java.awt.event.WindowAdapter;
public class FrameBorderCounter {
@@ -59,6 +58,7 @@
background.setVisible(true);
}
});
+ robot.waitForIdle();
EventQueue.invokeAndWait(new Runnable() {
public void run() {
frame = new Frame("Frame");
--- a/test/jdk/java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java Tue Sep 18 18:12:40 2018 +0530
+++ b/test/jdk/java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java Tue Sep 18 18:32:03 2018 -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);