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:
Maxim Kartashev
2023-05-24 16:12:15 +04:00
parent faead95d98
commit 2626653c5d
13 changed files with 274 additions and 173 deletions

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);