JBR-5274 recreate CGraphicsDevice if it was changed.

- AWT code heavily relies on reference comparison when updating graphics devices & configurations, so we need to actually re-create CGraphicsDevice if it was changed.

- Also do not rely on graphicsConfig.getDefaultTransform() when firing `graphicsContextScaleTransform` property change, as graphics devices are mutable and returned default transform may change over time, e.g. when device is invalidated.
This commit is contained in:
Nikita Gubarkov
2023-03-29 21:44:08 +03:00
committed by jbrbot
parent 4266173fc4
commit 02860b3bbc
3 changed files with 48 additions and 11 deletions

View File

@@ -92,12 +92,14 @@ public final class CGraphicsDevice extends GraphicsDevice
}
}
// initializes default device state, might be redundant step since we
// call "displayChanged()" later anyway, but we do not want to leave the
// device in an inconsistent state after construction
// [JBR] we don't call displayChanged after creating a device, so call it here.
displayChanged();
}
int getDisplayID() {
return displayID;
}
/**
* Return a list of all configurations.
*/
@@ -175,6 +177,17 @@ public final class CGraphicsDevice extends GraphicsDevice
//TODO configs?
}
/**
* @return false if display parameters were changed, so we need to recreate the device.
*/
boolean updateDevice() {
int s = scale;
double xr = xResolution, yr = yResolution;
var b = bounds;
displayChanged();
return s == scale && xr == xResolution && yr == yResolution && b.equals(bounds);
}
public void displayParametersChanged() {
Insets newScreenInsets = nativeGetScreenInsets(displayID);
if (!newScreenInsets.equals(screenInsets)) {

View File

@@ -175,7 +175,8 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
*/
private void rebuildDevices() {
initDevices();
displayChanged();
// Do not notify devices, this was already done in initDevices.
displayChanger.notifyListeners();
}
/**
@@ -232,8 +233,17 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
displayIDs = new int[]{mainDisplayID};
}
for (int id : displayIDs) {
devices.put(id, old.containsKey(id) ? old.remove(id)
: new CGraphicsDevice(id));
old.compute(id, (i, d) -> {
if (d != null && d.updateDevice()) {
// Device didn't change -> reuse
devices.put(i, d);
return null;
} else {
// Device changed -> create new
devices.put(i, new CGraphicsDevice(i));
return d;
}
});
}
// fetch the main display again, the old value might be outdated
mainDisplayID = getMainDisplayID();
@@ -269,9 +279,12 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
}
private CGraphicsDevice getSimilarDevice(CGraphicsDevice old) {
CGraphicsDevice sameId = devices.get(old.getDisplayID());
if (sameId != null) {
return sameId;
}
for (CGraphicsDevice device : devices.values()) {
if (device.getBounds().equals(old.getBounds())) {
// for now we will use the bounds only
return device;
}
}

View File

@@ -351,6 +351,13 @@ public abstract class Component implements ImageObserver, MenuContainer,
*/
private transient volatile GraphicsConfiguration graphicsConfig;
/**
* Last observed value of {@code graphicsConfig.getDefaultTransform()}.
* Used for firing 'graphicsContextScaleTransform' property change,
* as values returned by {@link #graphicsConfig} may change over time.
*/
private transient volatile AffineTransform lastGraphicsConfigTransform;
/**
* A reference to a {@code BufferStrategy} object
* used to manipulate the buffers on this component.
@@ -1207,13 +1214,17 @@ public abstract class Component implements ImageObserver, MenuContainer,
return false;
}
AffineTransform tx = graphicsConfig != null ? graphicsConfig.getDefaultTransform() : new AffineTransform();
AffineTransform tx = lastGraphicsConfigTransform;
AffineTransform newTx = gc != null ? gc.getDefaultTransform() : new AffineTransform();
graphicsConfig = gc;
if (tx.getScaleX() != newTx.getScaleX() ||
tx.getScaleY() != newTx.getScaleY())
// We cannot rely on graphicsConfig.getDefaultTransform(),
// because its device might have been invalidated and now
// reports different scale than it did before.
if (!newTx.equals(lastGraphicsConfigTransform))
{
firePropertyChange("graphicsContextScaleTransform", tx, newTx);
lastGraphicsConfigTransform = newTx;
firePropertyChange("graphicsContextScaleTransform",
tx != null ? tx : new AffineTransform(), newTx);
}
ComponentPeer peer = this.peer;