mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-5658 Wayland: incorrect scaling of window content
The buffer scale is changed atomically with the size. WLGraphicsConfig made immutable and is re-created when scaling changes. WLGraphicsDevice is also re-created when its position changes.
This commit is contained in:
@@ -28,7 +28,6 @@ package sun.awt.wl;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.AWTAccessor.ComponentAccessor;
|
||||
import sun.awt.DisplayChangedListener;
|
||||
import sun.awt.PaintEventDispatcher;
|
||||
import sun.awt.event.IgnorePaintEvent;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
@@ -57,8 +56,8 @@ import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class WLComponentPeer implements ComponentPeer,
|
||||
DisplayChangedListener {
|
||||
public class WLComponentPeer implements ComponentPeer {
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLComponentPeer");
|
||||
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.wl.focus.WLComponentPeer");
|
||||
|
||||
private static final String appID = System.getProperty("sun.java.command");
|
||||
@@ -83,7 +82,6 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
};
|
||||
|
||||
private long nativePtr;
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLComponentPeer");
|
||||
protected final Component target;
|
||||
|
||||
// Graphics devices this top-level component is visible on
|
||||
@@ -119,12 +117,12 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
y = bounds.y;
|
||||
width = bounds.width;
|
||||
height = bounds.height;
|
||||
wlBufferScale = ((WLGraphicsConfig)target.getGraphicsConfiguration()).getScale();
|
||||
this.surfaceData = (WLSurfaceData) ((WLGraphicsConfig)target.getGraphicsConfiguration())
|
||||
.createSurfaceData(this);
|
||||
this.nativePtr = nativeCreateFrame();
|
||||
final WLGraphicsConfig config = (WLGraphicsConfig)target.getGraphicsConfiguration();
|
||||
wlBufferScale = config.getScale();
|
||||
surfaceData = (WLSurfaceData) config.createSurfaceData(this);
|
||||
nativePtr = nativeCreateFrame();
|
||||
paintArea = new WLRepaintArea();
|
||||
log.info("WLComponentPeer: target=" + target + " x=" + x + " y=" + y +
|
||||
log.fine("WLComponentPeer: target=" + target + " x=" + x + " y=" + y +
|
||||
" width=" + width + " height=" + height);
|
||||
// TODO
|
||||
// setup parent window for target
|
||||
@@ -146,7 +144,7 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
return background;
|
||||
}
|
||||
|
||||
public void postPaintEvent(Component target, int x, int y, int w, int h) {
|
||||
public void postPaintEvent(int x, int y, int w, int h) {
|
||||
PaintEvent event = PaintEventDispatcher.getPaintEventDispatcher().
|
||||
createPaintEvent(target, x, y, w, h);
|
||||
if (event != null) {
|
||||
@@ -157,7 +155,7 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
void postPaintEvent() {
|
||||
if (isVisible()) {
|
||||
synchronized (sizeLock) {
|
||||
postPaintEvent(getTarget(), 0, 0, width, height);
|
||||
postPaintEvent(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,8 +246,10 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
|
||||
void configureWLSurface() {
|
||||
synchronized (sizeLock) {
|
||||
surfaceData.revalidate(getBufferWidth(), getBufferHeight());
|
||||
performLocked(() -> nativeSetBufferScale(nativePtr, wlBufferScale));
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(String.format("%s is configured to %dx%d with %dx scale", this, getBufferWidth(), getBufferHeight(), getBufferScale()));
|
||||
}
|
||||
surfaceData.revalidate(getBufferWidth(), getBufferHeight(), getBufferScale());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +340,10 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
if (sizeChanged) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
surfaceData.revalidate(getBufferWidth(), getBufferHeight());
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(String.format("%s is resizing its buffer to %dx%d with %dx scale", this, getBufferWidth(), getBufferHeight(), getBufferScale()));
|
||||
}
|
||||
surfaceData.revalidate(getBufferWidth(), getBufferHeight(), getBufferScale());
|
||||
updateWindowGeometry();
|
||||
layout();
|
||||
|
||||
@@ -407,14 +410,14 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
|
||||
switch (e.getID()) {
|
||||
case PaintEvent.UPDATE -> {
|
||||
if (log.isLoggable(Level.INFO)) {
|
||||
log.info("WLCP coalescePaintEvent : UPDATE : add : x = " +
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("WLCP coalescePaintEvent : UPDATE : add : x = " +
|
||||
r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height);
|
||||
}
|
||||
}
|
||||
case PaintEvent.PAINT -> {
|
||||
if (log.isLoggable(Level.INFO)) {
|
||||
log.info("WLCP coalescePaintEvent : PAINT : add : x = " +
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("WLCP coalescePaintEvent : PAINT : add : x = " +
|
||||
r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height);
|
||||
}
|
||||
}
|
||||
@@ -478,7 +481,9 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
paintPending = false;
|
||||
// Fallthrough to next statement
|
||||
case PaintEvent.UPDATE:
|
||||
log.info("WLComponentPeer.handleEvent(AWTEvent): UPDATE " + this);
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("UPDATE " + this);
|
||||
}
|
||||
// Skip all painting while layouting and all UPDATEs
|
||||
// while waiting for native paint
|
||||
if (!isLayouting && !paintPending) {
|
||||
@@ -529,7 +534,9 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
}
|
||||
|
||||
public void endLayout() {
|
||||
log.info("WLComponentPeer.endLayout(): paintArea.isEmpty() " + paintArea.isEmpty());
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("WLComponentPeer.endLayout(): paintArea.isEmpty() " + paintArea.isEmpty());
|
||||
}
|
||||
if (!paintPending && !paintArea.isEmpty()
|
||||
&& !AWTAccessor.getComponentAccessor().getIgnoreRepaint(target)) {
|
||||
// if not waiting for native painting repaint damaged area
|
||||
@@ -723,7 +730,23 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
|
||||
@Override
|
||||
public boolean updateGraphicsData(GraphicsConfiguration gc) {
|
||||
throw new UnsupportedOperationException();
|
||||
final int newScale = ((WLGraphicsConfig)gc).getScale();
|
||||
|
||||
synchronized (sizeLock) {
|
||||
if (newScale != wlBufferScale) {
|
||||
wlBufferScale = newScale;
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(String.format("%s is updating buffer to %dx%d with %dx scale", this, getBufferWidth(), getBufferHeight(), wlBufferScale));
|
||||
}
|
||||
surfaceData.revalidate(getBufferWidth(), getBufferHeight(), wlBufferScale);
|
||||
postPaintEvent();
|
||||
}
|
||||
}
|
||||
|
||||
// Not sure what would need to have changed in Wayland's graphics configuration
|
||||
// to warrant destroying the peer and creating a new one from scratch.
|
||||
// So return "never recreate" here.
|
||||
return false;
|
||||
}
|
||||
|
||||
final void setFrameTitle(String title) {
|
||||
@@ -783,7 +806,6 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
private static native void nativeSetCursor(long pData);
|
||||
private static native long nativeGetPredefinedCursor(String name);
|
||||
private native void nativeShowWindowMenu(long ptr, int x, int y);
|
||||
private native void nativeSetBufferScale(long ptr, int scale);
|
||||
|
||||
static long getParentNativePtr(Component target) {
|
||||
Component parent = target.getParent();
|
||||
@@ -928,6 +950,10 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
final long wlSurfacePtr = getWLSurface(nativePtr);
|
||||
// TODO: this needs to be done only once after wlSetVisible(true)
|
||||
surfaceData.assignSurface(wlSurfacePtr);
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(String.format("%s configured to %dx%d", this, newWidth, newHeight));
|
||||
}
|
||||
|
||||
if (newWidth != 0 && newHeight != 0) performUnlocked(() ->target.setSize(newWidth, newHeight));
|
||||
if (newWidth == 0 && newHeight == 0) {
|
||||
// From xdg-shell.xml: "If the width or height arguments are zero,
|
||||
@@ -941,27 +967,22 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayChanged() {
|
||||
updateBufferScale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paletteChanged() {
|
||||
}
|
||||
|
||||
void notifyEnteredOutput(int wlOutputID) {
|
||||
// Called from native code whenever the corresponding wl_surface enters a new output
|
||||
synchronized (devices) {
|
||||
final WLGraphicsEnvironment ge = (WLGraphicsEnvironment)WLGraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
final WLGraphicsDevice gd = ge.notifySurfaceEnteredOutput(this, wlOutputID);
|
||||
if (gd != null) {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(this + " has entered " + gd);
|
||||
}
|
||||
devices.add(gd);
|
||||
updateBufferScale();
|
||||
} else {
|
||||
log.severe("Entered output " + wlOutputID + " for which WLGraphicsEnvironment has no record");
|
||||
}
|
||||
}
|
||||
|
||||
checkIfOnNewScreen();
|
||||
}
|
||||
|
||||
void notifyLeftOutput(int wlOutputID) {
|
||||
@@ -970,34 +991,47 @@ public class WLComponentPeer implements ComponentPeer,
|
||||
final WLGraphicsEnvironment ge = (WLGraphicsEnvironment)WLGraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
final WLGraphicsDevice gd = ge.notifySurfaceLeftOutput(this, wlOutputID);
|
||||
if (gd != null) {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(this + " has left " + gd);
|
||||
}
|
||||
devices.remove(gd);
|
||||
updateBufferScale();
|
||||
} else {
|
||||
log.severe("Left output " + wlOutputID + " for which WLGraphicsEnvironment has no record");
|
||||
}
|
||||
}
|
||||
|
||||
checkIfOnNewScreen();
|
||||
}
|
||||
|
||||
private void updateBufferScale() {
|
||||
if (devices.isEmpty()) return; // no devices, no update
|
||||
|
||||
int newScale = 1;
|
||||
private WLGraphicsDevice getGraphicsDevice() {
|
||||
int scale = 0;
|
||||
WLGraphicsDevice theDevice = null;
|
||||
// AFAIK there's no way of knowing which WLGraphicsDevice is displaying
|
||||
// the largest portion of this component, so we can't base scaling on that.
|
||||
// Choose maximum scale simply to be deterministic.
|
||||
for (WLGraphicsDevice gd : devices) {
|
||||
if (gd.getScale() > newScale) {
|
||||
newScale = gd.getScale();
|
||||
// the largest portion of this component, so choose the first in the ordered list
|
||||
// of devices with the maximum scale simply to be deterministic.
|
||||
// NB: devices are added to the end of the list when we enter the corresponding
|
||||
// Wayland's output and are removed as soon as we have left.
|
||||
synchronized (devices) {
|
||||
for (WLGraphicsDevice gd : devices) {
|
||||
if (gd.getScale() > scale) {
|
||||
scale = gd.getScale();
|
||||
theDevice = gd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (sizeLock) {
|
||||
if (newScale != wlBufferScale) {
|
||||
wlBufferScale = newScale;
|
||||
surfaceData.revalidate(getBufferWidth(), getBufferHeight());
|
||||
performLocked(() -> nativeSetBufferScale(nativePtr, wlBufferScale));
|
||||
postPaintEvent();
|
||||
return theDevice;
|
||||
}
|
||||
|
||||
private void checkIfOnNewScreen() {
|
||||
final WLGraphicsDevice newDevice = getGraphicsDevice();
|
||||
if (newDevice != null) { // could be null when screens are being reconfigured
|
||||
final GraphicsConfiguration gc = newDevice.getDefaultConfiguration();
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine(this + " is on (possibly) new device " + newDevice);
|
||||
}
|
||||
var acc = AWTAccessor.getComponentAccessor();
|
||||
acc.setGraphicsConfiguration(target, gc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
if (decoration != null) {
|
||||
final Rectangle bounds = decoration.getBounds();
|
||||
decoration.markRepaintNeeded();
|
||||
postPaintEvent(getTarget(), bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
postPaintEvent(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,19 +13,19 @@ import sun.java2d.wl.WLSurfaceData;
|
||||
|
||||
public class WLGraphicsConfig extends GraphicsConfiguration {
|
||||
private final WLGraphicsDevice device;
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final int scale;
|
||||
|
||||
private final Object dataLock = new Object();
|
||||
|
||||
private final Rectangle bounds = new Rectangle(800, 600);
|
||||
|
||||
// This is Wayland scale for the use with wl_buffers only.
|
||||
// From wayland.xml, wl_surface.set_buffer_scale request:
|
||||
// "It is intended that you pick the same buffer scale as the scale of the
|
||||
// output that the surface is displayed on."
|
||||
private int wlBufferScale = 1;
|
||||
|
||||
public WLGraphicsConfig(WLGraphicsDevice device) {
|
||||
public WLGraphicsConfig(WLGraphicsDevice device, int width, int height, int scale) {
|
||||
this.device = device;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public boolean differsFrom(int width, int height, int scale) {
|
||||
return width != this.width || height != this.height || scale != this.scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,9 +72,7 @@ public class WLGraphicsConfig extends GraphicsConfiguration {
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
synchronized (dataLock) {
|
||||
return bounds;
|
||||
}
|
||||
return new Rectangle(width, height);
|
||||
}
|
||||
|
||||
public SurfaceType getSurfaceType() {
|
||||
@@ -85,16 +83,12 @@ public class WLGraphicsConfig extends GraphicsConfiguration {
|
||||
return WLSurfaceData.createData(peer);
|
||||
}
|
||||
|
||||
int getScale() {
|
||||
synchronized (dataLock) {
|
||||
return wlBufferScale;
|
||||
}
|
||||
public int getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
void update(int width, int height, int scale) {
|
||||
synchronized (dataLock) {
|
||||
this.wlBufferScale = scale;
|
||||
bounds.setSize(width, height);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("WLGraphicsConfig: %dx%d %dx scale", width, height, scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,91 @@
|
||||
package sun.awt.wl;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.DisplayChangedListener;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class WLGraphicsDevice extends GraphicsDevice implements DisplayChangedListener {
|
||||
private final int wlID; // ID of wl_output object received from Wayland
|
||||
private String name;
|
||||
private int x;
|
||||
private int y;
|
||||
/**
|
||||
* Corresponds to Wayland's output and is identified by its wlID and x, y coordinates
|
||||
* in the multi-monitor setup. Whenever those change, this device is re-created.
|
||||
*/
|
||||
public class WLGraphicsDevice extends GraphicsDevice {
|
||||
/**
|
||||
* ID of the corresponding wl_output object received from Wayland.
|
||||
*/
|
||||
private volatile int wlID; // only changes when the device gets invalidated
|
||||
|
||||
private final java.util.List<WLComponentPeer> peers = new ArrayList<>();
|
||||
private final WLGraphicsConfig config = new WLGraphicsConfig(this);
|
||||
/**
|
||||
* Some human-readable name of the device that came from Wayland.
|
||||
* NOT considered part of device's identity.
|
||||
*/
|
||||
private volatile String name;
|
||||
|
||||
public WLGraphicsDevice(int id) {
|
||||
/**
|
||||
* The horizontal location of this device in the multi-monitor configuration.
|
||||
*/
|
||||
private volatile int x; // only changes when the device gets invalidated
|
||||
|
||||
/**
|
||||
* The vertical location of this device in the multi-monitor configuration.
|
||||
*/
|
||||
private volatile int y; // only changes when the device gets invalidated
|
||||
|
||||
private volatile WLGraphicsConfig config = null;
|
||||
|
||||
private WLGraphicsDevice(int id, int x, int y) {
|
||||
this.wlID = id;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
int getWLID() {
|
||||
int getID() {
|
||||
return wlID;
|
||||
}
|
||||
|
||||
void updateConfiguration(String name, int x, int y, int width, int height, int scale) {
|
||||
void updateConfiguration(String name, int width, int height, int scale) {
|
||||
this.name = name == null ? "wl_output." + wlID : name;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
config.update(width, height, scale);
|
||||
if (config == null || config.differsFrom(width, height, scale)) {
|
||||
// It is necessary to create a new object whenever config changes as its
|
||||
// identity is used to detect changes in scale, among other things.
|
||||
config = new WLGraphicsConfig(this, width, height, scale);
|
||||
}
|
||||
}
|
||||
|
||||
void updateConfiguration(WLGraphicsDevice gd) {
|
||||
final Rectangle bounds = config.getBounds();
|
||||
updateConfiguration(gd.name, gd.x, gd.y, bounds.width, bounds.height, config.getScale());
|
||||
/**
|
||||
* Changes all aspects of this device including its identity to be that of the given
|
||||
* device. Only used for devices that are no longer physically present, but references
|
||||
* to which may still exist in the program.
|
||||
*/
|
||||
void invalidate(WLGraphicsDevice similarDevice) {
|
||||
this.wlID = similarDevice.wlID;
|
||||
this.x = similarDevice.x;
|
||||
this.y = similarDevice.y;
|
||||
|
||||
final int newScale = similarDevice.getScale();
|
||||
final Rectangle newBounds = similarDevice.config.getBounds();
|
||||
updateConfiguration(similarDevice.name, newBounds.width, newBounds.height, newScale);
|
||||
}
|
||||
|
||||
public static WLGraphicsDevice createWithConfiguration(int id, String name, int x, int y, int width, int height, int scale) {
|
||||
final WLGraphicsDevice device = new WLGraphicsDevice(id, x, y);
|
||||
device.updateConfiguration(name, width, height, scale);
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the identity of this device with the given attributes
|
||||
* and returns true iff the attributes identify the same device.
|
||||
*/
|
||||
public boolean isSameDeviceAs(int wlID, int x, int y) {
|
||||
return this.wlID == wlID && this.x == x && this.y == y;
|
||||
}
|
||||
|
||||
public boolean hasSameNameAs(WLGraphicsDevice otherDevice) {
|
||||
return name != null && otherDevice.name != null && name.equals(otherDevice.name);
|
||||
}
|
||||
|
||||
public boolean hasSameSizeAs(WLGraphicsDevice modelDevice) {
|
||||
return config != null && modelDevice.config != null && config.getBounds().equals(modelDevice.config.getBounds());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,17 +139,6 @@ public class WLGraphicsDevice extends GraphicsDevice implements DisplayChangedLi
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayChanged() {
|
||||
synchronized (peers) {
|
||||
peers.forEach(WLComponentPeer::displayChanged);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paletteChanged() {
|
||||
}
|
||||
|
||||
private void enterFullScreenExclusive(Window w) {
|
||||
WLComponentPeer peer = AWTAccessor.getComponentAccessor().getPeer(w);
|
||||
if (peer != null) {
|
||||
@@ -112,14 +154,17 @@ public class WLGraphicsDevice extends GraphicsDevice implements DisplayChangedLi
|
||||
}
|
||||
|
||||
public void addWindow(WLComponentPeer peer) {
|
||||
synchronized (peers) {
|
||||
peers.add(peer);
|
||||
}
|
||||
// TODO: may be needed to keep track of windows on the device to notify
|
||||
// them of display change events, perhaps.
|
||||
}
|
||||
|
||||
public void removeWindow(WLComponentPeer peer) {
|
||||
synchronized (peers) {
|
||||
peers.remove(peer);
|
||||
}
|
||||
// TODO: may be needed to keep track of windows on the device to notify
|
||||
// them of display change events, perhaps.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("WLGraphicsDevice: id=%d at (%d, %d) with %s", wlID, x, y, config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package sun.awt.wl;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.Optional;
|
||||
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.java2d.SurfaceManagerFactory;
|
||||
import sun.java2d.UnixSurfaceManagerFactory;
|
||||
@@ -21,8 +21,8 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
static {
|
||||
SurfaceManagerFactory.setInstance(new UnixSurfaceManagerFactory());
|
||||
vkwlAvailable = initVKWL();
|
||||
if (log.isLoggable(Level.INFO)) {
|
||||
log.info("Vulkan rendering available: " + (vkwlAvailable?"YES":"NO"));
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("Vulkan rendering available: " + (vkwlAvailable?"YES":"NO"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,38 +68,80 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
int subpixel, int transform, int scale) {
|
||||
// Called from native code whenever a new output appears or an existing one changes its properties
|
||||
// NB: initially called during WLToolkit.initIDs() on the main thread; later on EDT.
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine(String.format("Output configured id=%d at (%d, %d) %dx%d %dx scale", wlID, x, y, width, height, scale));
|
||||
}
|
||||
|
||||
synchronized (devices) {
|
||||
boolean newOutput = true;
|
||||
for (final WLGraphicsDevice gd : devices) {
|
||||
if (gd.getWLID() == wlID) {
|
||||
gd.updateConfiguration(name, x, y, width, height, scale);
|
||||
for (int i = 0; i < devices.size(); i++) {
|
||||
final WLGraphicsDevice gd = devices.get(i);
|
||||
if (gd.getID() == wlID) {
|
||||
newOutput = false;
|
||||
if (gd.isSameDeviceAs(wlID, x, y)) {
|
||||
gd.updateConfiguration(name, width, height, scale);
|
||||
} else {
|
||||
final WLGraphicsDevice updatedDevice = WLGraphicsDevice.createWithConfiguration(wlID, name, x, y, width, height, scale);
|
||||
devices.set(i, updatedDevice);
|
||||
gd.invalidate(updatedDevice);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newOutput) {
|
||||
final WLGraphicsDevice gd = new WLGraphicsDevice(wlID);
|
||||
gd.updateConfiguration(name, x, y, width, height, scale);
|
||||
final WLGraphicsDevice gd = WLGraphicsDevice.createWithConfiguration(wlID, name, x, y, width, height, scale);
|
||||
devices.add(gd);
|
||||
}
|
||||
}
|
||||
displayChanged();
|
||||
|
||||
// Skip notification during the initial configuration events
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
displayChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private WLGraphicsDevice getSimilarDevice(WLGraphicsDevice modelDevice) {
|
||||
WLGraphicsDevice similarDevice = devices.isEmpty() ? null : devices.getFirst();
|
||||
for (WLGraphicsDevice device : devices) {
|
||||
if (device.hasSameNameAs(modelDevice)) {
|
||||
similarDevice = device;
|
||||
break;
|
||||
} else if (device.hasSameSizeAs(modelDevice)) {
|
||||
similarDevice = device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return similarDevice;
|
||||
}
|
||||
|
||||
private void notifyOutputDestroyed(int wlID) {
|
||||
// Called from native code whenever one of the outputs is no longer available.
|
||||
// All surfaces that were partly visible on that output should have
|
||||
// notifySurfaceLeftOutput().
|
||||
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine(String.format("Output destroyed id=%d", wlID));
|
||||
}
|
||||
// NB: id may *not* be that of any output; if so, just ignore this event.
|
||||
synchronized (devices) {
|
||||
devices.removeIf(gd -> gd.getWLID() == wlID);
|
||||
final Optional<WLGraphicsDevice> deviceOptional = devices.stream()
|
||||
.filter(device -> device.getID() == wlID)
|
||||
.findFirst();
|
||||
if (deviceOptional.isPresent()) {
|
||||
final WLGraphicsDevice destroyedDevice = deviceOptional.get();
|
||||
devices.remove(destroyedDevice);
|
||||
final WLGraphicsDevice similarDevice = getSimilarDevice(destroyedDevice);
|
||||
if (similarDevice != null) destroyedDevice.invalidate(similarDevice);
|
||||
}
|
||||
}
|
||||
|
||||
displayChanged();
|
||||
}
|
||||
|
||||
WLGraphicsDevice notifySurfaceEnteredOutput(WLComponentPeer wlComponentPeer, int wlOutputID) {
|
||||
synchronized (devices) {
|
||||
for (WLGraphicsDevice gd : devices) {
|
||||
if (gd.getWLID() == wlOutputID) {
|
||||
if (gd.getID() == wlOutputID) {
|
||||
gd.addWindow(wlComponentPeer);
|
||||
return gd;
|
||||
}
|
||||
@@ -111,7 +153,7 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
WLGraphicsDevice notifySurfaceLeftOutput(WLComponentPeer wlComponentPeer, int wlOutputID) {
|
||||
synchronized (devices) {
|
||||
for (WLGraphicsDevice gd : devices) {
|
||||
if (gd.getWLID() == wlOutputID) {
|
||||
if (gd.getID() == wlOutputID) {
|
||||
gd.removeWindow(wlComponentPeer);
|
||||
return gd;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.wl.WLComponentPeer;
|
||||
@@ -18,44 +19,29 @@ public class WLSurfaceData extends SurfaceData {
|
||||
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.java2d.wl.WLSurfaceData");
|
||||
private final WLComponentPeer peer;
|
||||
private final WLGraphicsConfig graphicsConfig;
|
||||
private final int depth;
|
||||
|
||||
public native void assignSurface(long surfacePtr);
|
||||
|
||||
protected native void initOps(int width, int height, int backgroundRGB);
|
||||
protected native void initOps(int width, int height, int scale, int backgroundRGB);
|
||||
|
||||
protected WLSurfaceData(WLComponentPeer peer,
|
||||
WLGraphicsConfig gc,
|
||||
SurfaceType sType,
|
||||
ColorModel cm) {
|
||||
super(sType, cm);
|
||||
protected WLSurfaceData(WLComponentPeer peer) {
|
||||
super(((WLGraphicsConfig)peer.getGraphicsConfiguration()).getSurfaceType(),
|
||||
peer.getGraphicsConfiguration().getColorModel());
|
||||
this.peer = peer;
|
||||
this.graphicsConfig = gc;
|
||||
this.depth = cm.getPixelSize();
|
||||
final int backgroundRGB = peer.getBackground() != null
|
||||
? peer.getBackground().getRGB()
|
||||
: 0;
|
||||
initOps(peer.getBufferWidth(), peer.getBufferHeight(), backgroundRGB);
|
||||
final int scale = ((WLGraphicsConfig)peer.getGraphicsConfiguration()).getScale();
|
||||
initOps(peer.getBufferWidth(), peer.getBufferHeight(), scale, backgroundRGB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for instantiating a Window SurfaceData
|
||||
*/
|
||||
public static WLSurfaceData createData(WLComponentPeer peer) {
|
||||
WLGraphicsConfig gc = getGC(peer);
|
||||
return new WLSurfaceData(peer, gc, gc.getSurfaceType(), peer.getColorModel());
|
||||
}
|
||||
if (peer == null) throw new UnsupportedOperationException("Surface without the corresponding window peer is not supported");
|
||||
|
||||
public static WLGraphicsConfig getGC(WLComponentPeer peer) {
|
||||
if (peer != null) {
|
||||
return (WLGraphicsConfig) peer.getGraphicsConfiguration();
|
||||
} else {
|
||||
GraphicsEnvironment env =
|
||||
GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
GraphicsDevice gd = env.getDefaultScreenDevice();
|
||||
return (WLGraphicsConfig) gd.getDefaultConfiguration();
|
||||
}
|
||||
return new WLSurfaceData(peer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,7 +51,7 @@ public class WLSurfaceData extends SurfaceData {
|
||||
|
||||
@Override
|
||||
public GraphicsConfiguration getDeviceConfiguration() {
|
||||
return graphicsConfig;
|
||||
return peer.getGraphicsConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,7 +81,7 @@ public class WLSurfaceData extends SurfaceData {
|
||||
throw new UnsupportedOperationException("SurfaceData not associated with a Component is not supported");
|
||||
}
|
||||
|
||||
public native void revalidate(int width, int height);
|
||||
public native void revalidate(int width, int height, int scale);
|
||||
|
||||
public native void commitToServer();
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
extern struct wl_shm_pool *CreateShmPool(int32_t size, const char *name, void **data); // defined in WLToolkit.c
|
||||
extern struct wl_shm_pool *CreateShmPool(size_t size, const char *name, void **data); // defined in WLToolkit.c
|
||||
|
||||
static bool
|
||||
BufferShowToWayland(WLSurfaceBufferManager * manager);
|
||||
@@ -242,6 +242,7 @@ struct WLSurfaceBufferManager {
|
||||
WLDrawBuffer bufferForDraw; // only accessed under drawLock
|
||||
jint width; // only accessed under drawLock
|
||||
jint height; // only accessed under drawLock
|
||||
jint scale; // only accessed under drawLock
|
||||
bool sizeChanged; // only accessed under drawLock
|
||||
};
|
||||
|
||||
@@ -392,6 +393,7 @@ SendToWayland(WLSurfaceBufferManager * manager)
|
||||
manager->bufferForShow.state = WL_BUFFER_LOCKED;
|
||||
// wl_buffer_listener will release bufferForShow when Wayland's done with it
|
||||
wl_surface_attach(manager->wlSurface, manager->bufferForShow.wlBuffer, 0, 0);
|
||||
wl_surface_set_buffer_scale(manager->wlSurface, manager->scale);
|
||||
|
||||
DamageList_SendAll(manager->bufferForShow.damageList, manager->wlSurface);
|
||||
DamageList_FreeAll(manager->bufferForShow.damageList);
|
||||
@@ -530,7 +532,7 @@ SurfaceBufferCreate(WLSurfaceBufferManager * manager, size_t newSize)
|
||||
memset(manager->bufferForShow.data, 0, newSize);
|
||||
}
|
||||
|
||||
const int32_t stride = manager->width * sizeof(pixel_t);
|
||||
const int32_t stride = (int32_t)(manager->width * sizeof(pixel_t));
|
||||
manager->bufferForShow.wlBuffer = wl_shm_pool_create_buffer(manager->bufferForShow.wlPool, 0,
|
||||
manager->width,
|
||||
manager->height,
|
||||
@@ -601,7 +603,7 @@ DrawBufferDestroy(WLSurfaceBufferManager * manager)
|
||||
}
|
||||
|
||||
WLSurfaceBufferManager *
|
||||
WLSBM_Create(jint width, jint height, jint rgb)
|
||||
WLSBM_Create(jint width, jint height, jint scale, jint rgb)
|
||||
{
|
||||
WLSurfaceBufferManager * manager = calloc(1, sizeof(WLSurfaceBufferManager));
|
||||
if (!manager) {
|
||||
@@ -610,6 +612,7 @@ WLSBM_Create(jint width, jint height, jint rgb)
|
||||
|
||||
manager->width = width;
|
||||
manager->height = height;
|
||||
manager->scale = scale;
|
||||
manager->backgroundRGB = rgb;
|
||||
|
||||
pthread_mutex_init(&manager->showLock, NULL);
|
||||
@@ -751,14 +754,15 @@ WLSB_DataGet(WLDrawBuffer * buffer)
|
||||
}
|
||||
|
||||
void
|
||||
WLSBM_SizeChangeTo(WLSurfaceBufferManager * manager, jint width, jint height)
|
||||
WLSBM_SizeChangeTo(WLSurfaceBufferManager * manager, jint width, jint height, jint scale)
|
||||
{
|
||||
MUTEX_LOCK(manager->drawLock);
|
||||
|
||||
if (manager->width != width || manager->height != height) {
|
||||
const bool size_changed = manager->width != width || manager->height != height;
|
||||
if (size_changed) {
|
||||
DrawBufferDestroy(manager);
|
||||
|
||||
manager->width = width;
|
||||
manager->width = width;
|
||||
manager->height = height;
|
||||
manager->sizeChanged = true;
|
||||
|
||||
@@ -766,6 +770,10 @@ WLSBM_SizeChangeTo(WLSurfaceBufferManager * manager, jint width, jint height)
|
||||
ShowFrameNumbers(manager, "WLSBM_SizeChangeTo %dx%d", width, height);
|
||||
}
|
||||
|
||||
if (manager->scale != scale) {
|
||||
manager->scale = scale;
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(manager->drawLock);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ typedef uint32_t pixel_t;
|
||||
* the drawing to displaying buffer, synchronization, and sending
|
||||
* the appropriate notifications to Wayland.
|
||||
*/
|
||||
WLSurfaceBufferManager * WLSBM_Create(jint width, jint height, jint rgb);
|
||||
WLSurfaceBufferManager * WLSBM_Create(jint width, jint height, jint scale, jint rgb);
|
||||
|
||||
/**
|
||||
* Free all resources allocated for the WayLand Surface Buffer Manager,
|
||||
@@ -100,7 +100,7 @@ jint WLSBM_HeightGet(WLSurfaceBufferManager *);
|
||||
* displays things will change later, but before the changes in drawing buffer
|
||||
* are propagated to the display buffer.
|
||||
*/
|
||||
void WLSBM_SizeChangeTo(WLSurfaceBufferManager *, jint width, jint height);
|
||||
void WLSBM_SizeChangeTo(WLSurfaceBufferManager *, jint width, jint height, jint scale);
|
||||
|
||||
/**
|
||||
* Returns a buffer managed by the WayLand Surface Buffer Manager
|
||||
|
||||
@@ -107,7 +107,7 @@ Java_sun_java2d_wl_WLSurfaceData_commitToServer(JNIEnv *env, jobject wsd)
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_wl_WLSurfaceData_revalidate(JNIEnv *env, jobject wsd,
|
||||
jint width, jint height)
|
||||
jint width, jint height, jint scale)
|
||||
{
|
||||
#ifndef HEADLESS
|
||||
J2dTrace2(J2D_TRACE_INFO, "WLSurfaceData_revalidate to size %d x %d\n", width, height);
|
||||
@@ -116,7 +116,7 @@ Java_sun_java2d_wl_WLSurfaceData_revalidate(JNIEnv *env, jobject wsd,
|
||||
return;
|
||||
}
|
||||
|
||||
WLSBM_SizeChangeTo(wsdo->bufferManager, width, height);
|
||||
WLSBM_SizeChangeTo(wsdo->bufferManager, width, height, scale);
|
||||
#endif /* !HEADLESS */
|
||||
}
|
||||
|
||||
@@ -229,6 +229,7 @@ JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_wl_WLSurfaceData_initOps(JNIEnv *env, jobject wsd,
|
||||
jint width,
|
||||
jint height,
|
||||
jint scale,
|
||||
jint backgroundRGB)
|
||||
{
|
||||
#ifndef HEADLESS
|
||||
@@ -252,7 +253,7 @@ Java_sun_java2d_wl_WLSurfaceData_initOps(JNIEnv *env, jobject wsd,
|
||||
wsdo->sdOps.Unlock = WLSD_Unlock;
|
||||
wsdo->sdOps.GetRasInfo = WLSD_GetRasInfo;
|
||||
wsdo->sdOps.Dispose = WLSD_Dispose;
|
||||
wsdo->bufferManager = WLSBM_Create(width, height, backgroundRGB);
|
||||
wsdo->bufferManager = WLSBM_Create(width, height, backgroundRGB, scale);
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
// Recursive mutex is required because blit can be done with both source
|
||||
|
||||
@@ -492,12 +492,3 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeShowWindowMenu
|
||||
xdg_toplevel_show_window_menu(frame->xdg_toplevel, wl_seat, last_mouse_pressed_serial, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetBufferScale
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jint scale)
|
||||
{
|
||||
struct WLFrame *frame = jlong_to_ptr(ptr);
|
||||
if (frame->wl_surface) {
|
||||
wl_surface_set_buffer_scale(frame->wl_surface, scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ struct wl_event_queue *robot_queue;
|
||||
|
||||
#ifndef HEADLESS
|
||||
static struct wl_buffer*
|
||||
allocate_buffer(JNIEnv *env, int width, int height, uint32_t **buffer_data, int* size);
|
||||
allocate_buffer(JNIEnv *env, int width, int height, uint32_t **buffer_data, size_t* size);
|
||||
#endif
|
||||
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
@@ -258,7 +258,7 @@ Java_sun_awt_wl_WLRobotPeer_getRGBPixelsImpl
|
||||
}
|
||||
|
||||
uint32_t *buffer_data;
|
||||
int buffer_size_in_bytes;
|
||||
size_t buffer_size_in_bytes;
|
||||
struct wl_buffer *buffer = allocate_buffer(env, width, height, &buffer_data, &buffer_size_in_bytes);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
@@ -377,13 +377,13 @@ struct wakefield_listener wakefield_listener = {
|
||||
#ifndef HEADLESS
|
||||
|
||||
static struct wl_buffer*
|
||||
allocate_buffer(JNIEnv *env, int width, int height, uint32_t **buffer_data, int* size)
|
||||
allocate_buffer(JNIEnv *env, int width, int height, uint32_t **buffer_data, size_t* size)
|
||||
{
|
||||
const int stride = width * 4;
|
||||
*size = height * stride;
|
||||
*buffer_data = NULL;
|
||||
|
||||
if (*size <= 0) {
|
||||
if (*size == 0) {
|
||||
JNU_ThrowByName(env, "java/awt/AWTError", "buffer size overflow");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1282,7 +1282,7 @@ AllocateSharedMemoryFile(size_t size, const char* baseName) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct wl_shm_pool *CreateShmPool(int32_t size, const char *name, void **data) {
|
||||
struct wl_shm_pool *CreateShmPool(size_t size, const char *name, void **data) {
|
||||
if (size <= 0)
|
||||
return NULL;
|
||||
int poolFD = AllocateSharedMemoryFile(size, name);
|
||||
|
||||
@@ -57,4 +57,4 @@ JNIEnv *getEnv();
|
||||
|
||||
int wl_flush_to_server(JNIEnv* env);
|
||||
|
||||
struct wl_shm_pool *CreateShmPool(int32_t size, const char *name, void **data);
|
||||
struct wl_shm_pool *CreateShmPool(size_t size, const char *name, void **data);
|
||||
|
||||
Reference in New Issue
Block a user