Skip to content

Commit

Permalink
JBR-7969 Wayland: some popups misplaced when maximized with fractiona…
Browse files Browse the repository at this point in the history
…l scale
  • Loading branch information
mkartashev authored and jbrbot committed Dec 2, 2024
1 parent 67d6625 commit fc56ec0
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 38 deletions.
1 change: 1 addition & 0 deletions make/modules/java.desktop/gensrc/GensrcWayland.gmk
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ WAYLAND_BASIC_PROTOCOL_FILES := \
$(WAYLAND_PROTOCOLS_ROOT)/stable/xdg-shell/xdg-shell.xml \
$(WAYLAND_PROTOCOLS_ROOT)/staging/xdg-activation/xdg-activation-v1.xml \
$(WAYLAND_PROTOCOLS_ROOT)/unstable/primary-selection/primary-selection-unstable-v1.xml \
$(WAYLAND_PROTOCOLS_ROOT)/unstable/xdg-output/xdg-output-unstable-v1.xml \
$(GTK_SHELL1_PROTOCOL_PATH) \
#

Expand Down
23 changes: 18 additions & 5 deletions src/java.desktop/unix/classes/sun/awt/wl/WLGraphicsConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,27 @@ public abstract class WLGraphicsConfig extends GraphicsConfiguration {
private final WLGraphicsDevice device;
private final int x;
private final int y;
private final int xLogical; // logical (scaled) horizontal location; optional, could be zero
private final int yLogical; // logical (scaled) vertical location; optional, could be zero
private final int width;
private final int height;
private final int widthLogical; // logical (scaled) width; optional, could be zero
private final int heightLogical;// logical (scaled) height; optional, could be zero
private final int displayScale; // as reported by Wayland
private final double effectiveScale; // as enforced by Java

protected WLGraphicsConfig(WLGraphicsDevice device, int x, int y, int width, int height, int displayScale) {
protected WLGraphicsConfig(WLGraphicsDevice device, int x, int y, int xLogical, int yLogical,
int width, int height, int widthLogical, int heightLogical,
int displayScale) {
this.device = device;
this.x = x;
this.y = y;
this.xLogical = xLogical;
this.yLogical = yLogical;
this.width = width;
this.height = height;
this.widthLogical = widthLogical;
this.heightLogical = heightLogical;
this.displayScale = displayScale;
this.effectiveScale = WLGraphicsEnvironment.effectiveScaleFrom(displayScale);
}
Expand Down Expand Up @@ -86,10 +96,13 @@ public AffineTransform getNormalizingTransform() {

@Override
public Rectangle getBounds() {
// NB: despite the claims of GraphicsConfiguration.getBounds()'s javadoc,
// the value returned is expected to be in user-space coordinates,
// same as windows sizes, offsets, components' coordinates, etc.
return new Rectangle(x, y, (int) (width / effectiveScale), (int) (height / effectiveScale));
return (widthLogical > 0 && heightLogical > 0)
? new Rectangle(xLogical, yLogical, widthLogical, heightLogical)
: new Rectangle(x, y, width, height);
}

public Rectangle getRealBounds() {
return new Rectangle(x, y, width, height);
}

/**
Expand Down
36 changes: 22 additions & 14 deletions src/java.desktop/unix/classes/sun/awt/wl/WLGraphicsDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ public class WLGraphicsDevice extends GraphicsDevice {
*/
private volatile int y; // only changes when the device gets invalidated

private volatile int xLogical; // logical (scaled) horizontal location; optional, could be zero
private volatile int yLogical; // logical (scaled) vertical location; optional, could be zero

private final int widthMm;
private final int heightMm;

Expand All @@ -78,10 +81,12 @@ public class WLGraphicsDevice extends GraphicsDevice {
// and get their graphics configuration from it
private final Set<WLComponentPeer> toplevels = new HashSet<>(); // guarded by 'this'

private WLGraphicsDevice(int id, int x, int y, int widthMm, int heightMm) {
private WLGraphicsDevice(int id, int x, int y, int xLogical, int yLogical, int widthMm, int heightMm) {
this.wlID = id;
this.x = x;
this.y = y;
this.xLogical = xLogical;
this.yLogical = yLogical;
this.widthMm = widthMm;
this.heightMm = heightMm;
}
Expand All @@ -90,7 +95,7 @@ int getID() {
return wlID;
}

void updateConfiguration(String name, int width, int height, int scale) {
void updateConfiguration(String name, int width, int height, int widthLogical, int heightLogical, int scale) {
this.name = name;

WLGraphicsConfig config = defaultConfig;
Expand All @@ -101,16 +106,16 @@ void updateConfiguration(String name, int width, int height, int 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.
if (VKInstance.isVulkanEnabled()) {
newDefaultConfig = WLVKGraphicsConfig.getConfig(this, x, y, width, height, scale);
newDefaultConfig = WLVKGraphicsConfig.getConfig(this, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale);
newConfigs = new GraphicsConfiguration[1];
newConfigs[0] = newDefaultConfig;
} else {
// TODO: Actually, Wayland may support a lot more shared memory buffer configurations, need to
// subscribe to the wl_shm:format event and get the list from there.
newDefaultConfig = WLSMGraphicsConfig.getConfig(this, x, y, width, height, scale, false);
newDefaultConfig = WLSMGraphicsConfig.getConfig(this, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale, false);
newConfigs = new GraphicsConfiguration[2];
newConfigs[0] = newDefaultConfig;
newConfigs[1] = WLSMGraphicsConfig.getConfig(this, x, y, width, height, scale, true);
newConfigs[1] = WLSMGraphicsConfig.getConfig(this, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale, true);
}

configs = newConfigs;
Expand Down Expand Up @@ -145,28 +150,31 @@ void invalidate(WLGraphicsDevice similarDevice) {
this.wlID = similarDevice.wlID;
this.x = similarDevice.x;
this.y = similarDevice.y;
this.xLogical = similarDevice.xLogical;
this.yLogical = similarDevice.yLogical;

int newScale = similarDevice.getDisplayScale();
Rectangle newBounds = similarDevice.defaultConfig.getBounds();
updateConfiguration(similarDevice.name, newBounds.width, newBounds.height, newScale);
Rectangle newRealBounds = similarDevice.defaultConfig.getRealBounds();
updateConfiguration(similarDevice.name, newRealBounds.width, newRealBounds.height, newBounds.width, newBounds.height, newScale);
}

public static WLGraphicsDevice createWithConfiguration(int id, String name,
int x, int y,
int width, int height,
int x, int y, int xLogical, int yLogical,
int width, int height, int widthLogical, int heightLogical,
int widthMm, int heightMm,
int scale) {
WLGraphicsDevice device = new WLGraphicsDevice(id, x, y, widthMm, heightMm);
device.updateConfiguration(name, width, height, scale);
WLGraphicsDevice device = new WLGraphicsDevice(id, x, y, xLogical, yLogical, widthMm, heightMm);
device.updateConfiguration(name, width, height, widthLogical, heightLogical, scale);
return device;
}

/**
* Compares the identity of this device with the given attributes
* and returns true iff the attributes identify the same device.
*/
boolean isSameDeviceAs(int wlID, int x, int y) {
return this.wlID == wlID && this.x == x && this.y == y;
boolean isSameDeviceAs(int wlID, int x, int y, int xLogical, int yLogical) {
return this.wlID == wlID && this.x == x && this.y == y && this.xLogical == xLogical && this.yLogical == yLogical;
}

boolean hasSameNameAs(WLGraphicsDevice otherDevice) {
Expand Down Expand Up @@ -286,8 +294,8 @@ public void removeWindow(WLComponentPeer peer) {
@Override
public String toString() {
var config = defaultConfig;
return String.format("WLGraphicsDevice: '%s' id=%d at (%d, %d) with %s",
name, wlID, x, y,
return String.format("WLGraphicsDevice: '%s' id=%d at (%d, %d) ((%d, %d) logical) with %s",
name, wlID, x, y, xLogical, yLogical,
config != null ? config : "<no configs>");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@
import sun.util.logging.PlatformLogger.Level;

public class WLGraphicsEnvironment extends SunGraphicsEnvironment {
public static final int WL_OUTPUT_TRANSFORM_NORMAL = 0;
public static final int WL_OUTPUT_TRANSFORM_90 = 1;
public static final int WL_OUTPUT_TRANSFORM_180 = 2;
public static final int WL_OUTPUT_TRANSFORM_270 = 3;
public static final int WL_OUTPUT_TRANSFORM_FLIPPED = 4;
public static final int WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5;
public static final int WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6;
public static final int WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7;

private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLGraphicsEnvironment");

private static final boolean debugScaleEnabled;
Expand Down Expand Up @@ -95,12 +104,16 @@ public boolean isDisplayLocal() {
private final List<WLGraphicsDevice> devices = new ArrayList<>(5);

private void notifyOutputConfigured(String name, String make, String model, int wlID,
int x, int y, int width, int height, int widthMm, int heightMm,
int x, int y, int xLogical, int yLogical,
int width, int height,
int widthLogical, int heightLogical,
int widthMm, int heightMm,
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));
log.fine(String.format("Output configured id=%d at (%d, %d) (%d, %d logical) %dx%d (%dx%d logical) %dx scale",
wlID, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale));
}

String humanID =
Expand All @@ -113,21 +126,23 @@ private void notifyOutputConfigured(String name, String make, String model, int
final WLGraphicsDevice gd = devices.get(i);
if (gd.getID() == wlID) {
newOutput = false;
if (gd.isSameDeviceAs(wlID, x, y)) {
if (gd.isSameDeviceAs(wlID, x, y, xLogical, yLogical)) {
// These coordinates and the size are not scaled.
gd.updateConfiguration(humanID, width, height, scale);
gd.updateConfiguration(humanID, width, height, widthLogical, heightLogical, scale);
} else {
final WLGraphicsDevice updatedDevice = WLGraphicsDevice.createWithConfiguration(wlID, humanID,
x, y, width, height, widthMm, heightMm, scale);
x, y, xLogical, yLogical, width, height, widthLogical, heightLogical,
widthMm, heightMm, scale);
devices.set(i, updatedDevice);
gd.invalidate(updatedDevice);
}
break;
}
}
if (newOutput) {
final WLGraphicsDevice gd = WLGraphicsDevice.createWithConfiguration(wlID, humanID, x, y,
width, height, widthMm, heightMm, scale);
final WLGraphicsDevice gd = WLGraphicsDevice.createWithConfiguration(wlID, humanID,
x, y, xLogical, yLogical, width, height, widthLogical, heightLogical,
widthMm, heightMm, scale);
devices.add(gd);
}
if (LogDisplay.ENABLED) {
Expand Down
12 changes: 10 additions & 2 deletions src/java.desktop/unix/classes/sun/awt/wl/WLSMGraphicsConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,15 @@ public class WLSMGraphicsConfig extends WLGraphicsConfig {
private WLSMGraphicsConfig(WLGraphicsDevice device,
int x,
int y,
int xLogical,
int yLogical,
int width,
int height,
int widthLogical,
int heightLogical,
int scale,
boolean translucencyCapable) {
super(device, x, y, width, height, scale);
super(device, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale);
this.translucencyCapable = translucencyCapable;
this.colorModel = colorModelFor(translucencyCapable ? Transparency.TRANSLUCENT : Transparency.OPAQUE);
// Note: GNOME Shell definitely expects alpha values to be pre-multiplied
Expand All @@ -69,11 +73,15 @@ private WLSMGraphicsConfig(WLGraphicsDevice device,
public static WLSMGraphicsConfig getConfig(WLGraphicsDevice device,
int x,
int y,
int xLogical,
int yLogical,
int width,
int height,
int widthLogical,
int heightLogical,
int scale,
boolean translucencyCapable) {
var newConfig = new WLSMGraphicsConfig(device, x, y, width, height, scale, translucencyCapable);
var newConfig = new WLSMGraphicsConfig(device, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale, translucencyCapable);
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("New shared memory config " + newConfig);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,11 @@ public final class WLVKGraphicsConfig extends WLGraphicsConfig

private static native long getVKConfigInfo();

public WLVKGraphicsConfig(WLGraphicsDevice device, int x, int y, int width, int height, int scale, ContextCapabilities vkCaps) {
super(device, x, y, width, height, scale);
public WLVKGraphicsConfig(WLGraphicsDevice device,
int x, int y, int xLogical, int yLogical,
int width, int height, int widthLogical, int heightLogical,
int scale, ContextCapabilities vkCaps) {
super(device, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale);
this.vkCaps = vkCaps;
context = new VKContext(VKRenderQueue.getInstance());
}
Expand All @@ -89,13 +92,16 @@ public SurfaceManager.ProxyCache getSurfaceDataProxyCache() {
return surfaceDataProxyCache;
}

public static WLVKGraphicsConfig getConfig(WLGraphicsDevice device, int x, int y, int width, int height, int scale)
public static WLVKGraphicsConfig getConfig(WLGraphicsDevice device,
int x, int y, int xLogical, int yLogical,
int width, int height, int widthLogical, int heightLogical,
int scale)
{
ContextCapabilities caps = new VKContext.VKContextCaps(
CAPS_PS30 | CAPS_PS20 | CAPS_RT_TEXTURE_ALPHA |
CAPS_RT_TEXTURE_OPAQUE | CAPS_MULTITEXTURE | CAPS_TEXNONPOW2 |
CAPS_TEXNONSQUARE, null);
return new WLVKGraphicsConfig(device, x, y, width, height, scale, caps);
return new WLVKGraphicsConfig(device, x, y, xLogical, yLogical, width, height, widthLogical, heightLogical, scale, caps);
}

/**
Expand Down
Loading

0 comments on commit fc56ec0

Please sign in to comment.