8076313: GraphicsEnvironment does not detect changes in count of monitors on Linux OS

Reviewed-by: kizune
This commit is contained in:
Sergey Bylokhov 2021-02-03 03:41:53 +00:00
parent a47befc86f
commit 98a76921ec
6 changed files with 244 additions and 144 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2021, 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
@ -351,8 +351,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
awtUnlock();
try {
((X11GraphicsEnvironment)GraphicsEnvironment.
getLocalGraphicsEnvironment()).
displayChanged();
getLocalGraphicsEnvironment()).rebuildDevices();
} finally {
awtLock();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2021, 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
@ -329,19 +329,10 @@ public class X11GraphicsConfig extends GraphicsConfiguration
}
@Override
public Rectangle getBounds() {
Rectangle rect = pGetBounds(device.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;
public final Rectangle getBounds() {
return device.getBounds();
}
private native Rectangle pGetBounds(int screenNum);
private static class XDBECapabilities extends BufferCapabilities {
public XDBECapabilities() {
super(imageCaps, imageCaps, FlipContents.UNDEFINED);

View File

@ -42,6 +42,7 @@ import sun.awt.util.ThreadGroupUtils;
import sun.java2d.SunGraphicsEnvironment;
import sun.java2d.loops.SurfaceType;
import sun.java2d.opengl.GLXGraphicsConfig;
import sun.java2d.pipe.Region;
import sun.java2d.xr.XRGraphicsConfig;
/**
@ -53,7 +54,11 @@ import sun.java2d.xr.XRGraphicsConfig;
*/
public final class X11GraphicsDevice extends GraphicsDevice
implements DisplayChangedListener {
int screen;
/**
* X11 screen number. This identifier can become non-valid at any time
* therefore methods, which is using this id should be ready to it.
*/
private volatile int screen;
HashMap<SurfaceType, Object> x11ProxyKeyMap = new HashMap<>();
private static AWTPermission fullScreenExclusivePermission;
@ -105,6 +110,25 @@ public final class X11GraphicsDevice extends GraphicsDevice
return TYPE_RASTER_SCREEN;
}
public int scaleUp(int x) {
return Region.clipRound(x * (double)getScaleFactor());
}
public int scaleDown(int x) {
return Region.clipRound(x / (double)getScaleFactor());
}
public Rectangle getBounds() {
Rectangle rect = pGetBounds(getScreen());
if (getScaleFactor() != 1) {
rect.x = scaleDown(rect.x);
rect.y = scaleDown(rect.y);
rect.width = scaleDown(rect.width);
rect.height = scaleDown(rect.height);
}
return rect;
}
/**
* Returns the identification string associated with this graphics
* device.
@ -165,8 +189,8 @@ public final class X11GraphicsDevice extends GraphicsDevice
doubleBufferVisuals.contains(Integer.valueOf(visNum)));
if (xrenderSupported) {
ret[i] = XRGraphicsConfig.getConfig(this, visNum, depth, getConfigColormap(i, screen),
doubleBuffer);
ret[i] = XRGraphicsConfig.getConfig(this, visNum, depth,
getConfigColormap(i, screen), doubleBuffer);
} else {
ret[i] = X11GraphicsConfig.getConfig(this, visNum, depth,
getConfigColormap(i, screen),
@ -271,8 +295,8 @@ public final class X11GraphicsDevice extends GraphicsDevice
private static native void configDisplayMode(int screen,
int width, int height,
int displayMode);
private static native void resetNativeData(int screen);
private static native double getNativeScaleFactor(int screen);
private native Rectangle pGetBounds(int screenNum);
/**
* Returns true only if:
@ -514,7 +538,6 @@ public final class X11GraphicsDevice extends GraphicsDevice
}
public int getNativeScale() {
isXrandrExtensionSupported();
return (int)Math.round(getNativeScaleFactor(screen));
}
@ -544,4 +567,8 @@ public final class X11GraphicsDevice extends GraphicsDevice
public String toString() {
return ("X11GraphicsDevice[screen="+screen+"]");
}
public void invalidate(X11GraphicsDevice device) {
screen = device.screen;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2021, 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
@ -27,17 +27,23 @@ package sun.awt;
import java.awt.AWTError;
import java.awt.GraphicsDevice;
import java.lang.ref.WeakReference;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import sun.awt.X11.XToolkit;
import sun.java2d.SunGraphicsEnvironment;
import sun.java2d.SurfaceManagerFactory;
import sun.java2d.UnixSurfaceManagerFactory;
import sun.java2d.xr.XRSurfaceData;
import sun.util.logging.PlatformLogger;
/**
* This is an implementation of a GraphicsEnvironment object for the
@ -49,11 +55,6 @@ import sun.util.logging.PlatformLogger;
*/
public final class X11GraphicsEnvironment extends SunGraphicsEnvironment {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11GraphicsEnvironment");
private static final PlatformLogger screenLog = PlatformLogger.getLogger("sun.awt.screen.X11GraphicsEnvironment");
private static Boolean xinerState;
static {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Object>() {
@ -169,32 +170,109 @@ public final class X11GraphicsEnvironment extends SunGraphicsEnvironment {
private static native String getDisplayString();
private Boolean isDisplayLocal;
/** Available X11 screens. */
private final Map<Integer, X11GraphicsDevice> devices = new HashMap<>(5);
/**
* The key in the {@link #devices} for the main screen.
*/
private int mainScreen;
// list of invalidated graphics devices (those which were removed)
private List<WeakReference<X11GraphicsDevice>> oldDevices = new ArrayList<>();
/**
* This should only be called from the static initializer, so no need for
* the synchronized keyword.
*/
private static native void initDisplay(boolean glxRequested);
public X11GraphicsEnvironment() {
}
protected native int getNumScreens();
protected GraphicsDevice makeScreenDevice(int screennum) {
return new X11GraphicsDevice(screennum);
private native int getDefaultScreenNum();
public X11GraphicsEnvironment() {
if (isHeadless()) {
return;
}
/* Populate the device table */
rebuildDevices();
}
private native int getDefaultScreenNum();
/**
* Returns the default screen graphics device.
* Initialize the native list of devices.
*/
public GraphicsDevice getDefaultScreenDevice() {
GraphicsDevice[] screens = getScreenDevices();
if (screens.length == 0) {
private static native void initNativeData();
/**
* Updates the list of devices and notify listeners.
*/
public void rebuildDevices() {
XToolkit.awtLock();
try {
initNativeData();
initDevices();
} finally {
XToolkit.awtUnlock();
}
displayChanged();
}
/**
* (Re)create all X11GraphicsDevices, reuses a devices if it is possible.
*/
private synchronized void initDevices() {
Map<Integer, X11GraphicsDevice> old = new HashMap<>(devices);
devices.clear();
int numScreens = getNumScreens();
if (numScreens == 0) {
throw new AWTError("no screen devices");
}
int index = getDefaultScreenNum();
return screens[0 < index && index < screens.length ? index : 0];
mainScreen = 0 < index && index < screens.length ? index : 0;
for (int id = 0; id < numScreens; ++id) {
devices.put(id, old.containsKey(id) ? old.remove(id) :
new X11GraphicsDevice(id));
}
// if a device was not reused it should be invalidated
for (X11GraphicsDevice gd : old.values()) {
oldDevices.add(new WeakReference<>(gd));
}
// Need to notify old devices, in case the user hold the reference to it
for (ListIterator<WeakReference<X11GraphicsDevice>> it =
oldDevices.listIterator(); it.hasNext(); ) {
X11GraphicsDevice gd = it.next().get();
if (gd != null) {
gd.invalidate(devices.get(mainScreen));
gd.displayChanged();
} else {
// no more references to this device, remove it
it.remove();
}
}
}
@Override
public synchronized GraphicsDevice getDefaultScreenDevice() {
return devices.get(mainScreen);
}
@Override
public synchronized GraphicsDevice[] getScreenDevices() {
return devices.values().toArray(new X11GraphicsDevice[0]);
}
public synchronized GraphicsDevice getScreenDevice(int screen) {
return devices.get(screen);
}
@Override
protected GraphicsDevice makeScreenDevice(int screennum) {
throw new UnsupportedOperationException("This method is unused and" +
"should not be called in this implementation");
}
public boolean isDisplayLocal() {
@ -289,15 +367,7 @@ public final class X11GraphicsEnvironment extends SunGraphicsEnvironment {
private static native boolean pRunningXinerama();
public boolean runningXinerama() {
if (xinerState == null) {
// pRunningXinerama() simply returns a global boolean variable,
// so there is no need to synchronize here
xinerState = Boolean.valueOf(pRunningXinerama());
if (screenLog.isLoggable(PlatformLogger.Level.FINER)) {
screenLog.finer("Running Xinerama: " + xinerState);
}
}
return xinerState.booleanValue();
return pRunningXinerama();
}
/**

View File

@ -58,7 +58,7 @@
int awt_numScreens; /* Xinerama-aware number of screens */
AwtScreenDataPtr x11Screens;
AwtScreenDataPtr x11Screens; // should be guarded by AWT_LOCK()/AWT_UNLOCK()
/*
* Set in initDisplay() to indicate whether we should attempt to initialize
@ -591,8 +591,6 @@ static void xineramaInit(void) {
int32_t major_opcode, first_event, first_error;
Bool gotXinExt = False;
void* libHandle = NULL;
int32_t locNumScr = 0;
XineramaScreenInfo *xinInfo;
char* XineramaQueryScreensName = "XineramaQueryScreens";
gotXinExt = XQueryExtension(awt_display, XinExtName, &major_opcode,
@ -622,29 +620,92 @@ static void xineramaInit(void) {
if (XineramaQueryScreens == NULL) {
DTRACE_PRINTLN("couldn't load XineramaQueryScreens symbol");
dlclose(libHandle);
} else {
DTRACE_PRINTLN("calling XineramaQueryScreens func");
xinInfo = (*XineramaQueryScreens)(awt_display, &locNumScr);
if (xinInfo != NULL) {
if (locNumScr > XScreenCount(awt_display)) {
DTRACE_PRINTLN("Enabling Xinerama support");
usingXinerama = True;
/* set global number of screens */
DTRACE_PRINTLN1(" num screens = %i\n", locNumScr);
awt_numScreens = locNumScr;
} else {
DTRACE_PRINTLN("XineramaQueryScreens <= XScreenCount");
}
XFree(xinInfo);
} else {
DTRACE_PRINTLN("calling XineramaQueryScreens didn't work");
}
}
} else {
DTRACE_PRINTLN1("\ncouldn't open shared library: %s\n", dlerror());
}
}
static void resetNativeData(int screen) {
/*
* Reset references to the various configs; the actual native config data
* will be free'd later by the Disposer mechanism when the Java-level
* X11GraphicsConfig objects go away. By setting these values to NULL,
* we ensure that they will be reinitialized as necessary (for example,
* see the getNumConfigs() method).
*/
if (x11Screens[screen].configs) {
free(x11Screens[screen].configs);
x11Screens[screen].configs = NULL;
}
x11Screens[screen].defaultConfig = NULL;
x11Screens[screen].numConfigs = 0;
}
/*
* Class: sun_awt_X11GraphicsEnvironment
* Method: initDevices
* Signature: (Z)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsEnvironment_initNativeData(JNIEnv *env, jobject this) {
usingXinerama = False;
if (x11Screens) {
for (int i = 0; i < awt_numScreens; ++i) {
resetNativeData(i);
}
free((void *)x11Screens);
x11Screens = NULL;
awt_numScreens = 0;
}
// will try xinerama first
if (XineramaQueryScreens) {
int32_t locNumScr = 0;
XineramaScreenInfo *xinInfo;
DTRACE_PRINTLN("calling XineramaQueryScreens func");
xinInfo = (*XineramaQueryScreens)(awt_display, &locNumScr);
if (xinInfo != NULL) {
if (locNumScr > XScreenCount(awt_display)) {
DTRACE_PRINTLN("Enabling Xinerama support");
usingXinerama = True;
/* set global number of screens */
DTRACE_PRINTLN1(" num screens = %i\n", locNumScr);
awt_numScreens = locNumScr;
} else {
DTRACE_PRINTLN("XineramaQueryScreens <= XScreenCount");
}
XFree(xinInfo);
} else {
DTRACE_PRINTLN("calling XineramaQueryScreens didn't work");
}
}
// if xinerama is not enabled or does not work will use X11
if (!usingXinerama) {
awt_numScreens = XScreenCount(awt_display);
}
DTRACE_PRINTLN1("allocating %i screens\n", awt_numScreens);
/* Allocate screen data structure array */
x11Screens = calloc(awt_numScreens, sizeof(AwtScreenData));
if (x11Screens == NULL) {
JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2),
NULL);
return;
}
for (int i = 0; i < awt_numScreens; i++) {
if (usingXinerama) {
/* All Xinerama screens use the same X11 root for now */
x11Screens[i].root = RootWindow(awt_display, 0);
}
else {
x11Screens[i].root = RootWindow(awt_display, i);
}
x11Screens[i].defaultConfig = makeDefaultConfig(env, i);
JNU_CHECK_EXCEPTION(env);
}
}
Display *
awt_init_Display(JNIEnv *env, jobject this)
{
@ -692,32 +753,6 @@ awt_init_Display(JNIEnv *env, jobject this)
/* set awt_numScreens, and whether or not we're using Xinerama */
xineramaInit();
if (!usingXinerama) {
awt_numScreens = XScreenCount(awt_display);
}
DTRACE_PRINTLN1("allocating %i screens\n", awt_numScreens);
/* Allocate screen data structure array */
x11Screens = calloc(awt_numScreens, sizeof(AwtScreenData));
if (x11Screens == NULL) {
JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2),
NULL);
return NULL;
}
for (i = 0; i < awt_numScreens; i++) {
if (usingXinerama) {
/* All Xinerama screens use the same X11 root for now */
x11Screens[i].root = RootWindow(awt_display, 0);
}
else {
x11Screens[i].root = RootWindow(awt_display, i);
}
x11Screens[i].defaultConfig = makeDefaultConfig(env, i);
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
}
return dpy;
}
@ -937,8 +972,11 @@ JNIEXPORT jint JNICALL
Java_sun_awt_X11GraphicsDevice_getNumConfigs(
JNIEnv *env, jobject this, jint screen)
{
AWT_LOCK();
ensureConfigsInited(env, screen);
return x11Screens[screen].numConfigs;
int configs = x11Screens[screen].numConfigs;
AWT_UNLOCK();
return configs;
}
/*
@ -951,13 +989,12 @@ Java_sun_awt_X11GraphicsDevice_getConfigVisualId(
JNIEnv *env, jobject this, jint index, jint screen)
{
int visNum;
AWT_LOCK();
ensureConfigsInited(env, screen);
if (index == 0) {
return ((jint)x11Screens[screen].defaultConfig->awt_visInfo.visualid);
} else {
return ((jint)x11Screens[screen].configs[index]->awt_visInfo.visualid);
}
jint id = (jint) (index == 0 ? x11Screens[screen].defaultConfig
: x11Screens[screen].configs[index])->awt_visInfo.visualid;
AWT_UNLOCK();
return id;
}
/*
@ -970,13 +1007,12 @@ Java_sun_awt_X11GraphicsDevice_getConfigDepth(
JNIEnv *env, jobject this, jint index, jint screen)
{
int visNum;
AWT_LOCK();
ensureConfigsInited(env, screen);
if (index == 0) {
return ((jint)x11Screens[screen].defaultConfig->awt_visInfo.depth);
} else {
return ((jint)x11Screens[screen].configs[index]->awt_visInfo.depth);
}
jint depth = (jint) (index == 0 ? x11Screens[screen].defaultConfig
: x11Screens[screen].configs[index])->awt_visInfo.depth;
AWT_UNLOCK();
return depth;
}
/*
@ -989,38 +1025,14 @@ Java_sun_awt_X11GraphicsDevice_getConfigColormap(
JNIEnv *env, jobject this, jint index, jint screen)
{
int visNum;
AWT_LOCK();
ensureConfigsInited(env, screen);
if (index == 0) {
return ((jint)x11Screens[screen].defaultConfig->awt_cmap);
} else {
return ((jint)x11Screens[screen].configs[index]->awt_cmap);
}
jint colormap = (jint) (index == 0 ? x11Screens[screen].defaultConfig
: x11Screens[screen].configs[index])->awt_cmap;
AWT_UNLOCK();
return colormap;
}
/*
* Class: sun_awt_X11GraphicsDevice
* Method: resetNativeData
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsDevice_resetNativeData
(JNIEnv *env, jclass x11gd, jint screen)
{
/*
* Reset references to the various configs; the actual native config data
* will be free'd later by the Disposer mechanism when the Java-level
* X11GraphicsConfig objects go away. By setting these values to NULL,
* we ensure that they will be reinitialized as necessary (for example,
* see the getNumConfigs() method).
*/
if (x11Screens[screen].configs) {
free(x11Screens[screen].configs);
x11Screens[screen].configs = NULL;
}
x11Screens[screen].defaultConfig = NULL;
x11Screens[screen].numConfigs = 0;
}
/*
* Class: sun_awt_X11GraphicsConfig
@ -1128,6 +1140,7 @@ Java_sun_awt_X11GraphicsConfig_init(
JNIEnv *env, jobject this, jint visualNum, jint screen)
{
AwtGraphicsConfigData *adata = NULL;
AWT_LOCK();
AwtScreenData asd = x11Screens[screen];
int i, n;
int depth;
@ -1149,6 +1162,7 @@ JNIEnv *env, jobject this, jint visualNum, jint screen)
/* If didn't find the visual, throw an exception... */
if (adata == (AwtGraphicsConfigData *) NULL) {
AWT_UNLOCK();
JNU_ThrowIllegalArgumentException(env, "Unknown Visual Specified");
return;
}
@ -1167,6 +1181,7 @@ JNIEnv *env, jobject this, jint visualNum, jint screen)
(*env)->SetIntField(env, this, x11GraphicsConfigIDs.bitsPerPixel,
(jint)tempImage->bits_per_pixel);
XDestroyImage(tempImage);
AWT_UNLOCK();
}
/*
@ -1210,23 +1225,19 @@ JNIEnv *env, jobject this)
/*
* Class: sun_awt_X11GraphicsConfig
* Class: sun_awt_X11GraphicsDevice
* Method: getBounds
* Signature: ()Ljava/awt/Rectangle
*/
JNIEXPORT jobject JNICALL
Java_sun_awt_X11GraphicsConfig_pGetBounds(JNIEnv *env, jobject this, jint screen)
Java_sun_awt_X11GraphicsDevice_pGetBounds(JNIEnv *env, jobject this, jint screen)
{
jclass clazz;
jmethodID mid;
jobject bounds = NULL;
AwtGraphicsConfigDataPtr adata;
int32_t locNumScr = 0;
XineramaScreenInfo *xinInfo;
adata = (AwtGraphicsConfigDataPtr)
JNU_GetLongFieldAsPtr(env, this, x11GraphicsConfigIDs.aData);
clazz = (*env)->FindClass(env, "java/awt/Rectangle");
CHECK_NULL_RETURN(clazz, NULL);
mid = (*env)->GetMethodID(env, clazz, "<init>", "(IIII)V");
@ -1261,8 +1272,7 @@ Java_sun_awt_X11GraphicsConfig_pGetBounds(JNIEnv *env, jobject this, jint screen
memset(&xwa, 0, sizeof(xwa));
AWT_LOCK ();
XGetWindowAttributes(awt_display,
RootWindow(awt_display, adata->awt_visInfo.screen),
XGetWindowAttributes(awt_display, RootWindow(awt_display, screen),
&xwa);
AWT_UNLOCK ();

View File

@ -120,9 +120,10 @@ JNIEXPORT jlong JNICALL Java_sun_awt_X11_XToolkit_getTrayIconDisplayTimeout
JNIEXPORT jlong JNICALL Java_sun_awt_X11_XToolkit_getDefaultXColormap
(JNIEnv *env, jclass clazz)
{
AWT_LOCK();
AwtGraphicsConfigDataPtr defaultConfig =
getDefaultConfig(DefaultScreen(awt_display));
AWT_UNLOCK();
return (jlong) defaultConfig->awt_cmap;
}
@ -145,9 +146,11 @@ DEF_JNI_OnLoad(JavaVM *vm, void *reserved)
JNIEXPORT void JNICALL Java_sun_awt_X11_XToolkit_nativeLoadSystemColors
(JNIEnv *env, jobject this, jintArray systemColors)
{
AWT_LOCK();
AwtGraphicsConfigDataPtr defaultConfig =
getDefaultConfig(DefaultScreen(awt_display));
awtJNI_CreateColorData(env, defaultConfig, 1);
AWT_UNLOCK();
}
JNIEXPORT void JNICALL