Skip to content

Commit 4057542

Browse files
committed
wayland: implement fractional scaling
Signed-off-by: Julian Orth <[email protected]>
1 parent 2b7594b commit 4057542

17 files changed

+532
-108
lines changed

src/java.desktop/unix/classes/sun/awt/wl/WLComponentPeer.java

Lines changed: 78 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676
import java.util.Objects;
7777
import java.util.function.Supplier;
7878

79+
import static sun.awt.wl.WLGraphicsConfig.SCALE120;
80+
7981
public class WLComponentPeer implements ComponentPeer {
8082
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLComponentPeer");
8183
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.wl.focus.WLComponentPeer");
@@ -119,9 +121,12 @@ public class WLComponentPeer implements ComponentPeer {
119121
boolean visible = false;
120122

121123
private final Object dataLock = new Object();
122-
int width; // in native pixels, protected by dataLock
123-
int height; // in native pixels, protected by dataLock
124-
int wlBufferScale; // protected by dataLock
124+
int javaWidth; // in java coordinates, protected by dataLock
125+
int javaHeight; // in java coordinates, protected by dataLock
126+
int surfaceWidth; // in surface coordinates, protected by dataLock
127+
int surfaceHeight; // in surface coordinates, protected by dataLock
128+
long scale120; // protected by dataLock
129+
Long preferredScale120 = null; // protected by dataLock
125130
double effectiveScale; // protected by dataLock
126131

127132
static {
@@ -135,31 +140,33 @@ public class WLComponentPeer implements ComponentPeer {
135140
this.target = target;
136141
this.background = target.getBackground();
137142
Dimension size = constrainSize(target.getBounds().getSize());
138-
width = size.width;
139-
height = size.height;
143+
javaWidth = size.width;
144+
javaHeight = size.height;
140145
final WLGraphicsConfig config = (WLGraphicsConfig)target.getGraphicsConfiguration();
141-
wlBufferScale = config.getWlScale();
146+
scale120 = config.getWlScale120();
142147
effectiveScale = config.getEffectiveScale();
143148
surfaceData = config.createSurfaceData(this);
144149
nativePtr = nativeCreateFrame();
145150
paintArea = new WLRepaintArea();
151+
surfaceWidth = Math.max(javaUnitsToSurfaceUnits(javaWidth), 1);
152+
surfaceHeight = Math.max(javaUnitsToSurfaceUnits(javaHeight), 1);
146153

147154
if (log.isLoggable(Level.FINE)) {
148-
log.fine("WLComponentPeer: target=" + target + " with size=" + width + "x" + height);
155+
log.fine("WLComponentPeer: target=" + target + " with size=" + javaWidth + "x" + javaHeight);
149156
}
150157
// TODO
151158
// setup parent window for target
152159
}
153160

154-
public int getWidth() {
161+
public int getJavaWidth() {
155162
synchronized (dataLock) {
156-
return width;
163+
return javaWidth;
157164
}
158165
}
159166

160-
public int getHeight() {
167+
public int getJavaHeight() {
161168
synchronized (dataLock) {
162-
return height;
169+
return javaHeight;
163170
}
164171
}
165172

@@ -181,7 +188,7 @@ public void postPaintEvent(int x, int y, int w, int h) {
181188

182189
void postPaintEvent() {
183190
if (isVisible()) {
184-
postPaintEvent(0, 0, getWidth(), getHeight());
191+
postPaintEvent(0, 0, getJavaWidth(), getJavaHeight());
185192
}
186193
}
187194

@@ -268,8 +275,11 @@ protected void wlSetVisible(boolean v) {
268275
if (v) {
269276
String title = getTitle();
270277
boolean isWlPopup = targetIsWlPopup();
271-
int thisWidth = javaUnitsToSurfaceUnits(getWidth());
272-
int thisHeight = javaUnitsToSurfaceUnits(getHeight());
278+
int thisWidth, thisHeight;
279+
synchronized (dataLock) {
280+
thisWidth = surfaceWidth;
281+
thisHeight = surfaceHeight;
282+
}
273283
boolean isModal = targetIsModal();
274284

275285
int state = (target instanceof Frame frame)
@@ -354,14 +364,15 @@ private boolean targetIsModal() {
354364
}
355365

356366
void updateSurfaceData() {
367+
// The scale parameter is ignored.
357368
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).revalidate(
358-
getBufferWidth(), getBufferHeight(), getBufferScale());
369+
getBufferWidth(), getBufferHeight(), 1);
359370
updateWindowGeometry();
360371
}
361372

362373
void configureWLSurface() {
363374
if (log.isLoggable(PlatformLogger.Level.FINE)) {
364-
log.fine(String.format("%s is configured to %dx%d with %dx scale", this, getBufferWidth(), getBufferHeight(), getBufferScale()));
375+
log.fine(String.format("%s is configured to %dx%d with %fx scale", this, getBufferWidth(), getBufferHeight(), getWlScale()));
365376
}
366377
updateSurfaceData();
367378
}
@@ -471,8 +482,8 @@ public void setBounds(int newX, int newY, int newWidth, int newHeight, int op) {
471482
if (sizeChanged) {
472483
setSizeTo(newSize.width, newSize.height);
473484
if (log.isLoggable(PlatformLogger.Level.FINE)) {
474-
log.fine(String.format("%s is resizing its buffer to %dx%d with %dx scale",
475-
this, getBufferWidth(), getBufferHeight(), getBufferScale()));
485+
log.fine(String.format("%s is resizing its buffer to %dx%d with %fx scale",
486+
this, getBufferWidth(), getBufferHeight(), getWlScale()));
476487
}
477488
updateSurfaceData();
478489
layout();
@@ -485,18 +496,25 @@ public void setBounds(int newX, int newY, int newWidth, int newHeight, int op) {
485496

486497
private void setSizeTo(int newWidth, int newHeight) {
487498
Dimension newSize = constrainSize(newWidth, newHeight);
499+
final int surfaceWidth = Math.max(javaUnitsToSurfaceUnits(newSize.width), 1);
500+
final int surfaceHeight = Math.max(javaUnitsToSurfaceUnits(newSize.height), 1);
488501
performLocked(() -> {
489-
nativeSetSurfaceSize(nativePtr, javaUnitsToSurfaceUnits(newSize.width), javaUnitsToSurfaceUnits(newSize.height));
502+
nativeSetSurfaceSize(nativePtr, surfaceWidth, surfaceHeight);
490503
});
491504
synchronized (dataLock) {
492-
this.width = newSize.width;
493-
this.height = newSize.height;
505+
this.javaWidth = newSize.width;
506+
this.javaHeight = newSize.height;
507+
this.surfaceWidth = surfaceWidth;
508+
this.surfaceHeight = surfaceHeight;
494509
}
495510
}
496511

497512
private void repositionWlPopup(int newX, int newY) {
498-
final int thisWidth = getWidth();
499-
final int thisHeight = getHeight();
513+
final int thisWidth, thisHeight;
514+
synchronized (dataLock) {
515+
thisWidth = surfaceWidth;
516+
thisHeight = surfaceHeight;
517+
}
500518
performLocked(() -> {
501519
Window popup = (Window) target;
502520
final Component popupParent = AWTAccessor.getWindowAccessor().getPopupParent(popup);
@@ -523,32 +541,28 @@ private void repositionWlPopup(int newX, int newY) {
523541

524542
public Rectangle getVisibleBounds() {
525543
synchronized(dataLock) {
526-
return new Rectangle(0, 0, width, height);
544+
return new Rectangle(0, 0, javaWidth, javaHeight);
527545
}
528546
}
529547

530-
/**
531-
* Represents the scale ratio of Wayland's backing buffer in pixel units
532-
* to surface units. Wayland events are generated in surface units, while
533-
* painting should be performed in pixel units.
534-
* The ratio is enforced with nativeSetSize().
535-
*/
536-
int getBufferScale() {
548+
private double getWlScale() {
537549
synchronized(dataLock) {
538-
return wlBufferScale;
550+
return (double)scale120 / SCALE120;
539551
}
540552
}
541553

542-
public int getBufferWidth() {
554+
private int getBufferSize(int size) {
543555
synchronized (dataLock) {
544-
return (int)(width * effectiveScale);
556+
return (int)((size * scale120 + SCALE120 / 2) / SCALE120);
545557
}
546558
}
547559

560+
public int getBufferWidth() {
561+
return getBufferSize(surfaceWidth);
562+
}
563+
548564
public int getBufferHeight() {
549-
synchronized (dataLock) {
550-
return (int)(height * effectiveScale);
551-
}
565+
return getBufferSize(surfaceHeight);
552566
}
553567

554568
public Rectangle getBufferBounds() {
@@ -566,8 +580,8 @@ private void updateWindowGeometry() {
566580
Rectangle nativeVisibleBounds = getVisibleBounds();
567581
nativeVisibleBounds.x = javaUnitsToSurfaceUnits(nativeVisibleBounds.x);
568582
nativeVisibleBounds.y = javaUnitsToSurfaceUnits(nativeVisibleBounds.y);
569-
nativeVisibleBounds.width = javaUnitsToSurfaceUnits(nativeVisibleBounds.width);
570-
nativeVisibleBounds.height = javaUnitsToSurfaceUnits(nativeVisibleBounds.height);
583+
nativeVisibleBounds.width = Math.max(javaUnitsToSurfaceUnits(nativeVisibleBounds.width), 1);
584+
nativeVisibleBounds.height = Math.max(javaUnitsToSurfaceUnits(nativeVisibleBounds.height), 1);
571585
performLocked(() -> nativeSetWindowGeometry(nativePtr,
572586
nativeVisibleBounds.x, nativeVisibleBounds.y,
573587
nativeVisibleBounds.width, nativeVisibleBounds.height));
@@ -831,7 +845,7 @@ private void updateCursorImmediately(WLInputState inputState) {
831845
WLComponentPeer peer = inputState.getPeer();
832846
if (peer == null) return;
833847
Cursor cursor = peer.getCursor(inputState.getPointerX(), inputState.getPointerY());
834-
setCursor(cursor, getGraphicsDevice() != null ? getGraphicsDevice().getWlScale() : 1);
848+
setCursor(cursor, (int)((scale120 + SCALE120 - 1) / SCALE120));
835849
}
836850

837851
Cursor getCursor(int x, int y) {
@@ -942,16 +956,16 @@ public void applyShape(Region shape) {
942956

943957
@Override
944958
public boolean updateGraphicsData(GraphicsConfiguration gc) {
945-
final int newWlScale = ((WLGraphicsConfig)gc).getWlScale();
959+
final long newScale120 = ((WLGraphicsConfig)gc).getWlScale120();
946960

947961
WLGraphicsDevice gd = ((WLGraphicsConfig) gc).getDevice();
948962
gd.addWindow(this);
949963
synchronized (dataLock) {
950-
if (newWlScale != wlBufferScale) {
951-
wlBufferScale = newWlScale;
964+
if (newScale120 != scale120) {
965+
scale120 = newScale120;
952966
effectiveScale = ((WLGraphicsConfig)gc).getEffectiveScale();
953967
if (log.isLoggable(PlatformLogger.Level.FINE)) {
954-
log.fine(String.format("%s is updating buffer to %dx%d with %dx scale", this, getBufferWidth(), getBufferHeight(), wlBufferScale));
968+
log.fine(String.format("%s is updating buffer to %dx%d with %fx scale", this, getBufferWidth(), getBufferHeight(), getWlScale()));
955969
}
956970
updateSurfaceData();
957971
postPaintEvent();
@@ -1185,7 +1199,7 @@ int surfaceUnitsToJavaUnits(int value) {
11851199
return value;
11861200
} else {
11871201
synchronized (dataLock) {
1188-
return (int)(value * wlBufferScale / effectiveScale);
1202+
return (int)(value * scale120 / (effectiveScale * SCALE120));
11891203
}
11901204
}
11911205
}
@@ -1199,7 +1213,7 @@ int javaUnitsToSurfaceUnits(int value) {
11991213
return value;
12001214
} else {
12011215
synchronized (dataLock) {
1202-
return (int)(value * effectiveScale / wlBufferScale);
1216+
return (int)(value * effectiveScale * SCALE120 / scale120);
12031217
}
12041218
}
12051219
}
@@ -1285,8 +1299,17 @@ void notifyPopupDone() {
12851299
WLToolkit.postEvent(new WindowEvent((Window) target, WindowEvent.WINDOW_CLOSING));
12861300
}
12871301

1302+
void notifyPreferredScale(long scale120) {
1303+
synchronized (dataLock) {
1304+
if (preferredScale120 == null || preferredScale120 != scale120) {
1305+
preferredScale120 = scale120;
1306+
checkIfOnNewScreen();
1307+
}
1308+
}
1309+
}
1310+
12881311
private WLGraphicsDevice getGraphicsDevice() {
1289-
int scale = 0;
1312+
long scale120 = 0;
12901313
WLGraphicsDevice theDevice = null;
12911314
// AFAIK there's no way of knowing which WLGraphicsDevice is displaying
12921315
// the largest portion of this component, so choose the first in the ordered list
@@ -1295,8 +1318,8 @@ private WLGraphicsDevice getGraphicsDevice() {
12951318
// Wayland's output and are removed as soon as we have left.
12961319
synchronized (devices) {
12971320
for (WLGraphicsDevice gd : devices) {
1298-
if (gd.getWlScale() > scale) {
1299-
scale = gd.getWlScale();
1321+
if (gd.getWlScale120() > scale120) {
1322+
scale120 = gd.getWlScale120();
13001323
theDevice = gd;
13011324
}
13021325
}
@@ -1308,7 +1331,7 @@ private WLGraphicsDevice getGraphicsDevice() {
13081331
private void checkIfOnNewScreen() {
13091332
final WLGraphicsDevice newDevice = getGraphicsDevice();
13101333
if (newDevice != null) { // could be null when screens are being reconfigured
1311-
final GraphicsConfiguration gc = newDevice.getDefaultConfiguration();
1334+
final WLGraphicsConfig gc = (WLGraphicsConfig) newDevice.getDefaultConfiguration();
13121335
if (log.isLoggable(Level.FINE)) {
13131336
log.fine(this + " is on (possibly) new device " + newDevice);
13141337
}
@@ -1318,8 +1341,12 @@ private void checkIfOnNewScreen() {
13181341
newDevice.addWindow(this);
13191342
}
13201343
performUnlocked(() -> {
1344+
WLGraphicsConfig gcEffective = gc;
1345+
if (preferredScale120 != null) {
1346+
gcEffective = gc.withScale120(preferredScale120);
1347+
}
13211348
var acc = AWTAccessor.getComponentAccessor();
1322-
acc.setGraphicsConfiguration(target, gc);
1349+
acc.setGraphicsConfiguration(target, gcEffective);
13231350
});
13241351
}
13251352
}

src/java.desktop/unix/classes/sun/awt/wl/WLFrameDecoration.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public Insets getInsets() {
102102
public Rectangle getBounds() {
103103
return isUndecorated
104104
? new Rectangle(0, 0, 0, 0)
105-
: new Rectangle(0, 0, peer.getWidth(), HEIGHT);
105+
: new Rectangle(0, 0, peer.getJavaWidth(), HEIGHT);
106106
}
107107

108108
public Dimension getMinimumSize() {
@@ -120,19 +120,19 @@ private boolean hasMaximizeButton() {
120120
}
121121

122122
private Point getCloseButtonCenter() {
123-
int width = peer.getWidth();
123+
int width = peer.getJavaWidth();
124124
return width >= HEIGHT ? new Point(width - HEIGHT / 2, HEIGHT / 2) : null;
125125
}
126126

127127
private Point getMaximizeButtonCenter() {
128128
if (!hasMaximizeButton()) return null;
129-
int width = peer.getWidth();
129+
int width = peer.getJavaWidth();
130130
return width >= 2 * HEIGHT ? new Point(width - HEIGHT * 3 / 2, HEIGHT / 2) : null;
131131
}
132132

133133
private Point getMinimizeButtonCenter() {
134134
if (!hasMinimizeButton()) return null;
135-
int width = peer.getWidth();
135+
int width = peer.getJavaWidth();
136136
int buttonSpaceWidth = getButtonSpaceWidth();
137137
return width >= buttonSpaceWidth ? new Point(width - buttonSpaceWidth + HEIGHT / 2, HEIGHT / 2) : null;
138138
}
@@ -147,8 +147,8 @@ private int getButtonSpaceWidth() {
147147
public void paint(final Graphics g) {
148148
if (isUndecorated) return;
149149

150-
int width = peer.getWidth();
151-
int height = peer.getHeight();
150+
int width = peer.getJavaWidth();
151+
int height = peer.getJavaHeight();
152152
if (width <= 0 || height <= 0) return;
153153
Graphics2D g2d = (Graphics2D) g.create(0, 0, width, HEIGHT);
154154
try {
@@ -160,7 +160,7 @@ public void paint(final Graphics g) {
160160
}
161161

162162
private void doPaint(Graphics2D g) {
163-
int width = peer.getWidth();
163+
int width = peer.getJavaWidth();
164164
String title = peer.getTitle();
165165
Color foregroundColor = active ? ACTIVE_FOREGROUND : INACTIVE_FOREGROUND;
166166

@@ -265,7 +265,7 @@ private boolean pressedInDragStartArea() {
265265
pressedLocation.y >= 0 &&
266266
pressedLocation.y < HEIGHT &&
267267
pressedLocation.x >= 0 &&
268-
pressedLocation.x < peer.getWidth() - getButtonSpaceWidth();
268+
pressedLocation.x < peer.getJavaWidth() - getButtonSpaceWidth();
269269
}
270270

271271
boolean processMouseEvent(MouseEvent e) {
@@ -334,12 +334,12 @@ private int getResizeEdges(int x, int y) {
334334
int edges = 0;
335335
if (x < RESIZE_EDGE_THICKNESS) {
336336
edges |= XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
337-
} else if (x > peer.getWidth() - RESIZE_EDGE_THICKNESS) {
337+
} else if (x > peer.getJavaWidth() - RESIZE_EDGE_THICKNESS) {
338338
edges |= XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
339339
}
340340
if (y < RESIZE_EDGE_THICKNESS) {
341341
edges |= XDG_TOPLEVEL_RESIZE_EDGE_TOP;
342-
} else if (y > peer.getHeight() - RESIZE_EDGE_THICKNESS) {
342+
} else if (y > peer.getJavaHeight() - RESIZE_EDGE_THICKNESS) {
343343
edges |= XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
344344
}
345345
return edges;

src/java.desktop/unix/classes/sun/awt/wl/WLFramePeer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ public void toBack() {
152152

153153
@Override
154154
void notifyConfigured(int newXNative, int newYNative, int newWidthNative, int newHeightNative, boolean active, boolean maximized) {
155-
int widthBefore = getWidth();
156-
int heightBefore = getHeight();
155+
int widthBefore = getJavaWidth();
156+
int heightBefore = getJavaHeight();
157157

158158
super.notifyConfigured(newXNative, newYNative, newWidthNative, newHeightNative, active, maximized);
159159

0 commit comments

Comments
 (0)