Skip to content

Commit 98a7692

Browse files
committed
8076313: GraphicsEnvironment does not detect changes in count of monitors on Linux OS
Reviewed-by: kizune
1 parent a47befc commit 98a7692

File tree

6 files changed

+242
-142
lines changed

6 files changed

+242
-142
lines changed

src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -351,8 +351,7 @@ public void dispatchEvent(XEvent ev) {
351351
awtUnlock();
352352
try {
353353
((X11GraphicsEnvironment)GraphicsEnvironment.
354-
getLocalGraphicsEnvironment()).
355-
displayChanged();
354+
getLocalGraphicsEnvironment()).rebuildDevices();
356355
} finally {
357356
awtLock();
358357
}

src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java

+3-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -329,19 +329,10 @@ public String toString() {
329329
}
330330

331331
@Override
332-
public Rectangle getBounds() {
333-
Rectangle rect = pGetBounds(device.getScreen());
334-
if (getScale() != 1) {
335-
rect.x = scaleDown(rect.x);
336-
rect.y = scaleDown(rect.y);
337-
rect.width = scaleDown(rect.width);
338-
rect.height = scaleDown(rect.height);
339-
}
340-
return rect;
332+
public final Rectangle getBounds() {
333+
return device.getBounds();
341334
}
342335

343-
private native Rectangle pGetBounds(int screenNum);
344-
345336
private static class XDBECapabilities extends BufferCapabilities {
346337
public XDBECapabilities() {
347338
super(imageCaps, imageCaps, FlipContents.UNDEFINED);

src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java

+32-5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import sun.java2d.SunGraphicsEnvironment;
4343
import sun.java2d.loops.SurfaceType;
4444
import sun.java2d.opengl.GLXGraphicsConfig;
45+
import sun.java2d.pipe.Region;
4546
import sun.java2d.xr.XRGraphicsConfig;
4647

4748
/**
@@ -53,7 +54,11 @@
5354
*/
5455
public final class X11GraphicsDevice extends GraphicsDevice
5556
implements DisplayChangedListener {
56-
int screen;
57+
/**
58+
* X11 screen number. This identifier can become non-valid at any time
59+
* therefore methods, which is using this id should be ready to it.
60+
*/
61+
private volatile int screen;
5762
HashMap<SurfaceType, Object> x11ProxyKeyMap = new HashMap<>();
5863

5964
private static AWTPermission fullScreenExclusivePermission;
@@ -105,6 +110,25 @@ public int getType() {
105110
return TYPE_RASTER_SCREEN;
106111
}
107112

113+
public int scaleUp(int x) {
114+
return Region.clipRound(x * (double)getScaleFactor());
115+
}
116+
117+
public int scaleDown(int x) {
118+
return Region.clipRound(x / (double)getScaleFactor());
119+
}
120+
121+
public Rectangle getBounds() {
122+
Rectangle rect = pGetBounds(getScreen());
123+
if (getScaleFactor() != 1) {
124+
rect.x = scaleDown(rect.x);
125+
rect.y = scaleDown(rect.y);
126+
rect.width = scaleDown(rect.width);
127+
rect.height = scaleDown(rect.height);
128+
}
129+
return rect;
130+
}
131+
108132
/**
109133
* Returns the identification string associated with this graphics
110134
* device.
@@ -165,8 +189,8 @@ private void makeConfigurations() {
165189
doubleBufferVisuals.contains(Integer.valueOf(visNum)));
166190

167191
if (xrenderSupported) {
168-
ret[i] = XRGraphicsConfig.getConfig(this, visNum, depth, getConfigColormap(i, screen),
169-
doubleBuffer);
192+
ret[i] = XRGraphicsConfig.getConfig(this, visNum, depth,
193+
getConfigColormap(i, screen), doubleBuffer);
170194
} else {
171195
ret[i] = X11GraphicsConfig.getConfig(this, visNum, depth,
172196
getConfigColormap(i, screen),
@@ -271,8 +295,8 @@ private static native void enumDisplayModes(int screen,
271295
private static native void configDisplayMode(int screen,
272296
int width, int height,
273297
int displayMode);
274-
private static native void resetNativeData(int screen);
275298
private static native double getNativeScaleFactor(int screen);
299+
private native Rectangle pGetBounds(int screenNum);
276300

277301
/**
278302
* Returns true only if:
@@ -514,7 +538,6 @@ public int getScaleFactor() {
514538
}
515539

516540
public int getNativeScale() {
517-
isXrandrExtensionSupported();
518541
return (int)Math.round(getNativeScaleFactor(screen));
519542
}
520543

@@ -544,4 +567,8 @@ public void removeDisplayChangedListener(DisplayChangedListener client) {
544567
public String toString() {
545568
return ("X11GraphicsDevice[screen="+screen+"]");
546569
}
570+
571+
public void invalidate(X11GraphicsDevice device) {
572+
screen = device.screen;
573+
}
547574
}

src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java

+95-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -27,17 +27,23 @@
2727

2828
import java.awt.AWTError;
2929
import java.awt.GraphicsDevice;
30+
import java.lang.ref.WeakReference;
3031
import java.net.InetAddress;
3132
import java.net.NetworkInterface;
3233
import java.net.SocketException;
3334
import java.net.UnknownHostException;
35+
import java.util.ArrayList;
3436
import java.util.Enumeration;
37+
import java.util.HashMap;
38+
import java.util.List;
39+
import java.util.ListIterator;
40+
import java.util.Map;
3541

42+
import sun.awt.X11.XToolkit;
3643
import sun.java2d.SunGraphicsEnvironment;
3744
import sun.java2d.SurfaceManagerFactory;
3845
import sun.java2d.UnixSurfaceManagerFactory;
3946
import sun.java2d.xr.XRSurfaceData;
40-
import sun.util.logging.PlatformLogger;
4147

4248
/**
4349
* This is an implementation of a GraphicsEnvironment object for the
@@ -49,11 +55,6 @@
4955
*/
5056
public final class X11GraphicsEnvironment extends SunGraphicsEnvironment {
5157

52-
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11GraphicsEnvironment");
53-
private static final PlatformLogger screenLog = PlatformLogger.getLogger("sun.awt.screen.X11GraphicsEnvironment");
54-
55-
private static Boolean xinerState;
56-
5758
static {
5859
java.security.AccessController.doPrivileged(
5960
new java.security.PrivilegedAction<Object>() {
@@ -169,32 +170,109 @@ public static boolean isXRenderVerbose() {
169170
private static native String getDisplayString();
170171
private Boolean isDisplayLocal;
171172

173+
/** Available X11 screens. */
174+
private final Map<Integer, X11GraphicsDevice> devices = new HashMap<>(5);
175+
176+
/**
177+
* The key in the {@link #devices} for the main screen.
178+
*/
179+
private int mainScreen;
180+
181+
// list of invalidated graphics devices (those which were removed)
182+
private List<WeakReference<X11GraphicsDevice>> oldDevices = new ArrayList<>();
183+
172184
/**
173185
* This should only be called from the static initializer, so no need for
174186
* the synchronized keyword.
175187
*/
176188
private static native void initDisplay(boolean glxRequested);
177189

190+
protected native int getNumScreens();
191+
192+
private native int getDefaultScreenNum();
193+
178194
public X11GraphicsEnvironment() {
195+
if (isHeadless()) {
196+
return;
197+
}
198+
199+
/* Populate the device table */
200+
rebuildDevices();
179201
}
180202

181-
protected native int getNumScreens();
203+
/**
204+
* Initialize the native list of devices.
205+
*/
206+
private static native void initNativeData();
182207

183-
protected GraphicsDevice makeScreenDevice(int screennum) {
184-
return new X11GraphicsDevice(screennum);
208+
/**
209+
* Updates the list of devices and notify listeners.
210+
*/
211+
public void rebuildDevices() {
212+
XToolkit.awtLock();
213+
try {
214+
initNativeData();
215+
initDevices();
216+
} finally {
217+
XToolkit.awtUnlock();
218+
}
219+
displayChanged();
185220
}
186221

187-
private native int getDefaultScreenNum();
188222
/**
189-
* Returns the default screen graphics device.
223+
* (Re)create all X11GraphicsDevices, reuses a devices if it is possible.
190224
*/
191-
public GraphicsDevice getDefaultScreenDevice() {
192-
GraphicsDevice[] screens = getScreenDevices();
193-
if (screens.length == 0) {
225+
private synchronized void initDevices() {
226+
Map<Integer, X11GraphicsDevice> old = new HashMap<>(devices);
227+
devices.clear();
228+
229+
int numScreens = getNumScreens();
230+
if (numScreens == 0) {
194231
throw new AWTError("no screen devices");
195232
}
196233
int index = getDefaultScreenNum();
197-
return screens[0 < index && index < screens.length ? index : 0];
234+
mainScreen = 0 < index && index < screens.length ? index : 0;
235+
236+
for (int id = 0; id < numScreens; ++id) {
237+
devices.put(id, old.containsKey(id) ? old.remove(id) :
238+
new X11GraphicsDevice(id));
239+
}
240+
// if a device was not reused it should be invalidated
241+
for (X11GraphicsDevice gd : old.values()) {
242+
oldDevices.add(new WeakReference<>(gd));
243+
}
244+
// Need to notify old devices, in case the user hold the reference to it
245+
for (ListIterator<WeakReference<X11GraphicsDevice>> it =
246+
oldDevices.listIterator(); it.hasNext(); ) {
247+
X11GraphicsDevice gd = it.next().get();
248+
if (gd != null) {
249+
gd.invalidate(devices.get(mainScreen));
250+
gd.displayChanged();
251+
} else {
252+
// no more references to this device, remove it
253+
it.remove();
254+
}
255+
}
256+
}
257+
258+
@Override
259+
public synchronized GraphicsDevice getDefaultScreenDevice() {
260+
return devices.get(mainScreen);
261+
}
262+
263+
@Override
264+
public synchronized GraphicsDevice[] getScreenDevices() {
265+
return devices.values().toArray(new X11GraphicsDevice[0]);
266+
}
267+
268+
public synchronized GraphicsDevice getScreenDevice(int screen) {
269+
return devices.get(screen);
270+
}
271+
272+
@Override
273+
protected GraphicsDevice makeScreenDevice(int screennum) {
274+
throw new UnsupportedOperationException("This method is unused and" +
275+
"should not be called in this implementation");
198276
}
199277

200278
public boolean isDisplayLocal() {
@@ -289,15 +367,7 @@ public String getDefaultFontFaceName() {
289367
private static native boolean pRunningXinerama();
290368

291369
public boolean runningXinerama() {
292-
if (xinerState == null) {
293-
// pRunningXinerama() simply returns a global boolean variable,
294-
// so there is no need to synchronize here
295-
xinerState = Boolean.valueOf(pRunningXinerama());
296-
if (screenLog.isLoggable(PlatformLogger.Level.FINER)) {
297-
screenLog.finer("Running Xinerama: " + xinerState);
298-
}
299-
}
300-
return xinerState.booleanValue();
370+
return pRunningXinerama();
301371
}
302372

303373
/**

0 commit comments

Comments
 (0)